diff --git a/README.md b/README.md
index b6b1425..a361a15 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
## grblHAL ##
-Latest build date is 20260618, see the [changelog](changelog.md) for details.
+Latest build date is 20260619, see the [changelog](changelog.md) for details.
> [!NOTE]
> A settings reset will be performed on an update of builds prior to 20241208. Backup and restore of settings is recommended.
diff --git a/changelog.md b/changelog.md
index 561dacb..f11b356 100644
--- a/changelog.md
+++ b/changelog.md
@@ -1,5 +1,32 @@
## grblHAL changelog
+Build 20260619
+
+Core:
+
+* Made named O-call LinuxCNC compliant by changing name to lowercase.
+
+* Fix for parking motion using `$32` laser mode setting when it should use the current spindle mode.
+
+* For developers: changed signature of `hal.stream.on_linestate_changed()` to include stream properties.
+Currently the event only fires for native USB connections and it will now fire even if the current stream is not USB based.
+
+Drivers:
+
+* LPC176x, RP2040, STM32F1xx, STM32F3xx, STM32F4xx and STM32F7xx: updated for `hal.stream.on_linestate_changed()` signature change.
+> [!NOTE]
+> Other drivers that support native USB currently does not fire this event.
+
+* STM32F7xx: fixed typo that got committed. Ref. issue [#29](https://github.com/grblHAL/STM32F7xx/issues/29).
+
+Plugins:
+
+* SD card, macros: moved default values for `$675` - _Macro ATC Options_ to core.
+
+* SD card, stream: "hardened" code a bit.
+
+---
+
Build 20260618
Core:
diff --git a/config.h b/config.h
index 060147b..428348f 100644
--- a/config.h
+++ b/config.h
@@ -1496,6 +1496,20 @@ and less range over the total 255 PWM levels to signal different spindle speeds.
#endif
///@}
+/*! @name $675 - Setting_MacroATC_Options
+*/
+///@{
+#if !defined DEFAULT_MACRO_ATC_OPTION_EXECUTEM6T0 || defined __DOXYGEN__
+#define DEFAULT_MACRO_ATC_OPTION_EXECUTEM6T0 Off
+#endif
+#if !defined DEFAULT_MACRO_ATC_ERROR_NO_MACRO || defined __DOXYGEN__
+#define DEFAULT_MACRO_ATC_ERROR_NO_MACRO Off
+#endif
+#if !defined DEFAULT_MACRO_ATC_RANDOM_TOOLCHANGER || defined __DOXYGEN__
+#define DEFAULT_MACRO_ATC_RANDOM_TOOLCHANGER Off
+#endif
+///@}
+
// Homing settings (Group_Homing)
/*! @name $22 - Setting_HomingEnable
@@ -2202,12 +2216,12 @@ Filing systems options.
#define DEFAULT_FS_SD_AUTOMOUNT Off // Default disabled. Set to \ref On or 1 to enable.
#endif
-/*! /def DEFAULT_FS_LITLLEFS_HIDDEN
+/*! /def DEFAULT_FS_LITTLEFS_HIDDEN
\brief Hides LittleFS mount from directory listings.
\internal Bit 1 in settings.fs_options.mask.
*/
-#if !defined DEFAULT_FS_LITLLEFS_HIDDEN || defined __DOXYGEN__
-#define DEFAULT_FS_LITLLEFS_HIDDEN Off // Default disabled. Set to \ref On or 1 to enable.
+#if !defined DEFAULT_FS_LITTLEFS_HIDDEN || defined __DOXYGEN__
+#define DEFAULT_FS_LITTLEFS_HIDDEN Off // Default disabled. Set to \ref On or 1 to enable.
#endif
/*! /def DEFAULT_FS_HIERACHICAL_LISTING
@@ -2220,7 +2234,6 @@ Adds directory entries in $F and $F+ output to allow hierarchical navigation of
#endif
///@}
-
// Axis settings (Group_XAxis - Group_VAxis)
/*! @name $10x - Setting_AxisStepsPerMM
diff --git a/grbl.h b/grbl.h
index 79aedb6..abe6113 100644
--- a/grbl.h
+++ b/grbl.h
@@ -42,7 +42,7 @@
#else
#define GRBL_VERSION "1.1f"
#endif
-#define GRBL_BUILD 20260618
+#define GRBL_BUILD 20260619
#define GRBL_URL "https://github.com/grblHAL"
diff --git a/grbllib.c b/grbllib.c
index c1ad5e1..07c63c0 100644
--- a/grbllib.c
+++ b/grbllib.c
@@ -75,7 +75,6 @@ DCRAM grbl_t grbl;
DCRAM grbl_hal_t hal;
static driver_startup_t driver = { .ok = 0xFF };
-static on_linestate_changed_ptr on_linestate_changed;
static settings_changed_ptr hal_settings_changed;
static stepper_enable_ptr stepper_enable;
DCRAM static struct {
@@ -191,22 +190,6 @@ ISR_CODE static home_signals_t ISR_FUNC(get_homing_status2)(void)
return home;
}
-FLASHMEM static void output_welcome_message (void *data)
-{
- grbl.report.init_message(hal.stream.write);
-}
-
-FLASHMEM static void onLinestateChanged (serial_linestate_t state)
-{
- if(state.dtr) {
- task_delete(output_welcome_message, NULL);
- task_add_delayed(output_welcome_message, NULL, 200);
- }
-
- if(on_linestate_changed)
- on_linestate_changed(state);
-}
-
FLASHMEM static void stepperEnable (axes_signals_t enable, bool hold)
{
if(stepper_enable)
@@ -232,9 +215,9 @@ FLASHMEM static void print_pos_msg (void *data)
#pragma GCC diagnostic pop
#endif
-FLASHMEM static void onPosFailure (serial_linestate_t state)
+FLASHMEM static void onPosFailure (io_stream_properties_t *stream, serial_linestate_t state)
{
- if(state.dtr) // delay a bit to let the USB stack come up
+ if(state.dtr && stream->flags.is_usb == hal.stream.state.is_usb) // delay a bit to let the USB stack come up
task_add_delayed(print_pos_msg, NULL, 50);
}
@@ -461,11 +444,6 @@ FLASHMEM int grbl_enter (void)
setting_remove_elements(Setting_FSOptions, fs_options.mask, true);
}
- if(hal.stream.state.linestate_event && !hal.stream.state.passthru) {
- on_linestate_changed = hal.stream.on_linestate_changed;
- hal.stream.on_linestate_changed = onLinestateChanged;
- }
-
if(grbl.on_probe_toolsetter == NULL && hal.driver_cap.toolsetter && hal.probe.select)
grbl.on_probe_toolsetter = onProbeToolsetter;
diff --git a/ngc_expr.c b/ngc_expr.c
index eafcfde..0aa7b2d 100644
--- a/ngc_expr.c
+++ b/ngc_expr.c
@@ -591,7 +591,7 @@ starting at the index given by the pos offset.
*/
FLASHMEM status_code_t ngc_read_name (char *line, uint_fast8_t *pos, char *buffer)
{
- char *s;
+ char c, *s;
uint_fast8_t len = 0;
status_code_t status = Status_BadNumberFormat;
@@ -599,13 +599,13 @@ FLASHMEM status_code_t ngc_read_name (char *line, uint_fast8_t *pos, char *buffe
s++;
- while(*s && *s != '>' && len <= NGC_MAX_PARAM_LENGTH) {
- *buffer++ = *s++;
+ while((c = *s++) && c != '>' && len <= NGC_MAX_PARAM_LENGTH) {
+ *buffer++ = LCAPS(c);
(*pos)++;
len++;
}
- if((status = *s == '>' ? Status_OK : Status_FlowControlSyntaxError) == Status_OK) {
+ if((status = c == '>' ? Status_OK : Status_FlowControlSyntaxError) == Status_OK) {
*buffer = '\0';
(*pos)++;
}
diff --git a/settings.c b/settings.c
index dc8fafb..7deecc7 100644
--- a/settings.c
+++ b/settings.c
@@ -370,6 +370,10 @@ PROGMEM static const settings_t defaults = {
.tool_change.seek_rate = DEFAULT_TOOLCHANGE_SEEK_RATE,
.tool_change.pulloff_rate = DEFAULT_TOOLCHANGE_PULLOFF_RATE,
+ .macro_atc_flags.execute_m6t0 = DEFAULT_MACRO_ATC_OPTION_EXECUTEM6T0,
+ .macro_atc_flags.error_on_no_macro = DEFAULT_MACRO_ATC_ERROR_NO_MACRO,
+ .macro_atc_flags.random_toolchanger = DEFAULT_MACRO_ATC_RANDOM_TOOLCHANGER,
+
.parking.flags.enabled = DEFAULT_PARKING_ENABLE,
.parking.flags.deactivate_upon_init = DEFAULT_DEACTIVATE_PARKING_UPON_INIT,
.parking.flags.enable_override_control= DEFAULT_ENABLE_PARKING_OVERRIDE_CONTROL,
@@ -385,7 +389,7 @@ PROGMEM static const settings_t defaults = {
.safety_door.coolant_on_delay = DEFAULT_SAFETY_DOOR_COOLANT_DELAY,
.fs_options.sd_mount_on_boot = DEFAULT_FS_SD_AUTOMOUNT,
- .fs_options.lfs_hidden = DEFAULT_FS_LITLLEFS_HIDDEN,
+ .fs_options.lfs_hidden = DEFAULT_FS_LITTLEFS_HIDDEN,
.fs_options.hierarchical_listing = DEFAULT_FS_HIERACHICAL_LISTING,
.modbus_baud = DEFAULT_MODBUS_STREAM_BAUD,
diff --git a/state_machine.c b/state_machine.c
index 724d9c4..f697503 100644
--- a/state_machine.c
+++ b/state_machine.c
@@ -535,7 +535,7 @@ FLASHMEM static void state_await_hold (uint_fast16_t rt_exec)
// Parking requires parking axis homed, the current location not exceeding the
// parking target location, and laser mode disabled.
- if (settings.parking.flags.enabled && !sys.override.control.parking_disable && settings.mode != Mode_Laser) {
+ if (settings.parking.flags.enabled && !sys.override.control.parking_disable && gc_spindle_get(0)->hal->cap.laser) {
// Get current position and store as restore location.
if (!park.flags.active) {
diff --git a/stream.c b/stream.c
index 63a8952..a5e6f90 100644
--- a/stream.c
+++ b/stream.c
@@ -24,6 +24,7 @@
#include "hal.h"
#include "protocol.h"
+#include "task.h"
#include "state_machine.h"
#if defined(DEBUG) || defined(DEBUGOUT)
@@ -300,26 +301,41 @@ FLASHMEM static stream_connection_t *add_connection (const io_stream_t *stream)
return connection;
}
+FLASHMEM static void output_welcome_message (void *data)
+{
+ grbl.report.init_message(hal.stream.write);
+}
+
+FLASHMEM void stream_usb_linestate_changed (uint8_t instance, serial_linestate_t state)
+{
+ if(state.dtr && hal.stream.state.is_usb && !hal.stream.state.passthru) {
+ task_delete(output_welcome_message, NULL);
+ task_add_delayed(output_welcome_message, NULL, 200);
+ }
+
+ if(hal.stream.on_linestate_changed) {
+
+ io_stream_properties_t prop = {
+ .type = StreamType_Serial,
+ .instance = instance,
+ .flags.is_usb = On
+ };
+
+ hal.stream.on_linestate_changed(&prop, state);
+ }
+}
+
FLASHMEM static bool stream_select (const io_stream_t *stream, bool add)
{
static const io_stream_t *active_stream = NULL;
bool send_init_message = false, mpg_enable = false;
- static struct {
- const io_stream_t *stream;
- on_linestate_changed_ptr on_linestate_changed;
- } usb = {};
if(stream == base.stream) {
base.is_up = add ? (stream->is_connected ? stream->is_connected : stream_connected) : is_not_connected;
return true;
}
- if(active_stream != NULL && hal.stream.state.is_usb) {
- usb.stream = active_stream;
- usb.on_linestate_changed = hal.stream.on_linestate_changed;
- }
-
if(!add) { // disconnect
if(stream == base.stream || stream == &mpg.stream)
@@ -391,8 +407,8 @@ FLASHMEM static bool stream_select (const io_stream_t *stream, bool add)
memcpy(&hal.stream, stream, offsetof(io_stream_t, report));
- if(stream == usb.stream)
- hal.stream.on_linestate_changed = usb.on_linestate_changed;
+// if(stream == usb.stream)
+// hal.stream.on_linestate_changed = usb.on_linestate_changed;
if(stream == base.stream && base.is_up == is_not_connected)
base.is_up = stream_connected;
diff --git a/stream.h b/stream.h
index b68f6b0..92b6456 100644
--- a/stream.h
+++ b/stream.h
@@ -85,8 +85,8 @@ typedef enum {
StreamType_Bluetooth,
StreamType_Telnet,
StreamType_WebSocket,
- StreamType_SDCard, // deprecated, use StreamType_File instead
- StreamType_File = StreamType_SDCard,
+ StreamType_File,
+ StreamType_SDCard = StreamType_File, // deprecated, use StreamType_File instead
StreamType_Redirected,
StreamType_Null
} stream_type_t;
@@ -203,6 +203,9 @@ typedef struct {
uint8_t wco_counter; //!< Tracks when to add work coordinate offset data to status reports.
} status_report_tracking_t;
+struct io_stream_properties;
+typedef struct io_stream_properties io_stream_properties_t;
+
/*! \brief Pointer to function for getting stream connected status.
\returns \a true connected, \a false otherwise.
*/
@@ -326,7 +329,7 @@ typedef bool (*disable_rx_stream_ptr)(bool disable);
\param \a serial_linestate_t enum.
*/
-typedef void (*on_linestate_changed_ptr)(serial_linestate_t state);
+typedef void (*on_linestate_changed_ptr)(io_stream_properties_t *stream, serial_linestate_t state);
typedef union {
uint8_t value;
@@ -338,7 +341,7 @@ typedef union {
modbus_ready :1,
rts_handshake :1,
init_ok :1,
- unused :1;
+ is_usb :1;
};
} io_stream_flags_t;
@@ -380,9 +383,10 @@ typedef struct {
set_baud_rate_ptr set_baud_rate; //!< Optional handler for setting the stream baud rate. Required for Modbus/RS-485 support, recommended for Bluetooth support.
set_format_ptr set_format; //!< Optional handler for setting the stream format.
stream_set_direction_ptr set_direction; //!< Optional handler for setting the transfer direction for half-duplex communication.
- on_linestate_changed_ptr on_linestate_changed; //!< Optional handler to be called when line state changes. Set by client.
vfs_file_t *file; //!< File handle, non-null if streaming from a file.
+// The following fields are kept over a stream change
status_report_tracking_t report; //!< Tracks when to add data to status reports.
+ on_linestate_changed_ptr on_linestate_changed; //!< Optional handler to be called when line state changes. Set by client.
} io_stream_t;
typedef struct {
@@ -396,14 +400,14 @@ typedef const io_stream_t *(*stream_claim_ptr)(uint32_t baud_rate);
typedef bool (*stream_release_ptr)(uint8_t instance);
typedef const io_stream_status_t *(*stream_get_status_ptr)(uint8_t instance);
-typedef struct {
+struct io_stream_properties {
stream_type_t type; //!< Type of stream.
uint8_t instance; //!< Instance of stream type, starts from 0.
io_stream_flags_t flags;
stream_claim_ptr claim;
stream_release_ptr release;
stream_get_status_ptr get_status; //!< Optional handler for getting stream status, for UART streams only
-} io_stream_properties_t;
+};
typedef bool (*stream_enumerate_callback_ptr)(io_stream_properties_t const *properties, void *data);
@@ -512,6 +516,8 @@ const io_stream_status_t *stream_get_uart_status (uint8_t instance);
const io_stream_t *stream_null_init (uint32_t baud_rate);
+void stream_usb_linestate_changed (uint8_t instance, serial_linestate_t state);
+
io_stream_t const *stream_open_instance (uint8_t instance, uint32_t baud_rate, stream_write_char_ptr rx_handler, const char *description);
bool stream_close (io_stream_t const *stream);
bool stream_set_description (const io_stream_t *stream, const char *description);
diff --git a/stream_passthru.c b/stream_passthru.c
index ff1caed..5c16649 100644
--- a/stream_passthru.c
+++ b/stream_passthru.c
@@ -3,7 +3,7 @@
Part of grblHAL
- Copyright (c) 2024-2025 Terje Io
+ Copyright (c) 2024-2026 Terje Io
grblHAL is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -70,7 +70,7 @@ static void forward_uart_rx (void *data)
task_add_delayed(forward_uart_rx, NULL, 8);
}
-static void onLinestateChanged (serial_linestate_t state)
+static void onLinestateChanged (io_stream_properties_t *stream, serial_linestate_t state)
{
/*
Auto program
@@ -80,7 +80,7 @@ static void onLinestateChanged (serial_linestate_t state)
1 0 0 1
0 1 1 0
*/
- if(conn_ok) {
+ if(conn_ok && stream->flags.is_usb) {
if(state.dtr == state.rts) {
ioport_digital_out(boot0_port, 0);
diff --git a/system.c b/system.c
index 6fea714..9f6048b 100644
--- a/system.c
+++ b/system.c
@@ -122,7 +122,7 @@ ISR_CODE void ISR_FUNC(control_interrupt_handler)(control_signals_t signals)
// NOTE: at least for lasers there should be an external interlock blocking laser power.
if(state_get() != STATE_IDLE && state_get() != STATE_JOG)
system_set_exec_state_flag(EXEC_SAFETY_DOOR);
- if(settings.mode == Mode_Laser) // Turn off spindle immediately (laser) when in laser mode
+ if(gc_spindle_get(0)->hal->cap.laser) // Turn off spindle immediately (laser) when in laser mode
spindle_all_off(true);
} else
system_set_exec_state_flag(EXEC_SAFETY_DOOR);