aboutsummaryrefslogtreecommitdiffstats
path: root/klippy/extras
diff options
context:
space:
mode:
Diffstat (limited to 'klippy/extras')
-rw-r--r--klippy/extras/sdcard_loop.py73
-rw-r--r--klippy/extras/virtual_sdcard.py26
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