diff options
Diffstat (limited to 'klippy/extras')
-rw-r--r-- | klippy/extras/sdcard_loop.py | 73 | ||||
-rw-r--r-- | klippy/extras/virtual_sdcard.py | 26 |
2 files changed, 96 insertions, 3 deletions
diff --git a/klippy/extras/sdcard_loop.py b/klippy/extras/sdcard_loop.py new file mode 100644 index 00000000..3cba979f --- /dev/null +++ b/klippy/extras/sdcard_loop.py @@ -0,0 +1,73 @@ +# Sdcard file looping support +# +# Copyright (C) 2021 Jason S. McMullan <jason.mcmullan@gmail.com> +# +# This file may be distributed under the terms of the GNU GPLv3 license. + +import logging + +class SDCardLoop: + def __init__(self, config): + printer = config.get_printer() + self.sdcard = printer.load_object(config, "virtual_sdcard") + self.gcode = printer.lookup_object('gcode') + self.gcode.register_command( + "SDCARD_LOOP_BEGIN", self.cmd_SDCARD_LOOP_BEGIN, + desc=self.cmd_SDCARD_LOOP_BEGIN_help) + self.gcode.register_command( + "SDCARD_LOOP_END", self.cmd_SDCARD_LOOP_END, + desc=self.cmd_SDCARD_LOOP_END_help) + self.gcode.register_command( + "SDCARD_LOOP_DESIST", self.cmd_SDCARD_LOOP_DESIST, + desc=self.cmd_SDCARD_LOOP_DESIST_help) + self.loop_stack = [] + cmd_SDCARD_LOOP_BEGIN_help = "Begins a looped section in the SD file." + def cmd_SDCARD_LOOP_BEGIN(self, gcmd): + count = gcmd.get_int("COUNT", minval=0) + if not self.loop_begin(count): + raise gcmd.error("Only permitted in SD file.") + cmd_SDCARD_LOOP_END_help = "Ends a looped section in the SD file." + def cmd_SDCARD_LOOP_END(self, gcmd): + if not self.loop_end(): + raise gcmd.error("Only permitted in SD file.") + cmd_SDCARD_LOOP_DESIST_help = "Stops iterating the current loop stack." + def cmd_SDCARD_LOOP_DESIST(self, gcmd): + if not self.loop_desist(): + raise gcmd.error("Only permitted outside of a SD file.") + def loop_begin(self, count): + if not self.sdcard.is_cmd_from_sd(): + # Can only run inside of an SD file + return False + self.loop_stack.append((count, self.sdcard.get_file_position())) + return True + def loop_end(self): + if not self.sdcard.is_cmd_from_sd(): + # Can only run inside of an SD file + return False + # If the stack is empty, no need to skip back + if len(self.loop_stack) == 0: + return True + # Get iteration count and return position + count, position = self.loop_stack.pop() + if count == 0: # Infinite loop + self.sdcard.set_file_position(position) + self.loop_stack.append((0, position)) + elif count == 1: # Last repeat + # Nothing to do + pass + else: + # At the next opportunity, seek back to the start of the loop + self.sdcard.set_file_position(position) + # Decrement the count by 1, and add the position back to the stack + self.loop_stack.append((count - 1, position)) + return True + def loop_desist(self): + if self.sdcard.is_cmd_from_sd(): + # Can only run outside of an SD file + return False + logging.info("Desisting existing SD loops") + self.loop_stack = [] + return True + +def load_config(config): + return SDCardLoop(config) diff --git a/klippy/extras/virtual_sdcard.py b/klippy/extras/virtual_sdcard.py index ccce3afe..66fc5ade 100644 --- a/klippy/extras/virtual_sdcard.py +++ b/klippy/extras/virtual_sdcard.py @@ -21,6 +21,7 @@ class VirtualSD: # Work timer self.reactor = printer.get_reactor() self.must_pause_work = self.cmd_from_sd = False + self.next_file_position = 0 self.work_timer = None # Register commands self.gcode = printer.lookup_object('gcode') @@ -124,7 +125,7 @@ class VirtualSD: if filename[0] == '/': filename = filename[1:] self._load_file(gcmd, filename, check_subdirs=True) - self.cmd_M24(gcmd) + self.do_resume() def cmd_M20(self, gcmd): # List SD card files = self.get_file_list() @@ -191,6 +192,12 @@ class VirtualSD: return gcmd.respond_raw("SD printing byte %d/%d" % (self.file_position, self.file_size)) + def get_file_position(self): + return self.next_file_position + def set_file_position(self, pos): + self.next_file_position = pos + def is_cmd_from_sd(self): + return self.cmd_from_sd # Background work timer def work_handler(self, eventtime): logging.info("Starting SD card print (position %d)", self.file_position) @@ -232,8 +239,11 @@ class VirtualSD: continue # Dispatch command self.cmd_from_sd = True + line = lines.pop() + next_file_position = self.file_position + len(line) + 1 + self.next_file_position = next_file_position try: - self.gcode.run_script(lines[-1]) + self.gcode.run_script(line) except self.gcode.error as e: self.print_stats.note_error(str(e)) break @@ -241,7 +251,17 @@ class VirtualSD: logging.exception("virtual_sdcard dispatch") break self.cmd_from_sd = False - self.file_position += len(lines.pop()) + 1 + self.file_position = self.next_file_position + # Do we need to skip around? + if self.next_file_position != next_file_position: + try: + self.current_file.seek(self.file_position) + except: + logging.exception("virtual_sdcard seek") + self.work_timer = None + return self.reactor.NEVER + lines = [] + partial_input = "" logging.info("Exiting SD card print (position %d)", self.file_position) self.work_timer = None self.cmd_from_sd = False |