gc_init subscribes to grbl.on_settings_changed by capturing the previous
handler to chain it. When no plugin or driver has subscribed before the
first gc_init, the captured pointer is NULL and the chained call in
onSettingsChanged dereferences it - every runtime $-setting write then
crashes on drivers with no other subscriber (observed live with the
Simulator). The core dispatcher already NULL-checks its own pointer;
this adds the same guard to the chained tail.
Improved handling of some VFS file system actions (unlink, mkdirv and rmdir), added support for truncate.
Changed some kinematics API function signatures for readability/debugability.
The ioports implementation has been changed to allow for consecutive pin numbers for external (expander based) I/O. See changelog for details.
fs_stat() builds the path it looks up with strcat(strcpy(path, "/"),
filename) into a fixed char path[64] on the stack, with no check that
"/" + filename actually fits. Any filename of 63 bytes or more (very
easy to hit with a normal nested SD/LittleFS path, or over FTP/WebDAV/
the WebUI file browser once a network plugin is enabled) overflows the
stack buffer.
This is the exact same class of bug just fixed elsewhere in this file
(PR #986 / commit c84cda0, "correctly handle long working directory
paths") for parse_path() and vfs_chdir(), but fs_stat() itself wasn't
touched by that change and still has the raw fixed-size buffer.
Fix it the same way the recent VFS work handles long names elsewhere:
keep the 64-byte stack buffer for the common short-path case, and fall
back to a heap allocation sized to the actual path when it doesn't fit,
instead of silently overflowing.
Verified with a standalone harness that reproduces fs_stat()'s buffer
layout: filenames up to 62 bytes behave unchanged, 63+ bytes overflow
adjacent stack memory in the original code and eventually crash the
process for larger inputs, and no longer touch anything past the
buffer with the fix (heap path used exactly when the stack buffer
would not fit, freed exactly once, no leaks).
Ref. PR#986 which is a partial fix.
Updated named O calls to allow name lengths only limited by available heap.
Ref. PR#989 which likely would return an error on overly long names and would potentially execute incorrect code if not.
modbus_message wrote register values into the fixed-size adu[] buffer
before any length validation; the only size check runs later in
modbus_send_rtu. A register count above MODBUS_MAX_REGISTERS overran
both the caller's values[] array and adu[], and even a multi-register
write within the register limit could exceed MODBUS_MAX_ADU_SIZE and
write past the buffer.
Reject requests exceeding MODBUS_MAX_REGISTERS, and reject multi-register
write frames larger than MODBUS_MAX_ADU_SIZE, before any adu[] write.
Single-register reads and writes are unaffected.
In the both-rotation-axes branch, bit_false(r_around.mask, bit(idx)) used the stale
outer loop variable idx instead of idx_0. When idx != idx_0, idx_1 (the second
rotation-plane axis) came out wrong, so in the final offset loop that axis was not
recognized as a rotation axis and its WCS offset was applied a second time. Result:
a rotated G54 move with both X and Y present targeted (work + 2x offset) on the second
axis -> false soft-limit (Alarm:2). Reproduced on hardware; only a nonzero WCS rotation
+ a full-plane G54 move triggers it. Fix: clear bit(idx_0).
Upstream grblHAL bug - PR-worthy.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Commit 41abd8c dropped the disable_motors() call that restores
SquaringMode_Both after the dual axis offset pull-off move at the end
of homing.
When an auto squared axis has a non-zero $17n offset, homing masks off
one of the two motors for the compensation move and never unmasks it.
The motor stays step-disabled for all subsequent motion until a soft
reset, so the axis moves on one motor only while jogging or running a
program. A negative offset strands the second motor, a positive one
strands the first.
Restore the call so both motors are re-enabled once the pull-off
completes.
Only affects builds with ROTATION_ENABLE defined; the offending code is inside
#ifdef ROTATION_ENABLE, so default builds are unaffected.
The rotation-transform block was entered for any axis-word motion without
excluding NonModal_AbsoluteOverride, so G53 (absolute machine override) moves
had the active WCS offset added to the plane axes (and were rotated). Per
RS274/NGC a G53 target is in machine coordinates and must ignore all offsets
and rotation.
Symptom: with a non-zero WCS rotation active (e.g. set by G10 L2 R / G68), G53
drives to the rotated work origin instead of the machine target, false-
triggering a soft-limit alarm when that lands outside the machine envelope.
Guard the transform with `non_modal_command != NonModal_AbsoluteOverride`, and
initialise r_axes.mask = 0 so it stays defined when the block is bypassed.
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.
Added P-word option to G38.x probe commands, use to temporarily switch the probe input when multiple probes are available.
Fixed PWM spindle ramping, did not hit the target RPM.
Changes to allow stepper spindle to use per degree settings, ref. issue 926.
Changes for improved line number reporting for subroutines and branching gcode.