Skip to content

Feature/start print from z#28458

Open
sstefanov wants to merge 3 commits into
MarlinFirmware:bugfix-2.1.xfrom
sstefanov:feature/start-print-from-z
Open

Feature/start print from z#28458
sstefanov wants to merge 3 commits into
MarlinFirmware:bugfix-2.1.xfrom
sstefanov:feature/start-print-from-z

Conversation

@sstefanov

@sstefanov sstefanov commented Jun 11, 2026

Copy link
Copy Markdown

Description

Adds a START_PRINT_FROM_Z feature that lets a user resume a print at a chosen Z height — useful as a manual fallback when no power-loss recovery file was saved (crash, manual abort, swapped SD card, etc.).

How it works (high level)

  1. Selecting a file on the LCD opens a small action submenu:
    • Cancel
    • Print from Z: <value> (0 = normal print)
    • Print
  2. When a non-zero target Z is chosen, the SD file is pre-scanned (no motion) to simulate G-code state (position, temps, fans, tool, relative/absolute modes, G92 offsets).
  3. Scanning tracks the most recent line that established the current Z. Resuming triggers only when an extrusion move occurs at or beyond the target Z, avoiding false triggers from parking/purge moves.
  4. A self-contained resume sequence is enqueued (heat bed/hotends, home XY, move to Z, restore extruder counter, restore fan speeds, continue file from the saved byte offset). No POWER_LOSS_RECOVERY dependency.
  5. Live progress is reported during long scans: LCD status "Scan Z 1.2/12.0 56%" and serial "SkipToZ: 56% z=1.2/12.0 sdpos=12345".

New G-code: M1005 — internal entry point that triggers the scan and resume. Uses a free M-code slot. Documented in gcode.h.

New files

  • Marlin/src/feature/skip_to_z.{h,cpp} — line-buffered scan engine (128 B buffer), lightweight parameter parser, idle() called every 100 ms to keep watchdog/thermals/UI alive on slow hardware.
  • Marlin/src/gcode/feature/skipz/M1005.cpp — G-code entry point.

Modified files

  • Configuration_adv.h — new option block under HAS_MEDIA (disabled by default) with START_PRINT_FROM_Z_MAX and START_PRINT_FROM_Z_DEBUG.
  • gcode.{h,cpp} — declare and dispatch M1005.
  • ini/features.inibuild_src_filter so skip_to_z.cpp and M1005.cpp are only compiled when the feature is enabled.
  • sd/cardreader.cppopenAndPrintFile() injects the alt sequence when SkipToZ::target_z > 0; one-shot (cleared after use).
  • inc/SanityCheck.h — requires HAS_MEDIA only.
  • lcd/menu/menu_media.cpp — per-file action submenu (menu_sd_file_action()), float52 edit item for target Z.
  • lcd/menu/menu.hcurrent_edit_value() public static accessor on MenuEditItemBase so context-sensitive input can detect the active field.
  • lcd/language/language_en.hMSG_START_PRINT_FROM_Z, MSG_SKIP_TO_Z_SCAN.

ADC keypad (ZONESTAR_LCD etc.) — while editing target_z with Z homed, the RIGHT button loads the current Z position instead of clearing to zero. All other fields retain existing behavior.

Requirements

  • SDSUPPORT

Benefits

  • Lets users recover interrupted prints without a power-loss recovery file.
  • Fully self-contained: no PLR flash cost on boards that don't need it.
  • Smart extrusion-aware trigger avoids false resumes on parking/purge moves.
  • Live scan progress keeps the user informed on slow hardware.
  • Per-file action submenu keeps the file list uncluttered and intent explicit.

Configurations

Enable in Configuration_adv.h:

#define START_PRINT_FROM_Z
//#define START_PRINT_FROM_Z_MAX 300  // optional: clamp max Z value
//#define START_PRINT_FROM_Z_DEBUG    // optional: verbose serial output

No special hardware required beyond an SD card reader and an LCD.

Related Issues

Feature request — manual Z-skip resume for interrupted prints.

Adds an LCD menu item "Start from Z" (in the SD file browser) and a
new internal G-code M1003 that lets the user begin a print mid-file at
a chosen Z height — useful as a manual replacement for power-loss
recovery when no recovery file was saved (crash, manual abort, swapped
SD card).

How it works
------------
- The user sets a target Z via the new EDIT_ITEM in menu_media.
- When a file is selected, openAndPrintFile() injects
    M23 <file>\nM1003 Z<value>
  instead of the usual M23+M24.
- M1003 pre-scans the open SD file from offset 0, simulating G-code
  state (X/Y/Z/E, abs/rel modes, units, G92, target hotend/bed temps,
  fan speeds, active tool) WITHOUT performing any motion.
- When a motion command brings simulated Z >= target, the captured
  state is dumped into PrintJobRecovery::info (sd_filename, sdpos,
  current_position, feedrate, target_temperature[], fan_speed[],
  axis_relative, etc.) and recovery.resume() is invoked.
- recovery.resume() then performs the standard PLR sequence: heat,
  G28 XY, Z-lift, restore extruder/feedrate/leveling, and finally
  re-injects M23 <file>\nM24 S<sdpos> to continue the print.

New files
---------
- Marlin/src/feature/skip_to_z.{h,cpp} — scan engine and target_z
  global. The scan is line-buffered (128 B), parses parameters with
  a lightweight whitespace-aware letter scanner, and calls idle()
  every 100 ms to keep watchdog/thermals/UI alive on slow hardware.
- Marlin/src/gcode/feature/skipz/M1003.cpp — gcode entry point.

Modified files
--------------
- Configuration_adv.h: new option (disabled by default) with
  START_PRINT_FROM_Z_MAX and START_PRINT_FROM_Z_DEBUG.
- gcode.{h,cpp}: declare and dispatch M1003 (slot was free).
- sd/cardreader.cpp: openAndPrintFile() injects the alt sequence
  when SkipToZ::target_z > 0; one-shot (cleared after consumption).
- inc/SanityCheck.h: requires POWER_LOSS_RECOVERY and HAS_MEDIA.
- lcd/menu/menu_media.cpp: float52 EDIT_ITEM at the top of the
  file browser.
- lcd/language/language_en.h: MSG_START_PRINT_FROM_Z and
  MSG_SKIP_TO_Z_SCAN.

Verified
--------
mega2560 builds cleanly both with and without START_PRINT_FROM_Z.
Several upstream-suitable improvements to the START_PRINT_FROM_Z
feature added in the previous commit.

Self-contained resume (no PLR dependency)
-----------------------------------------
The original implementation used PrintJobRecovery::info as a transport
to invoke the standard PLR resume() path. This made the feature depend
on POWER_LOSS_RECOVERY at compile time and waste flash on AVR boards
that didn't otherwise need PLR.

skip_to_z.cpp now performs the resume itself by enqueueing a small
sequence of g-codes:
  M140 S<bed>     (bed heat, async)
  M104 T<n> S<t>  (hotend heat, async, per tool)
  M190 S<bed>     (wait for bed)
  T<active>       (switch to active tool)
  M109 T<n> S<t>  (wait for active hotend)
  G20/G21, G90, M82, G28 X Y
  G92 E<scanned>  (restore extruder counter)
  G1 Z<scanned> F300
  G91 / M83       (restore relative modes if needed)
  M106 P<i> S<v>  (restore fan speeds)
Then card.setIndex() + card.startOrResumeFilePrinting().

SanityCheck no longer requires POWER_LOSS_RECOVERY.
M1005.cpp drops the powerloss.h include and the recovery.resume() call.
The Configuration_adv.h block is moved out of the POWER_LOSS_RECOVERY
section to a sibling block under HAS_MEDIA, with the comment updated
to reflect the new self-contained design.

Smarter target detection: extrusion-aware Z-establishing line
-------------------------------------------------------------
A Bricked-vase print would previously trigger on any move that crossed
the target Z, including parking/purge moves like 'G1 Z15 F500' that
have no extrusion at the target height. The scanner now:
  * Tracks the most recent line that established the current Z
    (saving the pre-line state and the line's byte offset).
  * Triggers only when an extrusion move (E increasing) occurs while
    Z >= target.
  * Resumes from the Z-establishing line so the printer travels to
    (X,Y,Z) before any extrusion. The state used for the resume is
    the snapshot taken BEFORE the Z-establishing line ran, with z
    overwritten to the actual current Z.

Live progress reporting
-----------------------
Long files on slow MCUs can take many seconds to scan. New
report_progress() helper (throttled to ~1 s) updates:
  * LCD status line: 'Scan Z 1.2/12.0 56%'
  * Serial host log: 'SkipToZ: 56% z=1.2/12.0 sdpos=12345'

Per-file action submenu (LCD)
-----------------------------
Previously the EDIT_ITEM 'Print from Z...' was at the top of the file
selector and was a global value applied to whichever file you next
selected. Now selecting a file opens a small action submenu:
  Cancel
  Print from Z: <value>   (0 = normal print)
  Print
which makes the per-file intent explicit and keeps the file list
uncluttered. The new submenu function menu_sd_file_action() lives in
menu_media.cpp behind ENABLED(START_PRINT_FROM_Z).

current_edit_value() accessor (menu.h)
--------------------------------------
MenuEditItemBase exposes a new public static getter for the address
of the variable currently being edited. This lets context-sensitive
input handling decide what action to take based on the field on
screen. Default-disabled menus pay no cost; the accessor inlines.

RIGHT button loads current Z (ADC keypad)
-----------------------------------------
On RRW keypads (ZONESTAR_LCD etc.) RIGHT historically clears the
edit value to zero. While editing target_z and Z is homed, RIGHT
now loads the current Z position (scaled to float52). For all other
edit fields and unhomed Z, behavior is unchanged.

features.ini
------------
Adds a build_src_filter for START_PRINT_FROM_Z so the new sources
are only compiled into builds that enable the feature. This avoids
linking skip_to_z.cpp + M1005.cpp into firmware that doesn't use
the feature.

Verified
--------
mega2560 builds cleanly both with and without START_PRINT_FROM_Z
(Flash 62.2 KB without -> 82.6 KB with).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants