diff --git a/docs/configuration/config_yaml.rst b/docs/configuration/config_yaml.rst index c8640400..c5dc8ab8 100644 --- a/docs/configuration/config_yaml.rst +++ b/docs/configuration/config_yaml.rst @@ -319,9 +319,11 @@ The following settings are only relevant to you if you want to do OctoPrint deve # Forced pause for retrieving from the outgoing buffer throttle: 0.01 - # Whether to send "wait" responses while waiting for long moves to finish - # or not - waitOnLongMoves: false + # Whether to send "wait" responses every "waitInterval" seconds when serial rx buffer is empty + sendWait: false + + # Interval in which to send "wait" lines when rx buffer is empty + waitInterval: 1 # Size of the simulated RX buffer in bytes, when it's full a send from OctoPrint's # side will block diff --git a/src/octoprint/plugins/virtual_printer/virtual.py b/src/octoprint/plugins/virtual_printer/virtual.py index c41e527c..59afe659 100644 --- a/src/octoprint/plugins/virtual_printer/virtual.py +++ b/src/octoprint/plugins/virtual_printer/virtual.py @@ -63,6 +63,9 @@ class VirtualPrinter(): self._okBeforeCommandOutput = settings().getBoolean(["devel", "virtualPrinter", "okBeforeCommandOutput"]) + self._sendWait = settings().getBoolean(["devel", "virtualPrinter", "sendWait"]) + self._waitInterval = settings().getFloat(["devel", "virtualPrinter", "waitInterval"]) + self.currentLine = 0 self.lastN = 0 @@ -99,14 +102,20 @@ class VirtualPrinter(): pass def _processIncoming(self): + next_wait_timeout = time.time() + self._waitInterval while self.incoming is not None: self._simulateTemps() try: data = self.incoming.get(timeout=0.01) except Queue.Empty: + if self._sendWait and time.time() > next_wait_timeout: + self.outgoing.put("wait") + next_wait_timeout = time.time() + self._waitInterval continue + next_wait_timeout = time.time() + self._waitInterval + if data is None: continue @@ -137,7 +146,7 @@ class VirtualPrinter(): if linenumber != expected: self._triggerResend(actual=linenumber) continue - elif self.currentLine == 100: + elif self.currentLine == 101: # simulate a resend at line 100 self._triggerResend(expected=100) continue diff --git a/src/octoprint/settings.py b/src/octoprint/settings.py index 2ad8969c..f0506eb6 100644 --- a/src/octoprint/settings.py +++ b/src/octoprint/settings.py @@ -139,6 +139,7 @@ default_settings = { "swallowOkAfterResend": True, "repetierTargetTemp": False, "externalHeatupDetection": True, + "supportWait": True, "keyboardControl": True }, "folder": { @@ -266,7 +267,9 @@ default_settings = { "waitOnLongMoves": False, "rxBuffer": 64, "txBuffer": 40, - "commandBuffer": 4 + "commandBuffer": 4, + "sendWait": True, + "waitInterval": 1.0 } } } diff --git a/src/octoprint/util/comm.py b/src/octoprint/util/comm.py index f4b79703..b30796ee 100644 --- a/src/octoprint/util/comm.py +++ b/src/octoprint/util/comm.py @@ -797,6 +797,7 @@ class MachineCom(object): startSeen = False supportRepetierTargetTemp = settings().getBoolean(["feature", "repetierTargetTemp"]) + supportWait = settings().getBoolean(["feature", "supportWait"]) connection_timeout = settings().getFloat(["serial", "timeout", "connection"]) detection_timeout = settings().getFloat(["serial", "timeout", "detection"]) @@ -868,7 +869,7 @@ class MachineCom(object): continue ##~~ process oks - if line.strip().startswith("ok"): + if line.strip().startswith("ok") or (supportWait and line.strip().startswith("wait")): self._clear_to_send.set() self._blocking_command = False @@ -1082,7 +1083,9 @@ class MachineCom(object): else: self._logger.debug("Ran into a communication timeout, but a blocking command is currently active") - if "ok" in line: + if "ok" in line or (supportWait and "wait" in line): + # a wait while printing means our printer's buffer ran out, probably due to some ok getting + # swallowed, so we treat it the same as an ok here teo take up communication again if self._resendSwallowNextOk: self._resendSwallowNextOk = False @@ -1530,7 +1533,7 @@ class MachineCom(object): else: self._doSendWithoutChecksum(command) - use_up_clear = not self._unknownCommandsNeedAck + use_up_clear = self._unknownCommandsNeedAck if is_gcode: # trigger "sent" phase and use up one "ok" self._process_command_phase("sent", command, gcode=gcode_match.group(1))