diff --git a/README.md b/README.md index 63b4946..ff1cde5 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 20230606, see the [changelog](changelog.md) for details. +Latest build date is 20230607, see the [changelog](changelog.md) for details. __NOTE:__ A settings reset will be performed on an update of builds earlier than 20230125. Backup and restore of settings is recommended. __IMPORTANT!__ A new setting has been introduced for ganged axes motors in build 20211121. I have only bench tested this for a couple of drivers, correct function should be verified after updating by those who have more than three motors configured. @@ -91,4 +91,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. --- -2023-06-06 +2023-06-07 diff --git a/changelog.md b/changelog.md index 4ba6514..64ded26 100644 --- a/changelog.md +++ b/changelog.md @@ -1,11 +1,28 @@ ## grblHAL changelog +Build 20230607 + +Core: + +* Added initial support for macro based automatic tool changes (ATC). +Currently macros has to be stored on a SD card or in littlefs and [expression support](https://github.com/grblHAL/core/wiki/Expressions-and-flow-control) has to be enabled. + +* Added core events for file system mount/unmount. + +Plugins: + +* SD Card, macro plugin: Implemented automatic hook to tool change functions when tool change macros are found in the root mount directory. +Tool change macro: _tc.macro_, called on `M6`. \(required\) +Tool select macro: _ts.macro_, called on `T`. \(optional\). +__NOTE:__ This functionality needs to be extensively tested by users having access to ATC hardware! [Discuss here](https://github.com/grblHAL/core/discussions/309). + +--- + Build 20230606 Core: * Fixed regression related to CSS \(Constant Surface Speed for lathes\) mode. - * Improved stream handling for native USB streams when another stream claims/releases full control. Depending on the driver some output, such as real-time reports, will now be sent to the USB stream if it is connected to a client \(detected by DTR signal asserted\). When a pendant is in control \(via the MPG interface\) the USB interface will no longer block transmission if it is the primary interface and no client is connected. diff --git a/core_handlers.h b/core_handlers.h index f43d8fc..7d54eb3 100644 --- a/core_handlers.h +++ b/core_handlers.h @@ -108,6 +108,8 @@ typedef bool (*on_spindle_select_ptr)(spindle_ptrs_t *spindle); typedef void (*on_spindle_selected_ptr)(spindle_ptrs_t *spindle); typedef void (*on_gcode_message_ptr)(char *msg); typedef void (*on_rt_reports_added_ptr)(report_tracking_flags_t report); +typedef void (*on_vfs_mount_ptr)(const char *path, const vfs_t *fs); +typedef void (*on_vfs_unmount_ptr)(const char *path); typedef status_code_t (*on_file_open_ptr)(const char *fname, vfs_file_t *handle, bool stream); typedef status_code_t (*on_unknown_sys_command_ptr)(sys_state_t state, char *line); // return Status_Unhandled. typedef status_code_t (*on_user_command_ptr)(char *line); @@ -156,6 +158,8 @@ typedef struct { on_spindle_select_ptr on_spindle_select; //!< Called before spindle is selected, hook in HAL overrides here on_spindle_selected_ptr on_spindle_selected; //!< Called when spindle is selected, do not change HAL pointers here! on_reset_ptr on_reset; //!< Called from interrupt context. + on_vfs_mount_ptr on_vfs_mount; //!< Called when a file system is mounted. + on_vfs_unmount_ptr on_vfs_unmount; //!< Called when a file system is unmounted. on_file_open_ptr on_file_open; //!< Called when a file is opened for streaming. // core entry points - set up by core before driver_init() is called. enqueue_gcode_ptr enqueue_gcode; diff --git a/gcode.c b/gcode.c index ef82698..dd6702d 100644 --- a/gcode.c +++ b/gcode.c @@ -365,6 +365,29 @@ spindle_ptrs_t *gc_spindle_get (void) return gc_state.spindle.hal; } +static tool_data_t *tool_get_pending (uint32_t tool) +{ +#if N_TOOLS + return &tool_table[tool]; +#else + static tool_data_t tool_data = {0}; + + memcpy(&tool_data, gc_state.tool, sizeof(tool_data_t)); + tool_data.tool = tool; + + return &tool_data; +#endif +} + +static inline void tool_set (tool_data_t *tool) +{ +#if N_TOOLS + gc_state.tool = tool; +#else + gc_state.tool->tool = tool->tool; +#endif +} + // Add output command to linked list static bool add_output_command (output_command_t *command) { @@ -441,7 +464,7 @@ static status_code_t read_parameter (char *line, uint_fast8_t *char_counter, flo if(*(line + *char_counter) == '<') { (*char_counter)++; - char *pos = line + *char_counter; + char *pos = line = line + *char_counter; while(*line && *line != '>') line++; @@ -1692,6 +1715,18 @@ status_code_t gc_execute_block (char *block) gc_block.values.t = (uint32_t)gc_block.values.q; gc_block.words.q = Off; +#if NGC_EXPRESSIONS_ENABLE + if(sys.macro_file) { + gc_state.tool_pending = 0; // force set tool + #if N_TOOLS + if(gc_state.g43_pending) { + gc_block.values.h = gc_state.g43_pending; + command_words.G8 = On; + } + gc_state.g43_pending = 0; + #endif + } +#endif } else if (!gc_block.words.t) gc_block.values.t = gc_state.tool_pending; @@ -2914,15 +2949,13 @@ status_code_t gc_execute_block (char *block) // [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) { - gc_state.tool_pending = gc_block.values.t; + tool_data_t *pending_tool = tool_get_pending((gc_state.tool_pending = gc_block.values.t)); // If M6 not available or M61 commanded set new tool immediately if(set_tool || settings.tool_change.mode == ToolChange_Ignore || !(hal.stream.suspend_read || hal.tool.change)) { -#if N_TOOLS - gc_state.tool = &tool_table[gc_state.tool_pending]; -#else - gc_state.tool->tool = gc_state.tool_pending; -#endif + + tool_set(pending_tool); + if(grbl.on_tool_selected) { spindle_state_t state = gc_state.modal.spindle.state; @@ -2937,13 +2970,9 @@ status_code_t gc_execute_block (char *block) } // Prepare tool carousel when available - if(hal.tool.select) { -#if N_TOOLS - hal.tool.select(&tool_table[gc_state.tool_pending], !set_tool); -#else - hal.tool.select(gc_state.tool, !set_tool); -#endif - } else + if(hal.tool.select) + hal.tool.select(pending_tool, !set_tool); + else system_add_rt_report(Report_Tool); } @@ -2981,6 +3010,8 @@ status_code_t gc_execute_block (char *block) // [6. Change tool ]: Delegated to (possible) driver implementation if (command_words.M6 && !set_tool && !check_mode) { + tool_data_t *pending_tool = tool_get_pending(gc_state.tool_pending); + protocol_buffer_synchronize(); if(plan_data.message) { @@ -2988,31 +3019,42 @@ status_code_t gc_execute_block (char *block) plan_data.message = NULL; } -#if N_TOOLS - gc_state.tool = &tool_table[gc_state.tool_pending]; -#else - gc_state.tool->tool = gc_state.tool_pending; -#endif - if(grbl.on_tool_selected) { spindle_state_t state = gc_state.modal.spindle.state; - 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(hal.tool.change) { // ATC - if((int_value = (uint_fast16_t)hal.tool.change(&gc_state)) != Status_OK) - FAIL((status_code_t)int_value); + if((int_value = (uint_fast16_t)hal.tool.change(&gc_state)) != Status_OK) { +#if NGC_EXPRESSIONS_ENABLE + if(int_value != Status_Unhandled) +#endif + FAIL((status_code_t)int_value); + } system_add_rt_report(Report_Tool); } else { // Manual + int_value = (uint_fast16_t)Status_OK; gc_state.tool_change = true; system_set_exec_state_flag(EXEC_TOOL_CHANGE); // Set up program pause for manual tool change protocol_execute_realtime(); // Execute... } +#if NGC_EXPRESSIONS_ENABLE + if((status_code_t)int_value != Status_Unhandled) + tool_set(pending_tool); + #if N_TOOLS + else if(command_words.G8 && gc_block.modal.tool_offset_mode && ToolLengthOffset_Enable) { + gc_state.g43_pending = gc_block.values.h; + command_words.G8 = Off; + } + #endif +#else + tool_set(pending_tool); +#endif } // [7. Spindle control ]: diff --git a/gcode.h b/gcode.h index 34c6ccf..53355d7 100644 --- a/gcode.h +++ b/gcode.h @@ -526,6 +526,9 @@ typedef struct { // float blending_tolerance; //!< Motion blending tolerance int32_t line_number; //!< Last line number sent uint32_t tool_pending; //!< Tool to be selected on next M6 +#if N_TOOLS && NGC_EXPRESSIONS_ENABLE + uint32_t g43_pending; //!< Tool offset to be selected on next M6, for macro ATC +#endif bool file_run; //!< Tracks % command bool is_laser_ppi_mode; bool is_rpm_rate_adjusted; diff --git a/grbl.h b/grbl.h index d21e044..f30773d 100644 --- a/grbl.h +++ b/grbl.h @@ -42,7 +42,7 @@ #else #define GRBL_VERSION "1.1f" #endif -#define GRBL_BUILD 20230606 +#define GRBL_BUILD 20230607 #define GRBL_URL "https://github.com/grblHAL" diff --git a/ngc_params.c b/ngc_params.c index 4a8470a..2453339 100644 --- a/ngc_params.c +++ b/ngc_params.c @@ -513,7 +513,7 @@ float ngc_named_param_get_by_id (ncg_name_param_id_t id) break; case NGCParam_selected_tool: - value = gc_state.tool_change ? (float)gc_state.tool_pending : -1.0f; + value = gc_state.tool_pending != gc_state.tool->tool ? (float)gc_state.tool_pending : -1.0f; break; case NGCParam_selected_pocket: diff --git a/report.c b/report.c index ea59379..0923463 100644 --- a/report.c +++ b/report.c @@ -953,13 +953,8 @@ void report_build_info (char *line, bool extended) strcat(buf, "EXPR,"); #endif - #if N_TOOLS - if(hal.driver_cap.atc && hal.tool.change) - strcat(buf, "ATC,"); - else - #endif - if(hal.stream.suspend_read) - strcat(buf, "TC,"); // Manual tool change supported (M6) + if(hal.tool.change) + strcat(buf, hal.driver_cap.atc ? "ATC," : "TC,"); // Tool change supported (M6) if(hal.driver_cap.spindle_sync) strcat(buf, "SS,"); diff --git a/vfs.c b/vfs.c index f063056..f67ea34 100644 --- a/vfs.c +++ b/vfs.c @@ -5,7 +5,7 @@ Part of grblHAL - Copyright (c) 2022 Terje Io + Copyright (c) 2022-2023 Terje Io Grbl is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -413,6 +413,9 @@ bool vfs_mount (const char *path, const vfs_t *fs) mount->next = vfs; } + if(fs && grbl.on_vfs_mount) + grbl.on_vfs_mount(path, fs); + return fs != NULL; } @@ -440,6 +443,9 @@ bool vfs_unmount (const char *path) } } + if(grbl.on_vfs_unmount) + grbl.on_vfs_unmount(path); + return true; }