diff --git a/printrun/gcoder.py b/printrun/gcoder.py index ef5fd0a83..1a3fdaff5 100755 --- a/printrun/gcoder.py +++ b/printrun/gcoder.py @@ -240,6 +240,8 @@ def prepare(self, data = None, home_pos = None, layer_callback = None): self.layer_idxs = array('I', []) self.line_idxs = array('I', []) + def has_index(self, i): + return i < len(self) def __len__(self): return len(self.line_idxs) diff --git a/printrun/printcore.py b/printrun/printcore.py index beb9102d3..a4a545ac8 100644 --- a/printrun/printcore.py +++ b/printrun/printcore.py @@ -586,7 +586,7 @@ def _sendnext(self): self._send(self.priqueue.get_nowait()) self.priqueue.task_done() return - if self.printing and self.queueindex < len(self.mainqueue): + if self.printing and self.mainqueue.has_index(self.queueindex): (layer, line) = self.mainqueue.idxs(self.queueindex) gline = self.mainqueue.all_layers[layer][line] if self.queueindex > 0: @@ -604,7 +604,7 @@ def _sendnext(self): try: handler.on_preprintsend(gline, self.queueindex, self.mainqueue) except: logging.error(traceback.format_exc()) if self.preprintsendcb: - if self.queueindex + 1 < len(self.mainqueue): + if self.mainqueue.has_index(self.queueindex + 1): (next_layer, next_line) = self.mainqueue.idxs(self.queueindex + 1) next_gline = self.mainqueue.all_layers[next_layer][next_line] else: diff --git a/printrun/pronsole.py b/printrun/pronsole.py index 9aecc277f..60218b390 100644 --- a/printrun/pronsole.py +++ b/printrun/pronsole.py @@ -104,6 +104,37 @@ def bed_enabled(self): def extruder_enabled(self): return self.extruder_temp != 0 +class RGSGCoder(): + """Bare alternative to gcoder.LightGCode which does not preload all lines in memory, +but still allows run_gcode_script (hence the RGS) to be processed by do_print (checksum,threading,ok waiting)""" + def __init__(self, line): + self.lines = True + self.filament_length = 0. + self.filament_length_multi = [0] + self.proc = run_command(line, {"$s": 'str(self.filename)'}, stdout = subprocess.PIPE, universal_newlines = True) + lr = gcoder.Layer([]) + lr.duration = 0. + self.all_layers = [lr] + self.read() #empty layer causes division by zero during progress calculation + def read(self): + ln = self.proc.stdout.readline() + if not ln: + self.proc.stdout.close() + return None + ln = ln.strip() + if not ln: + return None + pyLn = gcoder.PyLightLine(ln) + self.all_layers[0].append(pyLn) + return pyLn + def has_index(self, i): + while i >= len(self.all_layers[0]) and not self.proc.stdout.closed: + self.read() + return i < len(self.all_layers[0]) + def __len__(self): + return len(self.all_layers[0]) + def idxs(self, i): + return 0, i #layer, line class pronsole(cmd.Cmd): def __init__(self): @@ -1755,9 +1786,11 @@ def help_run_script(self): self.log(_("Runs a custom script. Current gcode filename can be given using $s token.")) def do_run_gcode_script(self, l): - p = run_command(l, {"$s": str(self.filename)}, stdout = subprocess.PIPE, universal_newlines = True) - for line in p.stdout.readlines(): - self.onecmd(line.strip()) + try: + self.fgcode = RGSGCoder(l) + self.do_print(None) + except BaseException as e: + self.logError(traceback.format_exc()) def help_run_gcode_script(self): self.log(_("Runs a custom script which output gcode which will in turn be executed. Current gcode filename can be given using $s token.")) diff --git a/testtools/lengthy.py b/testtools/lengthy.py new file mode 100755 index 000000000..c50bdb2af --- /dev/null +++ b/testtools/lengthy.py @@ -0,0 +1,9 @@ +#!/usr/bin/python3 +#generate many g1 to test serial buffer overflow in run_gcode_script + +print('G28 X') +print('G1 X0') +for x in range(100): + print() + print(' ') + print('G1 X', x)