New gcode to interrupt the pending command queue

I want to add something that would interrupt the current command and clear the pending command queue. The approach I’m looking at is a CANCEL_COMMANDS custom gcode command that behaves similarly to M112, such that it would get matched and have its handler called directly inside GCodeIO._process_data(). However, instead of shutting down the printer you’d have the following steps:

  1. Suspend input processing.
  2. Set a flag on Printer that indicates it’s in a cancel state.
  3. Clear the command queue.
  4. Wait for active commands to bail out (anything that currently checks Printer.is_shutdown() would be updated to handle this).
  5. Unset the cancel flag on Printer
  6. Have some way for modules to register for post-cancellation (e.g. getting a CANCEL_PRINT at the front of the new queue if a print was active, although maybe that’s the only one).
  7. Unsuspend the input processing and begin processing commands normally again.

A typical use-case for this would be to break out of a potentially long macro (e.g. START_PRINT) or blocking command (e.g. M190).

Given the frequency with which people have asked for a way to interrupt long-running commands I think this safely crosses the 100 user threshold, but I figured I’d ask, and see what people think about the approach.

I would love this. I frequently use the emergency shutdown but have never had an actual emergency. It’s just the only way to make the printer stop what it’s doing NOW. It would be great to have something like an interrupting cancel_print that instantly takes effect no matter what the printer is doing.

What would be the advantage of using a new command as opposed to using the existing M112?

For what it is worth, I’ve looked at similar support in the past and I found it was very difficult to reliably produce behavior that is robust and understandable.

Cheers,
-Kevin

M112 requires a firmware restart afterwards. Motor positions and unsaved config changes are lost, and it’s essentially impossible to recover the print.

If the g-code command queue is pre-empted it is still very difficult to “resume”. Some, none, or all of that command queue may have been executed (including out of order and including partial execution of commands). Even internally it would be difficult to reconstruct the state. The user would have no way of resuming at any particular point in a g-code file, as the halt will not have occurred at any discrete point.

-Kevin

In case anyone is curious - my last attempt at this was about a year ago: GitHub - KevinOConnor/klipper-dev at work-cancel-20220322 . With some commentary at: klippy: add `klippy:interrupt` used by `pause_resume/cancel` by ayufan · Pull Request #4398 · Klipper3d/klipper · GitHub .

I abandoned the work as I concluded it was not workable.

Cheers,
-Kevin

Thanks, I’ll look at these past attempts. Before posting I made a very hacky version just to test the idea that successfully breaks out of heater waits and macro processing. So, maybe my initial post was scoped more broadly than necessary.

As to the question of “why”, for me it’s not really about recovering prints in progress (I can think of only one case where that would have been possible, and it was during a filament change).

The most common scenario is when I realize during the START_PRINT macro that I made a mistake and have to abort the print. If I use M112 I have to babysit the printer while I perform a number of manual steps. This is particularly annoying if everything is already at temperature and I forget to set something back, thus having to wait for things to heat back up again when I retry.

The other big one is just that it would be nice to just not have to shutdown and restart the printer when I set the wrong temperature value.

I appreciate that neither of these cases is a huge pain, but it is pretty jarring when you just want to abort a long-running operation in progress and have to first manually perform a firmware restart and then wait for Mainsail and the Web UI to reload and become responsive again before you can do something.

power loss monitoring could benefit from such a command too.
such as interrupting the print and executing a macro to save gcode position and raise Z on UPS power.

I’ve too wondered about working to implement something along these lines, at the user level. I feel that there are valid use cases, as you’ve enumerated.

To speak to the need to reheat after a restart, I do make use of the save_variable module, and wrapping the heater gcodes/set_heater commands to store latest settings, for reinstantiation at klipper restart. I’ve threaded in logic to enable this behavior by rename_existing restart such that a normal power outage/etc. Will not enable this behavior.

Your posits about losing gantry level, homed state, etc. are all valid and something that would be useful to a larger portion of the power users of klipper, I perceive.

I once mucked with wrapping M112 via rename existing, so I could go interactive with the user (via my user_interaction macros) but I saw something bright and shiney and it fell to the side for revisiting in the future.

That time is now, as I am currently in the klipper macro groove mode.

Well, now-ish … after I finish a set of macros that will dwell on print start, until system load drops below 1.0 - telegram bot post-print video encoding, after a long print concludes, slams the host (system load values > 6), sometimes for many minutes encoding a time-lapse video - I’m putting code in place to gracefully deal with dwelling/annunciation of this context, giving the user the option to cancel, wait, or forcibly override the dwelling to carry-on in spite of the host being task saturated (at the risk of print failure due to timer too close, etc.).

If I conjure up something that looks to have potential, I’ll draw attention to same herein.

~MHz

Can you share your code for a modified M112?