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()
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':
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:'):
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:
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)
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:
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):
print getExceptionString()
def _log(self, message):
+ #sys.stderr.write(message + "\n");
self._callback.mcLog(message)
try:
self._logQueue.put(message, False)
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()
except:
pass
self._log('Send: %s' % (cmd))
+ if self.isOperational():
+ self._currentCommands.append(cmd)
try:
self._serial.write(cmd + '\n')
except serial.SerialTimeoutException:
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)
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
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):
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)