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;
}