diff --git a/README.md b/README.md index ec91402..5d2a209 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 20240928, see the [changelog](changelog.md) for details. +Latest build date is 20241006, 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 1158a89..40c22fc 100644 --- a/changelog.md +++ b/changelog.md @@ -1,7 +1,33 @@ ## grblHAL changelog +Build 2024106 + +Core: + +* Fix for `M62` - `M68` regression. Ref. [issue #600](https://github.com/grblHAL/core/issues/600). + +* Fixed incorrect handling of `G65` call parameters, axis words had offsets added. Ref. [issue #594](https://github.com/grblHAL/core/issues/594). + +* Refactored handling of multiple spindles. There are still some limitations but should work better now. Disabled override delays for now, needs investigation. Ref. [issue #598](https://github.com/grblHAL/core/issues/598). +__NOTE:__ Please report any erratic behaviour after installing this version since it is a rather major change. + +Drivers: + +* ESP32: fix for compilation error. Ref. [issue #122](https://github.com/grblHAL/ESP32/issues/122). +Fixes for handling multiple devices on a single SPI port. Fixed xPro v5 map for Modbus comms. Ref. [issue #121](https://github.com/grblHAL/ESP32/issues/121). + +* STM32F4xx: fix for compilation error for some boards when configured for Trinamic drivers. + +Plugins: + +* BLTouch: implemented `$BLTEST` command, verified. + +--- + Build 20240928 +Core: + * 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. diff --git a/gcode.c b/gcode.c index 4381e4c..e60b6de 100644 --- a/gcode.c +++ b/gcode.c @@ -38,7 +38,7 @@ // NOTE: Max line number is defined by the g-code standard to be 99999. It seems to be an // arbitrary value, and some GUIs may require more. So we increased it based on a max safe -// value when converting a float (7.2 digit precision)s to an integer. +// value when converting a float (7.2 digit precision) to an integer. #define MAX_LINE_NUMBER 10000000 #define MAX_TOOL_NUMBER 4294967294 // Limited by max unsigned 32-bit value - 1 @@ -149,6 +149,14 @@ parser_state_t *gc_get_state (void) return &gc_state; } +static void set_spindle_override (spindle_t *spindle, bool disable) +{ + if(spindle->hal && spindle->hal->param->state.override_disable != disable) { + if((spindle->state.override_disable = spindle->hal->param->state.override_disable = disable)) + spindle_set_override(gc_state.spindle->hal, DEFAULT_SPINDLE_RPM_OVERRIDE); + } +} + static void set_scaling (float factor) { uint_fast8_t idx = N_AXIS; @@ -299,7 +307,14 @@ void gc_init (void) // Load default override status gc_state.modal.override_ctrl = sys.override.control; - gc_state.spindle.hal = spindle_get(0); + +#if N_SYS_SPINDLE > 1 + gc_state.spindle = &gc_state.modal.spindle[0]; + gc_state.modal.spindle[0].hal = spindle_get(0); +#else + gc_state.spindle = &gc_state.modal.spindle; + gc_state.modal.spindle.hal = spindle_get(0); +#endif set_scaling(1.0f); @@ -343,10 +358,25 @@ bool gc_laser_ppi_enable (uint_fast16_t ppi, uint_fast16_t pulse_length) return grbl.on_laser_ppi_enable && grbl.on_laser_ppi_enable(ppi, pulse_length); } +spindle_t *gc_spindle_get (spindle_num_t spindle) +{ +#if N_SYS_SPINDLE > 1 + return spindle < 0 ? gc_state.spindle : &gc_state.modal.spindle[spindle]; +#else + return &gc_state.modal.spindle; +#endif +} + void gc_spindle_off (void) { - gc_state.spindle.rpm = 0.0f; - gc_state.modal.spindle.state.value = 0; +#if N_SYS_SPINDLE > 1 + uint_fast8_t idx; + for(idx = 0; idx < N_SYS_SPINDLE; idx++) { + memset(&gc_state.modal.spindle[idx], 0, offsetof(spindle_t, hal)); + } +#else + memset(&gc_state.modal.spindle, 0, offsetof(spindle_t, hal)); +#endif spindle_all_off(); system_add_rt_report(Report_Spindle); @@ -359,11 +389,6 @@ void gc_coolant (coolant_state_t state) system_add_rt_report(Report_Coolant); } -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); @@ -655,12 +680,23 @@ bool gc_modal_state_restore (gc_modal_t *copy) 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); +#if N_SYS_SPINDLE > 1 + uint_fast8_t idx = N_SYS_SPINDLE; + spindle_t *spindle, *spindle_copy; + do { + if((spindle = &gc_state.modal.spindle[--idx])->hal) { + spindle_copy = ©->spindle[idx]; + if(!memcmp(spindle_copy, spindle, offsetof(spindle_t, hal))) + spindle_restore(spindle->hal, spindle_copy->state, spindle_copy->rpm); + } + } while(idx); +#else + if(!memcmp(©->spindle, &gc_state.modal.spindle, offsetof(spindle_t, hal))) + spindle_restore(gc_state.modal.spindle.hal, copy->spindle.state, copy->spindle.rpm); +#endif 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; } @@ -713,8 +749,6 @@ char *gc_normalize_block (char *block, char **message) *s1 = '\0'; if(!hal.driver_cap.no_gcode_message_handling) { - size_t len = s1 - comment - 4; - if(message && *message == NULL) { #if NGC_EXPRESSIONS_ENABLE if(!strncmp(comment, "(DEBUG,", 7)) { // Debug message string substitution @@ -733,6 +767,8 @@ char *gc_normalize_block (char *block, char **message) } } #else + size_t len = s1 - comment - 4; + if(!strncmp(comment, "(MSG,", 5) && (*message = malloc(len))) { comment += 5; @@ -937,11 +973,12 @@ status_code_t gc_execute_block (char *block) bool set_tool = false, spindle_event = false; axis_command_t axis_command = AxisCommand_None; io_mcode_t port_command = (io_mcode_t)0; + spindle_t *sspindle = gc_state.spindle; plane_t plane; // Initialize bitflag tracking variables for axis indices compatible operations. - axes_signals_t axis_words = {0}; // XYZ tracking - ijk_words_t ijk_words = {0}; // IJK tracking + axes_signals_t axis_words = {0}; // XYZ tracking + ijk_words_t ijk_words = {0}; // IJK tracking // 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. @@ -954,7 +991,7 @@ status_code_t gc_execute_block (char *block) gc_parser_flags.jog_motion = On; gc_block.modal.motion = MotionMode_Linear; gc_block.modal.feed_mode = FeedMode_UnitsPerMin; - gc_block.modal.spindle.rpm_mode = SpindleSpeedMode_RPM; + gc_block.spindle_modal.rpm_mode = SpindleSpeedMode_RPM; gc_block.values.n = JOG_LINE_NUMBER; // Initialize default line number reported during jog. } @@ -1275,7 +1312,7 @@ status_code_t gc_execute_block (char *block) case 96: case 97: if(settings.mode == Mode_Lathe) { word_bit.modal_group.G14 = On; - gc_block.modal.spindle.rpm_mode = (spindle_rpm_mode_t)((int_value - 96) ^ 1); + gc_block.spindle_modal.rpm_mode = (spindle_rpm_mode_t)((int_value - 96) ^ 1); } else FAIL(Status_GcodeUnsupportedCommand); break; @@ -1346,9 +1383,9 @@ status_code_t gc_execute_block (char *block) case 3: case 4: case 5: word_bit.modal_group.M7 = On; - gc_block.modal.spindle.state.on = !(int_value == 5); - gc_block.modal.spindle.state.ccw = int_value == 4; - sys.override_delay.spindle = On; + gc_block.spindle_modal.state.on = !(int_value == 5); + gc_block.spindle_modal.state.ccw = int_value == 4; +// sys.override_delay.spindle = On; TODO: only when spindle sync? break; case 6: @@ -1362,7 +1399,7 @@ status_code_t gc_execute_block (char *block) case 7: case 8: case 9: word_bit.modal_group.M8 = On; - sys.override_delay.coolant = On; +// sys.override_delay.coolant = On; TODO: ? gc_parser_flags.set_coolant = On; switch(int_value) { @@ -1757,6 +1794,10 @@ status_code_t gc_execute_block (char *block) // [0. Non-specific/common error-checks and miscellaneous setup]: + // If a G65 block remove axis and ijk words flags since values are to be passed unmodified. + if(word_bit.modal_group.G0 && gc_block.non_modal_command == NonModal_MacroCall) + axis_words.mask = ijk_words.mask = 0; + // Determine implicit axis command conditions. Axis words have been passed, but no explicit axis // command has been sent. If so, set axis command to current motion mode. if (axis_words.mask && !axis_command) @@ -1872,55 +1913,65 @@ status_code_t gc_execute_block (char *block) (command_words.G0 && (gc_block.modal.motion == MotionMode_SpindleSynchronized || gc_block.modal.motion == MotionMode_RigidTapping || gc_block.modal.motion == MotionMode_Threading)) || - command_words.G14 || - (command_words.M9 && gc_block.override_command == Override_SpindleSpeed); + (command_words.G5 && gc_block.modal.feed_mode == FeedMode_UnitsPerRev) || + command_words.G14 || + (command_words.M9 && gc_block.override_command == Override_SpindleSpeed); if(command_words.M7 || single_spindle_only) { if(gc_block.values.$ < (single_spindle_only ? 0 : -1)) FAIL(single_spindle_only ? Status_NegativeValue : Status_GcodeValueOutOfRange); - if(!spindle_is_enabled(gc_block.values.$)) +#if N_SYS_SPINDLE > 1 + if(gc_block.values.$ < 0) + sspindle = NULL; + else { + if(!spindle_is_enabled(gc_block.values.$)) + FAIL(Status_GcodeValueOutOfRange); + if(gc_state.modal.spindle[gc_block.values.$].hal == NULL) + gc_state.modal.spindle[gc_block.values.$].hal = spindle_get(gc_block.values.$); + sspindle = &gc_state.modal.spindle[gc_block.values.$]; + } +#else + if(gc_block.values.$ > 0) FAIL(Status_GcodeValueOutOfRange); - if(gc_block.values.$ >= 0) - gc_state.spindle.hal = gc_block.spindle = spindle_get(gc_block.values.$); +#endif gc_block.words.$ = Off; } - } else if(gc_block.spindle == NULL) - gc_block.spindle = gc_state.spindle.hal; + } - if(gc_block.modal.feed_mode == FeedMode_UnitsPerRev && !gc_state.spindle.hal->get_data) + if(gc_block.modal.feed_mode == FeedMode_UnitsPerRev && (sspindle == NULL || !sspindle->hal->get_data)) FAIL(Status_GcodeUnsupportedCommand); // [G95 not supported] - if (command_words.G14) { - if(gc_block.modal.spindle.rpm_mode == SpindleSpeedMode_CSS) { - if(!gc_state.spindle.hal->cap.variable) + if(command_words.G14) { + if(gc_block.spindle_modal.rpm_mode == SpindleSpeedMode_CSS) { + if(!sspindle->hal->cap.variable) FAIL(Status_GcodeUnsupportedCommand); - if (!gc_block.words.s) // TODO: add check for S0? + if(!gc_block.words.s) // TODO: add check for S0? FAIL(Status_GcodeValueWordMissing); // see below!! gc_block.values.s *= (gc_block.modal.units_imperial ? MM_PER_INCH * 12.0f : 1000.0f); // convert surface speed to mm/min - if (gc_block.words.d) { - gc_state.spindle.hal->param->css.max_rpm = min(gc_block.values.d, gc_state.spindle.hal->rpm_max); + if(gc_block.words.d) { + sspindle->hal->param->css.max_rpm = min(gc_block.values.d, sspindle->hal->rpm_max); gc_block.words.d = Off; } else - gc_state.spindle.hal->param->css.max_rpm = gc_state.spindle.hal->rpm_max; - } else if(gc_state.modal.spindle.rpm_mode == SpindleSpeedMode_CSS) { - if(gc_state.spindle.css) { - gc_state.spindle.css = NULL; + sspindle->hal->param->css.max_rpm = sspindle->hal->rpm_max; + } else if(sspindle->rpm_mode == SpindleSpeedMode_CSS) { + if(sspindle->css) { + sspindle->css = NULL; protocol_buffer_synchronize(); // Empty planner buffer to ensure we get RPM at end of last CSS motion } - gc_state.spindle.rpm = gc_state.spindle.hal->param->rpm; // Is it correct to restore latest spindle RPM here? + sspindle->rpm = sspindle->hal->param->rpm; // Is it correct to restore latest spindle RPM here? } - gc_state.modal.spindle.rpm_mode = gc_block.modal.spindle.rpm_mode; - } + sspindle->rpm_mode = gc_block.spindle_modal.rpm_mode; + } else if(sspindle) + gc_block.spindle_modal.rpm_mode = sspindle->rpm_mode; - spindle_event = 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(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 - gc_state.spindle.hal->param->css.surface_speed = gc_block.values.s; - } + if((spindle_event = gc_block.words.s)) { + if(sspindle->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 + sspindle->hal->param->css.surface_speed = gc_block.values.s; + } + } else if(sspindle) + gc_block.values.s = sspindle->rpm_mode == SpindleSpeedMode_RPM ? sspindle->rpm : sspindle->hal->param->css.max_rpm; // bit_false(gc_block.words,bit(Word_S)); // NOTE: Single-meaning value word. Set at end of error-checking. @@ -1950,7 +2001,7 @@ status_code_t gc_execute_block (char *block) } else if(!gc_block.words.t) gc_block.values.t = gc_state.tool_pending; - if(command_words.M10 && port_command) { + if(command_words.M5 && port_command) { switch(port_command) { @@ -2025,18 +2076,24 @@ status_code_t gc_execute_block (char *block) // [6. Change tool ]: N/A // [7. Spindle control ]: - if(command_words.M7 && gc_block.modal.spindle.state.ccw) { - // Check if spindle(s) support reversing direction - if(gc_block.spindle == NULL) { - uint_fast8_t idx = N_SYS_SPINDLE; - do { - idx--; - if(spindle_is_enabled(idx) && !(spindle_get(idx)->cap.direction || spindle_get(idx)->cap.laser)) - FAIL(Status_GcodeUnsupportedCommand); - } while(idx); - } else if(!(gc_block.spindle->cap.direction || gc_block.spindle->cap.laser)) - FAIL(Status_GcodeUnsupportedCommand); - } + if(command_words.M7) { + if(gc_block.spindle_modal.state.ccw) { + // Check if spindle(s) support reversing direction +#if N_SYS_SPINDLE > 1 + if(sspindle == NULL) { + uint_fast8_t idx = N_SYS_SPINDLE; + do { + idx--; + if(gc_state.modal.spindle[idx].hal && !(gc_state.modal.spindle[idx].hal->cap.direction || gc_state.modal.spindle[idx].hal->cap.laser)) + FAIL(Status_GcodeUnsupportedCommand); + } while(idx); + } else +#endif + if(!(sspindle->hal->cap.direction || sspindle->hal->cap.laser)) + FAIL(Status_GcodeUnsupportedCommand); + } + } else if(sspindle) + gc_block.spindle_modal.state = sspindle->state; // [8. Coolant control ]: N/A @@ -2585,13 +2642,13 @@ status_code_t gc_execute_block (char *block) gc_block.modal.retract_mode = CCRetractMode_Previous; // Initial(?) check for spindle running for moves in G96 mode - if(gc_block.modal.spindle.rpm_mode == SpindleSpeedMode_CSS && (!gc_block.modal.spindle.state.on || gc_block.values.s == 0.0f)) + if(gc_block.spindle_modal.rpm_mode == SpindleSpeedMode_CSS && (!gc_block.spindle_modal.state.on || gc_block.values.s == 0.0f)) FAIL(Status_GcodeSpindleNotRunning); // Check if feed rate is defined for the motion modes that require it. - if (gc_block.modal.motion == MotionMode_SpindleSynchronized) { + if(gc_block.modal.motion == MotionMode_SpindleSynchronized) { - if(!gc_state.spindle.hal->get_data) + if(!sspindle->hal->get_data) FAIL(Status_GcodeUnsupportedCommand); // [G33, G33.1] if(gc_block.values.k == 0.0f) @@ -2600,11 +2657,11 @@ status_code_t gc_execute_block (char *block) // Ensure spindle speed is at 100% - any override will be disabled on execute. gc_parser_flags.spindle_force_sync = On; - } else if (gc_block.modal.motion == MotionMode_Threading) { + } else if(gc_block.modal.motion == MotionMode_Threading) { // Fail if cutter radius comp is active - if(!gc_state.spindle.hal->get_data) + if(!sspindle->hal->get_data) FAIL(Status_GcodeUnsupportedCommand); // [G76 not supported] if(gc_block.modal.plane_select != PlaneSelect_ZX) @@ -2628,7 +2685,7 @@ status_code_t gc_execute_block (char *block) (gc_block.words.l && (gc_taper_type)gc_block.values.l > Taper_Both)) FAIL(Status_GcodeValueOutOfRange); - if(gc_state.spindle.rpm < gc_state.spindle.hal->rpm_min || gc_state.spindle.rpm > gc_state.spindle.hal->rpm_max) + if(sspindle->rpm < sspindle->hal->rpm_min || sspindle->rpm > sspindle->hal->rpm_max) FAIL(Status_GcodeRPMOutOfRange); if(gc_block.modal.motion != gc_state.modal.motion) { @@ -3113,30 +3170,35 @@ status_code_t gc_execute_block (char *block) // NOTE: G-code parser state is not updated, except the position to ensure sequential jog // targets are computed correctly. The final parser position after a jog is updated in // protocol_execute_realtime() when jogging completes or is canceled. - if (gc_parser_flags.jog_motion) { + if(gc_parser_flags.jog_motion) { // Only distance and unit modal commands and G53 absolute override command are allowed. // NOTE: Feed rate word and axis word checks have already been performed in STEP 3. - if (command_words.mask & ~jog_groups.mask) + if(command_words.mask & ~jog_groups.mask) FAIL(Status_InvalidJogCommand); - if (!(gc_block.non_modal_command == NonModal_AbsoluteOverride || gc_block.non_modal_command == NonModal_NoAction)) + if(!(gc_block.non_modal_command == NonModal_AbsoluteOverride || gc_block.non_modal_command == NonModal_NoAction)) FAIL(Status_InvalidJogCommand); +#if N_SYS_SPINDLE > 1 + spindle_t *spindle = sspindle ? sspindle : gc_state.modal.spindle; +#else + spindle_t *spindle = &gc_block.modal.spindle; +#endif + // Initialize planner data to current spindle and coolant modal state. - memcpy(&plan_data.spindle, &gc_state.spindle, sizeof(spindle_t)); - plan_data.spindle.state = gc_state.modal.spindle.state; + memcpy(&plan_data.spindle, spindle, sizeof(spindle_t)); plan_data.condition.coolant = gc_state.modal.coolant; - plan_data.condition.is_rpm_rate_adjusted = gc_state.is_rpm_rate_adjusted || (gc_state.modal.spindle.state.ccw && gc_state.spindle.hal->cap.laser); + plan_data.condition.is_rpm_rate_adjusted = gc_state.is_rpm_rate_adjusted || (spindle->state.ccw && spindle->hal->cap.laser); - if ((status_code_t)(int_value = (uint_fast16_t)mc_jog_execute(&plan_data, &gc_block, gc_state.position)) == Status_OK) + if((status_code_t)(int_value = (uint_fast16_t)mc_jog_execute(&plan_data, &gc_block, gc_state.position)) == Status_OK) memcpy(gc_state.position, gc_block.values.xyz, sizeof(gc_state.position)); return (status_code_t)int_value; } // If in laser mode, setup laser power based on current and past parser conditions. - if(gc_state.spindle.hal->cap.laser) { + if(sspindle && sspindle->hal->cap.laser) { if(!motion_is_lasercut(gc_block.modal.motion)) gc_parser_flags.laser_disable = On; @@ -3146,7 +3208,7 @@ status_code_t gc_execute_block (char *block) // TODO: Check sync conditions for M3 enabled motions that don't enter the planner. (zero length). if(axis_words.mask && (axis_command == AxisCommand_MotionMode)) gc_parser_flags.laser_is_motion = On; - else if(gc_state.modal.spindle.state.on && !gc_state.modal.spindle.state.ccw) { + else if(sspindle->state.on && !sspindle->state.ccw) { // M3 constant power laser requires planner syncs to update the laser when changing between // a G1/2/3 motion mode state and vice versa when there is no motion in the line. if(motion_is_lasercut(gc_state.modal.motion)) { @@ -3156,7 +3218,7 @@ status_code_t gc_execute_block (char *block) gc_parser_flags.spindle_force_sync = On; } - gc_state.is_rpm_rate_adjusted = gc_state.modal.spindle.state.ccw && !gc_parser_flags.laser_disable; + gc_state.is_rpm_rate_adjusted = sspindle->state.ccw && !gc_parser_flags.laser_disable; } // [0. Non-specific/common error-checks and miscellaneous setup]: @@ -3180,42 +3242,40 @@ status_code_t gc_execute_block (char *block) plan_data.feed_rate = gc_state.feed_rate; // Record data for planner use. // [4. Set spindle speed ]: - if(gc_state.modal.spindle.rpm_mode == SpindleSpeedMode_CSS) { + +#if N_SYS_SPINDLE > 1 + if(sspindle) { +#endif // N_SYS_SPINDLE > 1 + + if(sspindle->rpm_mode == SpindleSpeedMode_CSS) { 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, 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))); + sspindle->css = &sspindle->hal->param->css; + sspindle->css->axis = plane.axis_1; + sspindle->css->tool_offset = gc_get_offset(plane.axis_1, false); + float pos = gc_state.position[plane.axis_1] - sspindle->css->tool_offset; + gc_block.values.s = pos <= 0.0f ? sspindle->css->max_rpm : min(sspindle->css->max_rpm, sspindle->css->surface_speed / (pos * (float)(2.0f * M_PI))); //?? gc_parser_flags.spindle_force_sync = On; } else { - if(gc_state.spindle.css) { - gc_state.spindle.css = NULL; + if(sspindle->css) { + sspindle->css = NULL; protocol_buffer_synchronize(); // Empty planner buffer to ensure we get RPM at end of last CSS motion } - gc_block.values.s = gc_state.spindle.rpm; //gc_state.spindle.hal->param->rpm; // Keep current RPM + gc_block.values.s = sspindle->rpm; //sspindle.hal->param->rpm; // Keep current RPM } } - 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; - spindle_sync(gc_block.spindle, gc_state.modal.spindle.state, gc_parser_flags.laser_disable ? 0.0f : gc_block.values.s); - } - // else... - setting the same rpm for multiple spindles at once is not allowed! + if(sspindle->rpm != gc_block.values.s || gc_parser_flags.spindle_force_sync) { + if(sspindle->state.on && !gc_parser_flags.laser_is_motion) { + sspindle->hal->param->rpm = gc_block.values.s; + spindle_sync(sspindle->hal, sspindle->state, gc_parser_flags.laser_disable ? 0.0f : gc_block.values.s); } - gc_state.spindle.rpm = gc_block.values.s; // Update spindle speed state. - } - - // NOTE: Pass zero spindle speed for all restricted laser motions. - if (!gc_parser_flags.laser_disable) - memcpy(&plan_data.spindle, &gc_state.spindle, sizeof(spindle_t)); // Record data for planner use. - else { - plan_data.spindle.hal = gc_state.spindle.hal; - // plan_data.spindle.speed = 0.0f; // Initialized as zero already. + sspindle->rpm = gc_block.values.s; // Update spindle speed state. } +#if N_SYS_SPINDLE > 1 + } +#endif + // // [5. Select tool ]: Only tracks tool value if ATC or manual tool change is not possible. if(gc_state.tool_pending != gc_block.values.t && !check_mode) { @@ -3228,12 +3288,14 @@ status_code_t gc_execute_block (char *block) if(grbl.on_tool_selected) { - spindle_state_t state = gc_state.modal.spindle.state; + spindle_state_t state = sspindle ? sspindle->state : (spindle_state_t){0}; - grbl.on_tool_selected(gc_state.tool); + grbl.on_tool_selected(pending_tool); - if(state.value != gc_state.modal.spindle.state.value) - gc_block.modal.spindle.state = gc_state.modal.spindle.state; + if(sspindle && state.value != sspindle->state.value) { + command_words.M7 = On; + gc_block.spindle_modal.state = sspindle->state; + } } if(grbl.on_tool_changed) @@ -3281,7 +3343,7 @@ status_code_t gc_execute_block (char *block) } // [6. Change tool ]: Delegated to (possible) driver implementation - if (command_words.M6 && !set_tool && !check_mode) { + if(command_words.M6 && !set_tool && !check_mode) { tool_data_t *pending_tool = tool_get_pending(gc_state.tool_pending); @@ -3296,12 +3358,14 @@ status_code_t gc_execute_block (char *block) if(grbl.on_tool_selected) { - spindle_state_t state = gc_state.modal.spindle.state; + spindle_state_t state = sspindle ? sspindle->state : (spindle_state_t){0}; grbl.on_tool_selected(pending_tool); - if(state.value != gc_state.modal.spindle.state.value) - gc_block.modal.spindle.state = gc_state.modal.spindle.state; + if(sspindle && state.value != sspindle->state.value) { + command_words.M7 = On; + gc_block.spindle_modal.state = sspindle->state; + } } if(hal.tool.change) { // ATC @@ -3334,40 +3398,72 @@ status_code_t gc_execute_block (char *block) } // [7. Spindle control ]: - if(gc_state.modal.spindle.state.value != gc_block.modal.spindle.state.value) { - // Update spindle control and apply spindle speed when enabling it in this block. - // NOTE: All spindle state changes are synced, even in laser mode. Also, plan_data, - // rather than gc_state, is used to manage laser state for non-laser motions. - 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); - 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 { + // Update spindle control and apply spindle speed when enabling it in this block. + // NOTE: All spindle state changes are synced, even in laser mode. Also, plan_data, + // rather than gc_state, is used to manage laser state for non-laser motions. + if(command_words.M7) { + + bool spindle_ok; + +#if N_SYS_SPINDLE > 1 + + if(sspindle == NULL) { + idx = N_SYS_SPINDLE; do { - 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); - if(spindle_sync(spindle, gc_block.modal.spindle.state, plan_data.spindle.rpm)) - spindle->param->state = gc_block.modal.spindle.state; - else - spindle_ok = false; + spindle_t *sys_spindle = &gc_state.modal.spindle[--idx]; + if(sys_spindle->hal) { + + if((spindle_ok = sys_spindle->state.value != gc_block.spindle_modal.state.value)) { + + if(grbl.on_spindle_programmed) + grbl.on_spindle_programmed(sys_spindle->hal, gc_block.spindle_modal.state, sys_spindle->rpm, sys_spindle->rpm_mode); + + if((spindle_ok = spindle_sync(sys_spindle->hal, gc_block.spindle_modal.state, sys_spindle->rpm))) { + if((sys_spindle->state = sys_spindle->hal->param->state = gc_block.spindle_modal.state).on) + sspindle = sys_spindle; + } + } + + if((spindle_ok ? false : (!spindle_ok || spindle_event)) && grbl.on_spindle_programmed) + grbl.on_spindle_programmed(sys_spindle->hal, sys_spindle->state, sys_spindle->rpm, sys_spindle->rpm_mode); } } while(idx); + + spindle_event = false; + + } else + +#endif // N_SYS_SPINDLE > 1 + + if((spindle_ok = sspindle->state.value != gc_block.spindle_modal.state.value)) { + + if(grbl.on_spindle_programmed) + grbl.on_spindle_programmed(sspindle->hal, gc_block.spindle_modal.state, sspindle->rpm, sspindle->rpm_mode); + + if((spindle_ok = spindle_sync(sspindle->hal, gc_block.spindle_modal.state, sspindle->rpm))) + sspindle->state = sspindle->hal->param->state = gc_block.spindle_modal.state; + + spindle_event = !spindle_ok; } - if(!(spindle_event = !spindle_ok)) - gc_state.modal.spindle.state = gc_block.modal.spindle.state; + + if(spindle_event && grbl.on_spindle_programmed) + grbl.on_spindle_programmed(sspindle->hal, sspindle->state, sspindle->rpm, sspindle->rpm_mode); } - if(spindle_event && grbl.on_spindle_programmed) - grbl.on_spindle_programmed(gc_state.spindle.hal, gc_state.modal.spindle.state, gc_state.spindle.rpm, gc_state.modal.spindle.rpm_mode); + if(sspindle != NULL) + gc_state.spindle = sspindle; // for now + // NOTE: Pass zero spindle speed for all restricted laser motions. + if(!gc_parser_flags.laser_disable) + memcpy(&plan_data.spindle, gc_state.spindle, sizeof(spindle_t)); // Record data for planner use. + else { + plan_data.spindle.hal = gc_state.spindle->hal; + // plan_data.spindle.speed = 0.0f; // Initialized as zero already. + } // TODO: Recheck spindle running in CCS mode (is_rpm_pos_adjusted == On)? - plan_data.spindle.state = gc_state.modal.spindle.state; // Set condition flag for planner use. + plan_data.spindle.state = gc_state.spindle->state; // Set condition flag for planner use. 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; @@ -3378,7 +3474,6 @@ status_code_t gc_execute_block (char *block) 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? @@ -3411,17 +3506,24 @@ status_code_t gc_execute_block (char *block) sys.override_delay.flags = 0; // [9. Override control ]: - if (gc_state.modal.override_ctrl.value != gc_block.modal.override_ctrl.value) { + if(command_words.M9 && gc_state.modal.override_ctrl.value != gc_block.modal.override_ctrl.value) { gc_state.modal.override_ctrl = gc_block.modal.override_ctrl; - gc_state.modal.spindle.state.override_disable = gc_state.spindle.hal->param->state.override_disable = gc_state.modal.override_ctrl.spindle_rpm_disable; + +#if N_SYS_SPINDLE > 1 + if(sspindle == NULL) { + uint_fast8_t idx = N_SYS_SPINDLE; + do { + set_spindle_override(&gc_state.modal.spindle[--idx], gc_state.modal.override_ctrl.spindle_rpm_disable); + } while(idx); + } else +#else + set_spindle_override(sspindle, gc_state.modal.override_ctrl.spindle_rpm_disable); +#endif if(gc_state.modal.override_ctrl.feed_rate_disable) plan_feed_override(0, 0); - if(gc_state.modal.override_ctrl.spindle_rpm_disable) - spindle_set_override(gc_state.spindle.hal, DEFAULT_SPINDLE_RPM_OVERRIDE); - mc_override_ctrl_update(gc_state.modal.override_ctrl); // NOTE: must be called last! } @@ -3841,7 +3943,6 @@ status_code_t gc_execute_block (char *block) gc_block.modal.canned_cycle_active = false; gc_state.modal.plane_select = PlaneSelect_XY; // gc_state.modal.plane_select = settings.flags.lathe_mode ? PlaneSelect_ZX : PlaneSelect_XY; - gc_state.modal.spindle.rpm_mode = SpindleSpeedMode_RPM; // NOTE: not compliant with linuxcnc (?) gc_state.modal.distance_incremental = false; gc_state.modal.feed_mode = FeedMode_UnitsPerMin; // TODO: check gc_state.distance_per_rev = 0.0f; @@ -3850,20 +3951,32 @@ status_code_t gc_execute_block (char *block) gc_state.modal.coord_system.id = CoordinateSystem_G54; system_add_rt_report(Report_GWCO); } - gc_state.modal.spindle.state = (spindle_state_t){0}; gc_state.modal.coolant = (coolant_state_t){0}; gc_state.modal.override_ctrl.feed_rate_disable = Off; gc_state.modal.override_ctrl.spindle_rpm_disable = Off; +#if N_SYS_SPINDLE > 1 + idx = N_SYS_SPINDLE; - spindle_ptrs_t *spindle; + spindle_t *spindle; do { - if((spindle = spindle_get(--idx))) { - spindle->param->state.override_disable = Off; + if((spindle = &gc_state.modal.spindle[--idx])) { + spindle->css = NULL; + spindle->state = (spindle_state_t){0}; + spindle->rpm_mode = SpindleSpeedMode_RPM; // NOTE: not compliant with linuxcnc (?); + spindle->hal->param->state.override_disable = Off; if(settings.flags.restore_overrides) - spindle->param->override_pct = DEFAULT_SPINDLE_RPM_OVERRIDE; + spindle->hal->param->override_pct = DEFAULT_SPINDLE_RPM_OVERRIDE; } } while(idx); +#else + gc_state.modal.spindle.css = NULL; + gc_state.modal.spindle.state = (spindle_state_t){0}; + gc_state.modal.spindle.rpm_mode = SpindleSpeedMode_RPM; // NOTE: not compliant with linuxcnc (?) + gc_state.modal.spindle.hal->param->state.override_disable = Off; + if(settings.flags.restore_overrides) + sspindle->hal->param->override_pct = DEFAULT_SPINDLE_RPM_OVERRIDE; +#endif if(settings.parking.flags.enabled) gc_state.modal.override_ctrl.parking_disable = settings.parking.flags.enable_override_control && diff --git a/gcode.h b/gcode.h index cb5394c..274d41f 100644 --- a/gcode.h +++ b/gcode.h @@ -498,9 +498,17 @@ typedef struct { } gc_value_ptr_t; typedef struct { + float rpm; //!< Spindle speed spindle_state_t state; //!< {M3,M4,M5} spindle_rpm_mode_t rpm_mode; //!< {G96,G97} -} spindle_mode_t; + spindle_css_data_t *css; //!< Data used for Constant Surface Speed Mode calculations + spindle_ptrs_t *hal; //!< Spindle function pointers etc. Must be last! +} spindle_t; + +typedef struct { + spindle_state_t state; //!< {M3,M4,M5} + spindle_rpm_mode_t rpm_mode; //!< {G96,G97} +} spindle_modal_t; // NOTE: When this struct is zeroed, the above defines set the defaults for the system. typedef struct { @@ -519,7 +527,11 @@ typedef struct { #endif program_flow_t program_flow; //!< {M0,M1,M2,M30,M60} coolant_state_t coolant; //!< {M7,M8,M9} - spindle_mode_t spindle; //!< {M3,M4,M5 and G96,G97} +#if N_SYS_SPINDLE > 1 + spindle_t spindle[N_SYS_SPINDLE]; +#else + spindle_t spindle; //!< {M3,M4,M5 and G96,G97} +#endif gc_override_flags_t override_ctrl; //!< {M48,M49,M50,M51,M53,M56} cc_retract_mode_t retract_mode; //!< {G98,G99} bool scaling_active; //!< {G50,G51} @@ -528,7 +540,6 @@ typedef struct { #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; @@ -575,20 +586,13 @@ typedef struct { tool_id_t tool_id; //!< Tool number } tool_data_t; -typedef struct { - float rpm; //!< Spindle speed - spindle_state_t state; - spindle_css_data_t *css; //!< Data used for Constant Surface Speed Mode calculations - spindle_ptrs_t *hal; -} spindle_t; - /*! \brief Parser state */ typedef struct { gc_modal_t modal; gc_canned_t canned; - spindle_t spindle; //!< RPM + spindle_t *spindle; //!< Last referenced spindle float feed_rate; //!< Millimeters/min float distance_per_rev; //!< Millimeters/rev float position[N_AXIS]; //!< Where the interpreter considers the tool to be at this point in the code @@ -636,11 +640,11 @@ typedef struct { user_mcode_t user_mcode; //!< Set > #UserMCode_Ignore if a user M-code is found. bool user_mcode_sync; //!< Set to \a true by M-code validation handler if M-code is to be executed after synchronization. gc_modal_t modal; //!< The current modal state is copied here before parsing starts. + spindle_modal_t spindle_modal; gc_values_t values; //!< Parameter values for block. parameter_words_t words; //!< Bitfield for tracking found parameter values. output_command_t output_command; //!< Details about M62-M68 output command to execute if present in block. uint32_t arc_turns; // - 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 @@ -676,7 +680,7 @@ float *gc_get_scaling (void); // Get current axis offset. float gc_get_offset (uint_fast8_t idx, bool real_time); -spindle_ptrs_t *gc_spindle_get (void); +spindle_t *gc_spindle_get (spindle_num_t spindle); void gc_spindle_off (void); void gc_coolant (coolant_state_t state); diff --git a/grbl.h b/grbl.h index 4594567..d620c73 100644 --- a/grbl.h +++ b/grbl.h @@ -42,7 +42,7 @@ #else #define GRBL_VERSION "1.1f" #endif -#define GRBL_BUILD 20240928 +#define GRBL_BUILD 20241006 #define GRBL_URL "https://github.com/grblHAL" diff --git a/motion_control.c b/motion_control.c index 29bbe45..715d810 100644 --- a/motion_control.c +++ b/motion_control.c @@ -627,7 +627,7 @@ void mc_canned_drill (motion_mode_t motion, float *target, plan_line_data_t *pl_ return; if(canned->spindle_off) - spindle_sync(pl_data->spindle.hal, gc_state.modal.spindle.state, pl_data->spindle.rpm); + spindle_sync(pl_data->spindle.hal, pl_data->spindle.state, pl_data->spindle.rpm); } pl_data->condition.rapid_motion = On; // Set rapid motion condition flag. diff --git a/ngc_params.c b/ngc_params.c index b78da3f..baa0c87 100644 --- a/ngc_params.c +++ b/ngc_params.c @@ -488,11 +488,11 @@ float ngc_named_param_get_by_id (ncg_name_param_id_t id) break; case NGCParam_spindle_rpm_mode: - value = gc_state.modal.spindle.rpm_mode == SpindleSpeedMode_RPM ? 1.0f : 0.0f; + value = gc_spindle_get(0)->rpm_mode == SpindleSpeedMode_RPM ? 1.0f : 0.0f; break; case NGCParam_spindle_css_mode: - value = gc_state.modal.spindle.rpm_mode == SpindleSpeedMode_CSS ? 1.0f : 0.0f; + value = gc_spindle_get(0)->rpm_mode == SpindleSpeedMode_CSS ? 1.0f : 0.0f; break; case NGCParam_ijk_absolute_mode: @@ -508,11 +508,11 @@ float ngc_named_param_get_by_id (ncg_name_param_id_t id) break; case NGCParam_spindle_on: - value = gc_state.modal.spindle.state.on ? 1.0f : 0.0f; + value = gc_spindle_get(0)->state.on ? 1.0f : 0.0f; break; case NGCParam_spindle_cw: - value = gc_state.modal.spindle.state.ccw ? 1.0f : 0.0f; + value = gc_spindle_get(0)->state.ccw ? 1.0f : 0.0f; break; case NGCParam_mist: @@ -544,7 +544,7 @@ float ngc_named_param_get_by_id (ncg_name_param_id_t id) break; case NGCParam_rpm: - value = gc_state.spindle.rpm; + value = gc_spindle_get(0)->rpm; break; case NGCParam_x: diff --git a/planner.c b/planner.c index c220217..768c3a7 100644 --- a/planner.c +++ b/planner.c @@ -691,7 +691,7 @@ 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->spindle.hal = gc_spindle_get(-1)->hal; plan_data->condition.target_validated = plan_data->condition.target_valid = sys.soft_limits.mask == 0; #ifdef KINEMATICS_API plan_data->rate_multiplier = 1.0f; diff --git a/protocol.c b/protocol.c index 95fa75b..ccb92b1 100644 --- a/protocol.c +++ b/protocol.c @@ -566,7 +566,6 @@ bool protocol_exec_rt_system (void) sys.override.control = gc_state.modal.override_ctrl; gc_state.tool_change = false; - gc_state.modal.spindle.rpm_mode = SpindleSpeedMode_RPM; // Tell driver/plugins about reset. hal.driver_reset(); @@ -684,7 +683,7 @@ bool protocol_exec_rt_system (void) if(!sys.override_delay.spindle && (rt_exec = get_spindle_override())) { bool spindle_stop = false; - spindle_ptrs_t *spindle = gc_spindle_get(); + spindle_ptrs_t *spindle = gc_spindle_get(-1)->hal; override_t last_s_override = spindle->param->override_pct; do { @@ -727,7 +726,7 @@ bool protocol_exec_rt_system (void) spindle_set_override(spindle, last_s_override); - if (spindle_stop && state_get() == STATE_HOLD && gc_state.modal.spindle.state.on) { + if (spindle_stop && state_get() == STATE_HOLD && gc_spindle_get(-1)->state.on) { // Spindle stop override allowed only while in HOLD state. // NOTE: Report flag is set in spindle_set_state() when spindle stop is executed. if (!sys.override.spindle_stop.value) diff --git a/report.c b/report.c index aaacf30..46ce07a 100644 --- a/report.c +++ b/report.c @@ -724,8 +724,8 @@ void report_gcode_modes (void) hal.stream.write(" G"); hal.stream.write(uitoa((uint32_t)(93 + (gc_state.modal.feed_mode == FeedMode_UnitsPerRev ? 2 : gc_state.modal.feed_mode ^ 1)))); - if(settings.mode == Mode_Lathe && gc_spindle_get()->cap.variable) - hal.stream.write(gc_state.modal.spindle.rpm_mode == SpindleSpeedMode_RPM ? " G97" : " G96"); + if(settings.mode == Mode_Lathe && gc_spindle_get(0)->hal->cap.variable) + hal.stream.write(gc_spindle_get(0)->rpm_mode == SpindleSpeedMode_RPM ? " G97" : " G96"); #if COMPATIBILITY_LEVEL < 10 @@ -777,7 +777,7 @@ void report_gcode_modes (void) } } - hal.stream.write(gc_state.modal.spindle.state.on ? (gc_state.modal.spindle.state.ccw ? " M4" : " M3") : " M5"); + hal.stream.write(gc_spindle_get(0)->state.on ? (gc_spindle_get(0)->state.ccw ? " M4" : " M3") : " M5"); if(gc_state.tool_change) hal.stream.write(" M6"); @@ -809,8 +809,8 @@ void report_gcode_modes (void) hal.stream.write(appendbuf(2, " F", get_rate_value(gc_state.feed_rate))); - if(gc_spindle_get()->cap.variable) - hal.stream.write(appendbuf(2, " S", ftoa(gc_state.spindle.rpm, N_DECIMAL_RPMVALUE))); + if(gc_spindle_get(0)->hal->cap.variable) + hal.stream.write(appendbuf(2, " S", ftoa(gc_spindle_get(0)->rpm, N_DECIMAL_RPMVALUE))); hal.stream.write("]" ASCII_EOL); } @@ -1450,12 +1450,13 @@ void report_realtime_status (void) static gc_modal_t last_state; static bool g92_active; - bool is_changed = feed_rate != gc_state.feed_rate || spindle_rpm != gc_state.spindle.rpm || tool_id != gc_state.tool->tool_id; + spindle_t *spindle = gc_spindle_get(0); + bool is_changed = feed_rate != gc_state.feed_rate || spindle_rpm != spindle->rpm || tool_id != gc_state.tool->tool_id; if(is_changed) { feed_rate = gc_state.feed_rate; tool_id = gc_state.tool->tool_id; - spindle_rpm = gc_state.spindle.rpm; + spindle_rpm = spindle->rpm; } else if ((is_changed = g92_active != is_g92_active())) g92_active = !g92_active; else if(memcmp(&last_state, &gc_state.modal, sizeof(gc_modal_t))) { @@ -2199,12 +2200,12 @@ status_code_t report_current_home_signal_state (sys_state_t state, char *args) // Prints spindle data (encoder pulse and index count, angular position). status_code_t report_spindle_data (sys_state_t state, char *args) { - spindle_ptrs_t *spindle = gc_spindle_get(); + spindle_t *spindle = gc_spindle_get(-1); - if(spindle->get_data) { + if(spindle->hal->get_data) { - float apos = spindle->get_data(SpindleData_AngularPosition)->angular_position; - spindle_data_t *data = spindle->get_data(SpindleData_Counters); + float apos = spindle->hal->get_data(SpindleData_AngularPosition)->angular_position; + spindle_data_t *data = spindle->hal->get_data(SpindleData_Counters); hal.stream.write("[SPINDLEENCODER:"); hal.stream.write(uitoa(data->index_count)); @@ -2217,7 +2218,7 @@ status_code_t report_spindle_data (sys_state_t state, char *args) hal.stream.write("]" ASCII_EOL); } - return spindle->get_data ? Status_OK : Status_InvalidStatement; + return spindle->hal->get_data ? Status_OK : Status_InvalidStatement; } // Prints info about registered pins. diff --git a/sleep.c b/sleep.c index abb067b..c35e125 100644 --- a/sleep.c +++ b/sleep.c @@ -75,7 +75,7 @@ void sleep_check (void) // has any powered components enabled. // NOTE: With overrides or in laser mode, modal spindle and coolant state are not guaranteed. Need // to directly monitor and record running state during parking to ensure proper function. - if (!(slumber || sys.steppers_deenergize || sys.flags.auto_reporting) && (gc_state.modal.spindle.state.value || gc_state.modal.coolant.value)) { + if (!(slumber || sys.steppers_deenergize || sys.flags.auto_reporting) && (gc_spindle_get(0)->state.value || gc_state.modal.coolant.value)) { switch(state_get()) { case STATE_IDLE: diff --git a/spindle_control.c b/spindle_control.c index e6e59d9..4010a98 100644 --- a/spindle_control.c +++ b/spindle_control.c @@ -510,19 +510,22 @@ void spindle_set_override (spindle_ptrs_t *spindle, override_t speed_override) speed_override = constrain(speed_override, MIN_SPINDLE_RPM_OVERRIDE, MAX_SPINDLE_RPM_OVERRIDE); - if ((uint8_t)speed_override != spindle->param->override_pct) { + if((uint8_t)speed_override != spindle->param->override_pct) { - spindle->param->override_pct = speed_override; + spindle_set_rpm(spindle, spindle->param->rpm, speed_override); - if(state_get() == STATE_IDLE) - spindle_set_state(spindle, gc_state.modal.spindle.state, gc_state.spindle.rpm); - else + if(state_get() == STATE_IDLE) { + if(spindle->get_pwm && spindle->update_pwm) + spindle->update_pwm(spindle, spindle->get_pwm(spindle, spindle->param->rpm_overridden)); + else if(spindle->update_rpm) + spindle->update_rpm(spindle, spindle->param->rpm_overridden); + } else sys.step_control.update_spindle_rpm = On; system_add_rt_report(Report_Overrides); // Set to report change immediately - if(grbl.on_spindle_programmed) - grbl.on_spindle_programmed(spindle, gc_state.modal.spindle.state, spindle_set_rpm(spindle, gc_state.spindle.rpm, speed_override), gc_state.modal.spindle.rpm_mode); +// if(grbl.on_spindle_programmed) +// grbl.on_spindle_programmed(spindle, spindle->param->state, spindle->param->rpm, spindle->param->rpm_mode); if(grbl.on_override_changed) grbl.on_override_changed(OverrideChanged_SpindleRPM); @@ -542,10 +545,10 @@ static bool set_state (spindle_ptrs_t *spindle, spindle_state_t state, float rpm if (!ABORTED) { // Block during abort. if (!state.on) { // Halt or set spindle direction and rpm. - spindle->param->rpm = rpm = 0.0f; + rpm = 0.0f; spindle->set_state(spindle, (spindle_state_t){0}, 0.0f); } else { - // NOTE: Assumes all calls to this function is when Grbl is not moving or must remain off. + // NOTE: Assumes all calls to this function is when grblHAL is not moving or must remain off. // TODO: alarm/interlock if going from CW to CCW directly in non-laser mode? if (spindle->cap.laser && state.ccw) rpm = 0.0f; // TODO: May need to be rpm_min*(100/MAX_SPINDLE_RPM_OVERRIDE); @@ -553,6 +556,9 @@ static bool set_state (spindle_ptrs_t *spindle, spindle_state_t state, float rpm spindle->set_state(spindle, state, spindle_set_rpm(spindle, rpm, spindle->param->override_pct)); } + spindle->param->rpm = rpm; + spindle->param->state = state; + system_add_rt_report(Report_Spindle); // Set to report change immediately st_rpm_changed(rpm); diff --git a/state_machine.c b/state_machine.c index 67f47ee..a60c654 100644 --- a/state_machine.c +++ b/state_machine.c @@ -122,7 +122,7 @@ static void enter_sleep (void) static bool initiate_hold (uint_fast16_t new_state) { - spindle_ptrs_t *spindle; + spindle_t *spindle; spindle_num_t spindle_num = N_SYS_SPINDLE; if (settings.parking.flags.enabled) { @@ -137,21 +137,21 @@ static bool initiate_hold (uint_fast16_t new_state) restore_condition.spindle_num = 0; do { - if((spindle = spindle_get(--spindle_num))) { - if(block && block->spindle.hal == spindle) { + if((spindle = gc_spindle_get(--spindle_num))) { + if(block && block->spindle.hal == spindle->hal) { restore_condition.spindle_num = spindle_num; restore_condition.spindle[spindle_num].hal = block->spindle.hal; restore_condition.spindle[spindle_num].rpm = block->spindle.rpm; restore_condition.spindle[spindle_num].state = block->spindle.state; - } else if(gc_state.spindle.hal == spindle) { + } else if(spindle->hal) { restore_condition.spindle_num = spindle_num; - restore_condition.spindle[spindle_num].hal = gc_state.spindle.hal; - restore_condition.spindle[spindle_num].rpm = gc_state.spindle.rpm; - restore_condition.spindle[spindle_num].state = gc_state.modal.spindle.state; + restore_condition.spindle[spindle_num].hal = spindle->hal; + restore_condition.spindle[spindle_num].rpm = spindle->rpm; + restore_condition.spindle[spindle_num].state = spindle->state; } else { - restore_condition.spindle[spindle_num].hal = spindle; - restore_condition.spindle[spindle_num].rpm = spindle->param->rpm; - restore_condition.spindle[spindle_num].state = spindle->param->state; + restore_condition.spindle[spindle_num].hal = NULL; +// restore_condition.spindle[spindle_num].rpm = spindle->param->rpm; +// restore_condition.spindle[spindle_num].state = spindle->param->state; } } else restore_condition.spindle[spindle_num].hal = NULL; @@ -352,7 +352,7 @@ void state_set (sys_state_t new_state) // Suspend manager. Controls spindle overrides in hold states. void state_suspend_manager (void) { - if (stateHandler != state_await_resume || !gc_state.modal.spindle.state.on) + if (stateHandler != state_await_resume || !gc_spindle_get(0)->state.on) return; if (sys.override.spindle_stop.value) { diff --git a/system.c b/system.c index 06a8ea7..aa28eab 100644 --- a/system.c +++ b/system.c @@ -167,12 +167,12 @@ static status_code_t read_int (char *s, int32_t *value) // Reset spindle encoder data static status_code_t spindle_reset_data (sys_state_t state, char *args) { - spindle_ptrs_t *spindle = gc_spindle_get(); + spindle_t *spindle = gc_spindle_get(-1); - if(spindle->reset_data) - spindle->reset_data(); + if(spindle->hal->reset_data) + spindle->hal->reset_data(); - return spindle->reset_data ? Status_OK : Status_InvalidStatement; + return spindle->hal->reset_data ? Status_OK : Status_InvalidStatement; } static status_code_t jog (sys_state_t state, char *args) @@ -767,7 +767,7 @@ const char *help_rtc (const char *cmd) const char *help_spindle (const char *cmd) { - spindle_ptrs_t *spindle = gc_spindle_get(); + spindle_ptrs_t *spindle = gc_spindle_get(0)->hal; if(cmd[1] == 'R' && spindle->reset_data) hal.stream.write("$SR - reset spindle encoder data." ASCII_EOL); diff --git a/tool_change.c b/tool_change.c index b43ba99..f352b1c 100644 --- a/tool_change.c +++ b/tool_change.c @@ -137,10 +137,12 @@ static bool restore (void) if(protocol_buffer_synchronize()) { + sync_position(); coolant_sync(gc_state.modal.coolant); - spindle_restore(plan_data.spindle.hal, gc_state.modal.spindle.state, gc_state.spindle.rpm); + spindle_t *spindle = gc_spindle_get(-1); + spindle_restore(spindle->hal, spindle->state, spindle->rpm); if(!settings.flags.no_restore_position_after_M6) { previous.values[plane.axis_linear] += gc_get_offset(plane.axis_linear, false);