chiark / gitweb /
Keep updating the temperature even in paused state
[cura.git] / Cura / util / machineCom.py
index 5fe86611c4aacdfe77b14981a1b54bd74c74f0da..a0a763a782cab6224fe1a9e73395611bfc833b9a 100644 (file)
@@ -202,7 +202,9 @@ class MachineCom(object):
                self._heatupWaitStartTime = 0
                self._heatupWaitTimeLost = 0.0
                self._printStartTime100 = None
-               
+               self._currentCommands = []
+
+               self._thread_lock = threading.Lock()
                self.thread = threading.Thread(target=self._monitor)
                self.thread.daemon = True
                self.thread.start()
@@ -296,7 +298,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':
@@ -364,7 +378,7 @@ class MachineCom(object):
                        line = self._readline()
                        if line is None:
                                break
-                       
+
                        #No matter the state, if we see an fatal error, goto the error state and store the error for reference.
                        # Only goto error on known fatal errors.
                        if line.startswith('Error:'):
@@ -380,6 +394,7 @@ class MachineCom(object):
                                                self._errorValue = line[6:]
                                                self._changeState(self.STATE_ERROR)
                        if ' T:' in line or line.startswith('T:'):
+                               tempRequestTimeout = time.time() + 5
                                try:
                                        self._temp[self._temperatureRequestExtruder] = float(re.search("T: *([0-9\.]*)", line).group(1))
                                except:
@@ -453,7 +468,7 @@ class MachineCom(object):
                                else:
                                        self._testingBaudrate = False
                        elif self._state == self.STATE_CONNECTING:
-                               if line == '' or 'wait' in line:        # 'wait' needed for Repetier (kind of watchdog)
+                               if line == '' or 'wait' in line or 'start' in line:        # 'wait' needed for Repetier (kind of watchdog)
                                        self._sendCommand("M105")
                                elif 'ok' in line:
                                        self._changeState(self.STATE_OPERATIONAL)
@@ -468,6 +483,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:
@@ -481,17 +500,54 @@ 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:
-                                               self._gcodePos = int(line.replace("N:"," ").replace("N"," ").replace(":"," ").split()[-1])
+                                               newPos = int(line.replace("N:"," ").replace("N"," ").replace(":"," ").split()[-1])
                                        except:
                                                if "rs" in line:
-                                                       self._gcodePos = int(line.split()[1])
+                                                       newPos = int(line.split()[1])
+                                       # If we need to resend more than 10 lines, we can assume that the machine
+                                       # was shut down and turned back on or something else that's weird just happened.
+                                       # In that case, it can be dangerous to restart the print, so we'd better kill it
+                                       if newPos == 1 or self._gcodePos > newPos + 100:
+                                               self._callback.mcMessage("Print canceled due to loss of communication to printer (USB unplugged or power lost)")
+                                               self.cancelPrint()
+                                       else:
+                                               self._gcodePos = newPos
+                       elif self._state == self.STATE_PAUSED:
+                               #Even when printing request the temperature every 5 seconds.
+                               if time.time() > tempRequestTimeout:
+                                       if self._extruderCount > 0:
+                                               self._temperatureRequestExtruder = (self._temperatureRequestExtruder + 1) % self._extruderCount
+                                               self.sendCommand("M105 T%d" % (self._temperatureRequestExtruder))
+                                       else:
+                                               self.sendCommand("M105")
+                                       tempRequestTimeout = time.time() + 5
+                               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")
 
        def _setBaudrate(self, baudrate):
@@ -501,6 +557,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)
@@ -541,7 +598,9 @@ class MachineCom(object):
                self.close()
        
        def _sendCommand(self, cmd):
+               self._thread_lock.acquire(True)
                if self._serial is None:
+                       self._thread_lock.release()
                        return
                if 'M109' in cmd or 'M190' in cmd:
                        self._heatupWaitStartTime = time.time()
@@ -559,6 +618,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:
@@ -574,7 +635,8 @@ class MachineCom(object):
                        self._log("Unexpected error while writing serial port: %s" % (getExceptionString()))
                        self._errorValue = getExceptionString()
                        self.close(True)
-       
+               self._thread_lock.release()
+
        def _sendNext(self):
                if self._gcodePos >= len(self._gcodeList):
                        self._changeState(self.STATE_OPERATIONAL)
@@ -592,26 +654,29 @@ class MachineCom(object):
                        if self._printSection in self._feedRateModifier:
                                line = re.sub('F([0-9]*)', lambda m: 'F' + str(int(int(m.group(1)) * self._feedRateModifier[self._printSection])), line)
                        if ('G0' in line or 'G1' in line) and 'Z' in line:
-                               z = float(re.search('Z([0-9\.]*)', line).group(1))
+                               z = float(re.search('Z(-?[0-9\.]*)', line).group(1))
                                if self._currentZ != z:
                                        self._currentZ = z
                                        self._callback.mcZChange(z)
                except:
                        self._log("Unexpected error: %s" % (getExceptionString()))
                checksum = reduce(lambda x,y:x^y, map(ord, "N%d%s" % (self._gcodePos, line)))
-               self._sendCommand("N%d%s*%d" % (self._gcodePos, line, checksum))
+               pos = self._gcodePos
                self._gcodePos += 1
+               self._sendCommand("N%d%s*%d" % (pos, line, checksum))
                self._callback.mcProgress(self._gcodePos)
-       
+
        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
@@ -619,7 +684,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):
@@ -629,8 +694,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)