From 6bfa9ac4f50cde9d9ae7c217bef2a3161140735f Mon Sep 17 00:00:00 2001 From: Youness Alaoui Date: Tue, 8 Dec 2015 13:34:08 -0500 Subject: [PATCH] Keep track of which commands are in the command queue of Marlin This allows us to have better control on our timeouts and to know when we can send a command or when we should just buffer it instead. This can help us avoid having issues such as buffer overruns or write timeout for windows. Hopefully fixes T332 --- Cura/util/machineCom.py | 51 ++++++++++++++++--- .../printerConnection/serialConnection.py | 2 +- 2 files changed, 46 insertions(+), 7 deletions(-) diff --git a/Cura/util/machineCom.py b/Cura/util/machineCom.py index 0627af82..e6ce8c11 100644 --- a/Cura/util/machineCom.py +++ b/Cura/util/machineCom.py @@ -202,6 +202,7 @@ class MachineCom(object): self._heatupWaitStartTime = 0 self._heatupWaitTimeLost = 0.0 self._printStartTime100 = None + self._currentCommands = [] self.thread = threading.Thread(target=self._monitor) self.thread.daemon = True @@ -296,7 +297,19 @@ class MachineCom(object): for line in ret: self._logQueue.put(line, False) return ret - + + def receivedOK(self): + if len(self._currentCommands) > 0: + # Marlin will answer 'ok' immediatly to G[0-3] commands + for i in xrange(0, len(self._currentCommands)): + if "G0 " in self._currentCommands[i] or \ + "G1 " in self._currentCommands[i] or \ + "G2 " in self._currentCommands[i] or \ + "G3 " in self._currentCommands[i]: + self._currentCommands.pop(i) + return + self._currentCommands.pop(0) + def _monitor(self): #Open the serial port. if self._port == 'AUTO': @@ -469,6 +482,10 @@ class MachineCom(object): else: self.sendCommand("M105") tempRequestTimeout = time.time() + 5 + elif 'ok' in line: + self.receivedOK() + elif 'start' in line: + self._currentCommands = [] elif self._state == self.STATE_PRINTING: #Even when printing request the temperature every 5 seconds. if time.time() > tempRequestTimeout: @@ -482,11 +499,20 @@ class MachineCom(object): self._log("Communication timeout during printing, forcing a line") line = 'ok' if 'ok' in line: + self.receivedOK() timeout = time.time() + 5 if not self._commandQueue.empty(): self._sendCommand(self._commandQueue.get()) else: self._sendNext() + if "G28" in self._currentCommands[0] or "G29" in self._currentCommands[0] or \ + "M109" in self._currentCommands[0] or "M190" in self._currentCommands[0]: + # Long command detected. Timeout is now set to 60s to avoid forcing 'ok' + # every 5 seconds while it's not needed + timeout = time.time() + 60 + + elif 'start' in line: + self._currentCommands = [] elif "resend" in line.lower() or "rs" in line: newPos = self._gcodePos try: @@ -503,10 +529,15 @@ class MachineCom(object): else: self._gcodePos = newPos elif self._state == self.STATE_PAUSED: + if line == '' and time.time() > timeout: + line = 'ok' if 'ok' in line: + self.receivedOK() timeout = time.time() + 5 if not self._commandQueue.empty(): self._sendCommand(self._commandQueue.get()) + elif 'start' in line: + self._currentCommands = [] self._log("Connection closed, closing down monitor") @@ -517,6 +548,7 @@ class MachineCom(object): print getExceptionString() def _log(self, message): + #sys.stderr.write(message + "\n"); self._callback.mcLog(message) try: self._logQueue.put(message, False) @@ -575,6 +607,8 @@ class MachineCom(object): except: pass self._log('Send: %s' % (cmd)) + if self.isOperational(): + self._currentCommands.append(cmd) try: self._serial.write(cmd + '\n') except serial.SerialTimeoutException: @@ -622,13 +656,15 @@ class MachineCom(object): def sendCommand(self, cmd): cmd = cmd.encode('ascii', 'replace') - if self.isPrinting(): + if self.isPrinting() or self.isPaused(): self._commandQueue.put(cmd) + if len(self._currentCommands) == 0: + self._sendCommand(self._commandQueue.get()) elif self.isOperational(): self._sendCommand(cmd) def printGCode(self, gcodeList): - if not self.isOperational() or self.isPrinting(): + if not self.isOperational() or self.isPrinting() or self.isPaused(): return self._gcodeList = gcodeList self._gcodePos = 0 @@ -636,7 +672,7 @@ class MachineCom(object): self._printSection = 'CUSTOM' self._changeState(self.STATE_PRINTING) self._printStartTime = time.time() - for i in xrange(0, 2): + for i in xrange(0, 4): self._sendNext() def cancelPrint(self): @@ -646,8 +682,11 @@ class MachineCom(object): def setPause(self, pause): if not pause and self.isPaused(): self._changeState(self.STATE_PRINTING) - for i in xrange(0, 2): - self._sendNext() + for i in xrange(0, 4): + if not self._commandQueue.empty(): + self._sendCommand(self._commandQueue.get()) + else: + self._sendNext() if pause and self.isPrinting(): self._changeState(self.STATE_PAUSED) diff --git a/Cura/util/printerConnection/serialConnection.py b/Cura/util/printerConnection/serialConnection.py index c038cc36..40a87e70 100644 --- a/Cura/util/printerConnection/serialConnection.py +++ b/Cura/util/printerConnection/serialConnection.py @@ -148,6 +148,7 @@ class serialConnection(printerConnectionBase.printerConnectionBase): retract_amount = 5.0 moveZ = 10.0 + self._process.stdin.write("PAUSE\n") if self._printProgress - 5 > start_gcode_lines: # Substract 5 because of the marlin queue x = None y = None @@ -196,7 +197,6 @@ class serialConnection(printerConnectionBase.printerConnectionBase): self.sendCommand("M82") self._pausePosition = (x, y, self._ZPosition, f, e) - self._process.stdin.write("PAUSE\n") else: if self._pausePosition: retract_amount = profile.getProfileSettingFloat('retraction_amount') -- 2.30.2