From d0afa7eabc210a8d6a1c4bcf62b74ec74b63a846 Mon Sep 17 00:00:00 2001 From: Brandon Nance Date: Fri, 10 Nov 2023 21:08:52 -0500 Subject: [PATCH] HEATER_INTERRUPT command and INTERRUPT mutex fix refactor with wait_while util cancel print too back to interrupt command fix gcode ref readme stuff --- README.md | 2 ++ docs/G-Codes.md | 3 +++ klippy/extras/heaters.py | 38 ++++++++++++++++++-------------------- klippy/gcode.py | 16 +++++++++++++++- klippy/klippy.py | 14 ++++++++++++++ 5 files changed, 52 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index 80dcf628e..a0c6b6349 100644 --- a/README.md +++ b/README.md @@ -38,6 +38,8 @@ If I want my printer to light itself on fire, I should be able to make my printe - [gcode: expose math functions to gcode macros](https://github.com/DangerKlippers/danger-klipper/pull/173) ([klipper#4072](https://github.com/Klipper3d/klipper/pull/4072)) +- [gcode: HEATER_INTERRUPT gcode command](https://github.com/DangerKlippers/danger-klipper/pull/94) + - [probe: dockable Probe](https://github.com/DangerKlippers/danger-klipper/pull/43) ([klipper#4328](https://github.com/Klipper3d/klipper/pull/4328)) - [probe: drop the first result](https://github.com/DangerKlippers/danger-klipper/pull/2) ([klipper#3397](https://github.com/Klipper3d/klipper/issues/3397)) diff --git a/docs/G-Codes.md b/docs/G-Codes.md index fb6fd094b..94091aaa1 100644 --- a/docs/G-Codes.md +++ b/docs/G-Codes.md @@ -692,6 +692,9 @@ software (see `FIRMWARE_RESTART`: This is similar to a RESTART command, but it also clears any error state from the micro-controller. +#### HEATER_INTERRUPT +`HEATER_INTERRUPT`: Interrupts a TEMPERATURE_WAIT command. + #### STATUS `STATUS`: Report the Klipper host software status. diff --git a/klippy/extras/heaters.py b/klippy/extras/heaters.py index 3d07eea3f..6e59253f9 100644 --- a/klippy/extras/heaters.py +++ b/klippy/extras/heaters.py @@ -843,14 +843,14 @@ def __init__(self, config): "gcode:request_restart", self.turn_off_all_heaters ) # Register commands - gcode = self.printer.lookup_object("gcode") - gcode.register_command( + self.gcode = self.printer.lookup_object("gcode") + self.gcode.register_command( "TURN_OFF_HEATERS", self.cmd_TURN_OFF_HEATERS, desc=self.cmd_TURN_OFF_HEATERS_help, ) - gcode.register_command("M105", self.cmd_M105, when_not_ready=True) - gcode.register_command( + self.gcode.register_command("M105", self.cmd_M105, when_not_ready=True) + self.gcode.register_command( "TEMPERATURE_WAIT", self.cmd_TEMPERATURE_WAIT, desc=self.cmd_TEMPERATURE_WAIT_help, @@ -960,16 +960,15 @@ def cmd_M105(self, gcmd): def _wait_for_temperature(self, heater): # Helper to wait on heater.check_busy() and report M105 temperatures + if self.printer.get_start_args().get("debugoutput") is not None: return - toolhead = self.printer.lookup_object("toolhead") - gcode = self.printer.lookup_object("gcode") - reactor = self.printer.get_reactor() - eventtime = reactor.monotonic() - while not self.printer.is_shutdown() and heater.check_busy(eventtime): - print_time = toolhead.get_last_move_time() - gcode.respond_raw(self._get_temp(eventtime)) - eventtime = reactor.pause(eventtime + 1.0) + + def check(eventtime): + self.gcode.respond_raw(self._get_temp(eventtime)) + return heater.check_busy(eventtime) + + self.printer.wait_while(check) def set_temperature(self, heater, temp, wait=False): toolhead = self.printer.lookup_object("toolhead") @@ -996,16 +995,15 @@ def cmd_TEMPERATURE_WAIT(self, gcmd): sensor = self.heaters[sensor_name] else: sensor = self.printer.lookup_object(sensor_name) - toolhead = self.printer.lookup_object("toolhead") - reactor = self.printer.get_reactor() - eventtime = reactor.monotonic() - while not self.printer.is_shutdown(): - temp, target = sensor.get_temp(eventtime) + + def check(eventtime): + temp, _ = sensor.get_temp(eventtime) if temp >= min_temp and temp <= max_temp: - return - print_time = toolhead.get_last_move_time() + return False gcmd.respond_raw(self._get_temp(eventtime)) - eventtime = reactor.pause(eventtime + 1.0) + return True + + self.printer.wait_while(check) def load_config(config): diff --git a/klippy/gcode.py b/klippy/gcode.py index e326cec94..18fe7039b 100644 --- a/klippy/gcode.py +++ b/klippy/gcode.py @@ -154,6 +154,7 @@ def __init__(self, printer): self.mux_commands = {} self.gcode_help = {} self.status_commands = {} + self._interrupt_counter = 0 # Register commands needed before config file is loaded handlers = [ "M110", @@ -164,12 +165,19 @@ def __init__(self, printer): "ECHO", "STATUS", "HELP", + "HEATER_INTERRUPT", ] for cmd in handlers: func = getattr(self, "cmd_" + cmd) desc = getattr(self, "cmd_" + cmd + "_help", None) self.register_command(cmd, func, True, desc) + def get_interrupt_counter(self): + return self._interrupt_counter + + def increment_interrupt_counter(self): + self._interrupt_counter += 1 + def is_traditional_gcode(self, cmd): # A "traditional" g-code command is a letter and followed by a number try: @@ -306,8 +314,11 @@ def run_script_from_command(self, script): self._process_commands(script.split("\n"), need_ack=False) def run_script(self, script): - with self.mutex: + if "INTERRUPT" in script or "CANCEL_PRINT" in script: self._process_commands(script.split("\n"), need_ack=False) + else: + with self.mutex: + self._process_commands(script.split("\n"), need_ack=False) def get_mutex(self): return self.mutex @@ -475,6 +486,9 @@ def cmd_HELP(self, gcmd): cmdhelp.append("%-10s: %s" % (cmd, self.gcode_help[cmd])) gcmd.respond_info("\n".join(cmdhelp), log=False) + def cmd_HEATER_INTERRUPT(self, gcmd): + self.increment_interrupt_counter() + # Support reading gcode from a pseudo-tty interface class GCodeIO: diff --git a/klippy/klippy.py b/klippy/klippy.py index 73d2a7ab9..9bba5066e 100644 --- a/klippy/klippy.py +++ b/klippy/klippy.py @@ -376,6 +376,20 @@ def request_exit(self, result): self.run_result = result self.reactor.end() + def wait_while(self, condition_cb): + """ + receives a callback + waits until callback returns False + (or is interrupted, or printer shuts down) + """ + gcode = self.lookup_object("gcode") + counter = gcode.get_interrupt_counter() + eventtime = self.reactor.monotonic() + while condition_cb(eventtime): + if self.is_shutdown() or counter != gcode.get_interrupt_counter(): + return + eventtime = self.reactor.pause(eventtime + 1.0) + ###################################################################### # Startup