def _openSerial(self): if self._port == 'AUTO': self._changeState(self.STATE_DETECT_SERIAL) programmer = stk500v2.Stk500v2() self._log("Serial port list: %s" % (str(serialList()))) for p in serialList(): try: self._log("Connecting to: %s" % (p)) programmer.connect(p) self._serial = programmer.leaveISP() break except ispBase.IspError as (e): self._log("Error while connecting to %s: %s" % (p, str(e))) pass except: self._log( "Unexpected error while connecting to serial port: %s %s" % (p, getExceptionString())) programmer.close() if self._serial is None: self._log("Failed to autodetect serial port") self._errorValue = 'Failed to autodetect serial port.' self._changeState(self.STATE_ERROR) eventManager().fire("Error", self.getErrorString()) return False elif self._port == 'VIRTUAL': self._changeState(self.STATE_OPEN_SERIAL) self._serial = VirtualPrinter() else: self._changeState(self.STATE_OPEN_SERIAL) try: self._log("Connecting to: %s" % self._port) if self._baudrate == 0: self._serial = serial.Serial(str(self._port), 115200, timeout=0.1, writeTimeout=10000) else: self._serial = serial.Serial(str(self._port), self._baudrate, timeout=settings().getFloat([ "serial", "timeout", "connection" ]), writeTimeout=10000) except: self._log( "Unexpected error while connecting to serial port: %s %s" % (self._port, getExceptionString())) self._errorValue = "Failed to open serial port, permissions correct?" self._changeState(self.STATE_ERROR) eventManager().fire("Error", self.getErrorString()) return False return True
def _readline(self): if self._serial == None: return None try: ret = self._serial.readline() except: self._log("Unexpected error while reading serial port: %s" % (getExceptionString())) self._errorValue = getExceptionString() self.close(True) return None if ret == '': #self._log("Recv: TIMEOUT") return '' self._log("Recv: %s" % sanitizeAscii(ret)) return ret
def _readline(self): if self._serial == None: return None try: ret = self._serial.readline() except: self._log("Unexpected error while reading serial port: %s" % (getExceptionString())) self._errorValue = getExceptionString() self.close(True) return None if ret == '': #self._log("Recv: TIMEOUT") return '' self._log("Recv: %s" % (unicode(ret, 'ascii', 'replace').encode('ascii', 'replace').rstrip())) return ret
def startPrint(self): if not self.isOperational() or self.isPrinting(): return if self._currentFile is None: raise ValueError("No file selected for printing") try: self._currentFile.start() self._lastLayerHeight = 0.0; self._currentLayer = 0; #self._currentLayer = 1; #sefl._lastLayerHeight; #self._callback.mcLayerChange(self._tentativeLayer) wasPaused = self.isPaused() self._changeState(self.STATE_PRINTING) eventManager().fire(Events.PRINT_STARTED, { "file": self._currentFile.getFilename(), "filename": os.path.basename(self._currentFile.getFilename()), "origin": self._currentFile.getFileLocation() }) if self.isSdFileSelected(): if wasPaused: self.sendCommand("M26 S0") self._currentFile.setFilepos(0) self.sendCommand("M24") else: self._sendNext() except: self._errorValue = getExceptionString() self._changeState(self.STATE_ERROR) eventManager().fire(Events.ERROR, {"error": self.getErrorString()})
def startPrint(self): if not self.isOperational() or self.isPrinting(): return if self._currentFile is None: raise ValueError("No file selected for printing") try: self._currentFile.start() wasPaused = self.isPaused() self._changeState(self.STATE_PRINTING) eventManager().fire(Events.PRINT_STARTED, { "file": self._currentFile.getFilename(), "filename": os.path.basename(self._currentFile.getFilename()), "origin": self._currentFile.getFileLocation() }) if self.isSdFileSelected(): if wasPaused: self.sendCommand("M26 S0") self._currentFile.setFilepos(0) self.sendCommand("M24") else: self._sendNext() except: self._errorValue = getExceptionString() self._changeState(self.STATE_ERROR) eventManager().fire(Events.ERROR, {"error": self.getErrorString()})
def startPrint(self): if not self.isOperational() or self.isPrinting(): return if self._currentFile is None: raise ValueError("No file selected for printing") wasPaused = self.isPaused() try: self._currentFile.start() self._changeState(self.STATE_PRINTING) eventManager().fire("PrintStarted", self._currentFile.getFilename()) if self.isSdFileSelected(): if wasPaused: self.sendCommand("M26 S0") self._currentFile.setFilepos(0) self.sendCommand("M24") else: self._sendNext() except: self._errorValue = getExceptionString() self._changeState(self.STATE_ERROR) eventManager().fire("Error", self.getErrorString())
def startPrint(self): if not self.isOperational() or self.isPrinting(): return if self._currentFile is None: raise ValueError("No file selected for printing") self._heatupWaitStartTime = 0 self._heatupWaitTimeLost = 0.0 self._pauseWaitStartTime = 0 self._pauseWaitTimeLost = 0.0 try: self._currentFile.start() wasPaused = self.isPaused() self._changeState(self.STATE_PRINTING) eventManager().fire(Events.PRINT_STARTED, { "file": self._currentFile.getFilename(), "filename": os.path.basename(self._currentFile.getFilename()), "origin": self._currentFile.getFileLocation() }) if self.isSdFileSelected(): if wasPaused: self.sendCommand("M26 S0") self._currentFile.setFilepos(0) self.sendCommand("M24") else: self._sendNext() except: self._logger.exception("Error while trying to start printing") self._errorValue = getExceptionString() self._changeState(self.STATE_ERROR) eventManager().fire(Events.ERROR, {"error": self.getErrorString()})
def _connect(self): self.changeState(State.OPENING_CONNECTION) if self._port == "VIRTUAL": self._serial = VirtualPrinter(read_timeout=self._readTimeout, write_timeout=self._writeTimeout) self.changeState(State.CONNECTED) self._transport_logger.debug("Connected to %s" % self._serial) else: try: self._serial = serial.Serial(self._port, self._baudrate, timeout=self._readTimeout, writeTimeout=self._writeTimeout) self.changeState(State.CONNECTED) self._transport_logger.debug("Connected to %s" % self._serial) except: self.logError( "Unexpected error while connecting to serial port: %s %s" % (self._port, getExceptionString())) self.onError( "Failed to open serial port, permissions correct?") return False eventManager().fire(Events.CONNECTED, { "port": self._port, "baudrate": self._baudrate }) return True
def _doSend(self, cmd): #make sure sends are done orderly with self._sendingLock: self._serialLoggerEnabled and self._log("Send: %s" % cmd) retriesLeft = 5 while True: try: self._serial.write(cmd + '\n') break except serial.SerialTimeoutException: retriesLeft -= 1 if retriesLeft == 0: self._serialLoggerEnabled and self._log("No more retries left. Closing the connection") self._errorValue = "Unable to send data" self.close(True) break else: self._serialLoggerEnabled and self._log("Serial Timeout while sending data. Retries left: %d" % retriesLeft) time.sleep(0.5) except: self._serialLoggerEnabled and self._log("Unexpected error while writing serial port: %s" % (getExceptionString())) self._errorValue = getExceptionString() self.close(True) break
def _doSendWithoutChecksum(self, cmd): self._log("Send: %s" % cmd) try: self._serial.write(cmd + '\n') except serial.SerialTimeoutException: self._log("Serial timeout while writing to serial port, trying again.") try: self._serial.write(cmd + '\n') except: self._log("Unexpected error while writing serial port: %s" % (getExceptionString())) self._errorValue = getExceptionString() self.close(True) except: self._log("Unexpected error while writing serial port: %s" % (getExceptionString())) self._errorValue = getExceptionString() self.close(True)
def write(self, value): if self._socketWrite is not None: #self._logger.info("PipeReadWrite write:%s" % value) with self._stateMutex : try: self._socketWrite.send(value) #self._socketWrite.flush() except: exceptionString = getExceptionString() self._logger.error("Unexpected error while writing pipe port: %s" % exceptionString)
def write(self, value): if self._socketWrite is not None: #self._logger.info("PipeReadWrite write:%s" % value) with self._stateMutex: try: self._socketWrite.send(value) #self._socketWrite.flush() except: exceptionString = getExceptionString() self._logger.error( "Unexpected error while writing pipe port: %s" % exceptionString)
def send(self, command): commandToSend = command + "\n" try: self._pipe.write(commandToSend) self._transport_logger.info("Send: %s" % command) self.logTx(command) #lkj except serial.SerialTimeoutException: # self._transport_logger.warn("Timeout while sending: %s" % command) # self.logError("Pipe timeout while writing to pipe port, try again later.") # raise SendTimeout() except: exceptionString = getExceptionString() self.logError("Unexpected error while writing pipe port: %s" % exceptionString) self.onError(exceptionString) self.disconnect(True) raise TransportError()
def send(self, command): commandToSend = command + "\n" try: self._serial.write(commandToSend) self._transport_logger.info("Send: %s" % command) self.logTx(command) except serial.SerialTimeoutException: self._transport_logger.warn("Timeout while sending: %s" % command) self.logError("Serial timeout while writing to serial port, try again later.") raise SendTimeout() except: exceptionString = getExceptionString() self.logError("Unexpected error while writing serial port: %s" % exceptionString) self.onError(exceptionString) self.disconnect(True) raise TransportError()
def _validate_profile(profile): if not "name" in profile \ and "volume" in profile \ and "width" in profile["volume"] \ and "depth" in profile["volume"] \ and "height" in profile["volume"] \ and "formFactor" in profile["volume"] \ and "heatedBed" in profile \ and "extruder" in profile \ and "count" in profile["extruder"] \ and "offsets" in profile["extruder"] \ and len(profile["extruder"]["offsets"]) == profile["extruder"]["count"]: return False for dimension in ("width", "depth", "height"): try: profile["volume"][dimension] = float(profile["volume"][dimension]) except: return False if not profile["volume"]["formFactor"] in ("rectangular", "circular"): return False try: profile["heatedBed"] = bool(profile["heatedBed"]) except: return False try: profile["extruder"]["count"] = int(profile["extruder"]["count"]) except: return False converted_offsets = [] for offset in profile["extruder"]["offsets"]: try: #converted_offsets.append((float(offset[0]), float(offset[1]), float(offset[2]))) converted_offsets.append(offset) except: from octoprint.util import getExceptionString exceptionString = getExceptionString() print("lkj except : %s" % exceptionString) return False profile["extruder"]["offsets"] = converted_offsets return True
def _readline(self): if self._serial is None: return None try: line = self._serial.readline() except: exceptionString = getExceptionString() self.logError("Unexpected error while reading serial port: %s" % exceptionString) self.onError(exceptionString) self.disconnect() return None if line != "": loggable_line = unicode(line, "ascii", "replace").encode("ascii", "replace").rstrip() self._transport_logger.debug("Recv: %s" % loggable_line) self.logRx(loggable_line) return line
def _readline(self): if self._pipe is None: return None try: line = self._pipe.readline() except: exceptionString = getExceptionString() print("lkj Unexpected error while reading pipe port: %s" % exceptionString) self.logError("Unexpected error while reading pipe port: %s" % exceptionString) self.onError(exceptionString) self.disconnect() return None if line != "": loggable_line = unicode(line, "ascii", "replace").encode("ascii", "replace").rstrip() self._transport_logger.debug("Recv: %s" % loggable_line) self.logRx(loggable_line) return line
def _openSerial(self): if self._port == 'AUTO': self._changeState(self.STATE_DETECT_SERIAL) programmer = stk500v2.Stk500v2() self._log("Serial port list: %s" % (str(self._callback.serialList()))) for p in self._callback.serialList(): try: self._log("Connecting to: %s" % (p)) programmer.connect(p) self._serial = programmer.leaveISP() break except ispBase.IspError as (e): self._log("Error while connecting to %s: %s" % (p, str(e))) pass except: self._log("Unexpected error while connecting to serial port: %s %s" % (p, getExceptionString())) programmer.close() if self._serial is None: self._log("Failed to autodetect serial port") self._errorValue = 'Failed to autodetect serial port.' self._changeState(self.STATE_ERROR) eventManager().fire(Events.ERROR, {"error": self.getErrorString()}) return False elif self._port == 'VIRTUAL': self._changeState(self.STATE_OPEN_SERIAL) self._serial = VirtualPrinter() else: self._changeState(self.STATE_OPEN_SERIAL) try: self._log("Connecting to: %s" % self._port) if self._baudrate == 0: self._serial = serial.Serial(str(self._port), 115200, timeout=0.1, writeTimeout=10000) else: self._serial = serial.Serial(str(self._port), self._baudrate, timeout=settings().getFloat(["serial", "timeout", "connection"]), writeTimeout=10000) except: self._log("Unexpected error while connecting to serial port: %s %s" % (self._port, getExceptionString())) self._errorValue = "Failed to open serial port, permissions correct?" self._changeState(self.STATE_ERROR) eventManager().fire(Events.ERROR, {"error": self.getErrorString()}) return False return True
def _readline(self): if self._serial == None: return None try: ret = self._serial.readline() except: self._serialLoggerEnabled and self._log("Unexpected error while reading serial port: %s" % (getExceptionString())) self._errorValue = getExceptionString() self.close(True) return None if ret == '': # self._serialLoggerEnabled and self._log("Recv: TIMEOUT") return '' self._serialLoggerEnabled and self._log("Recv: %s" % sanitizeAscii(ret)) if self._callback.broadcastTraffic > 0: self._callback.doTrafficBroadcast('r', ret) #sanitizeAscii(ret)) return ret
def _monitor(self): feedbackControls = settings().getFeedbackControls() pauseTriggers = settings().getPauseTriggers() feedbackErrors = [] #Open the serial port. if self._port == 'AUTO': self._changeState(self.STATE_DETECT_SERIAL) programmer = stk500v2.Stk500v2() self._log("Serial port list: %s" % (str(serialList()))) for p in serialList(): try: self._log("Connecting to: %s" % (p)) programmer.connect(p) self._serial = programmer.leaveISP() break except ispBase.IspError as (e): self._log("Error while connecting to %s: %s" % (p, str(e))) pass except: self._log("Unexpected error while connecting to serial port: %s %s" % (p, getExceptionString())) programmer.close() elif self._port == 'VIRTUAL': self._changeState(self.STATE_OPEN_SERIAL) self._serial = VirtualPrinter() else: self._changeState(self.STATE_OPEN_SERIAL) try: self._log("Connecting to: %s" % (self._port)) if self._baudrate == 0: self._serial = serial.Serial(str(self._port), 115200, timeout=0.1, writeTimeout=10000) else: self._serial = serial.Serial(str(self._port), self._baudrate, timeout=settings().getFloat(["serial", "timeout", "connection"]), writeTimeout=10000) except: self._log("Unexpected error while connecting to serial port: %s %s" % (self._port, getExceptionString())) if self._serial == None: self._log("Failed to open serial port (%s)" % (self._port)) self._errorValue = 'Failed to autodetect serial port.' self._changeState(self.STATE_ERROR) eventManager().fire("Error", self.getErrorString()) return self._log("Connected to: %s, starting monitor" % (self._serial)) if self._baudrate == 0: self._changeState(self.STATE_DETECT_BAUDRATE) else: self._changeState(self.STATE_CONNECTING) #Start monitoring the serial port. timeout = getNewTimeout("communication") tempRequestTimeout = timeout sdStatusRequestTimeout = timeout startSeen = not settings().getBoolean(["feature", "waitForStartOnConnect"]) heatingUp = False swallowOk = False while True: try: line = self._readline() if line == None: break ##~~ Error handling # No matter the state, if we see an error, goto the error state and store the error for reference. if line.startswith('Error:'): #Oh YEAH, consistency. # Marlin reports an MIN/MAX temp error as "Error:x\n: Extruder switched off. MAXTEMP triggered !\n" # But a bed temp error is reported as "Error: Temperature heated bed switched off. MAXTEMP triggered !!" # So we can have an extra newline in the most common case. Awesome work people. if re.match('Error:[0-9]\n', line): line = line.rstrip() + self._readline() #Skip the communication errors, as those get corrected. if 'checksum mismatch' in line \ or 'Wrong checksum' in line \ or 'Line Number is not Last Line Number' in line \ or 'expected line' in line \ or 'No Line Number with checksum' in line \ or 'No Checksum with line number' in line \ or 'Missing checksum' in line: pass elif not self.isError(): self._errorValue = line[6:] self._changeState(self.STATE_ERROR) eventManager().fire("Error", self.getErrorString()) ##~~ SD file list # if we are currently receiving an sd file list, each line is just a filename, so just read it and abort processing if self._sdFileList and not 'End file list' in line: self._sdFiles.append(line.strip().lower()) continue ##~~ Temperature processing if ' T:' in line or line.startswith('T:'): try: self._temp = float(re.search("-?[0-9\.]*", line.split('T:')[1]).group(0)) if ' B:' in line: self._bedTemp = float(re.search("-?[0-9\.]*", line.split(' B:')[1]).group(0)) self._callback.mcTempUpdate(self._temp, self._bedTemp, self._targetTemp, self._bedTargetTemp) except ValueError: # catch conversion issues, we'll rather just not get the temperature update instead of killing the connection pass #If we are waiting for an M109 or M190 then measure the time we lost during heatup, so we can remove that time from our printing time estimate. if not 'ok' in line: heatingUp = True if self._heatupWaitStartTime != 0: t = time.time() self._heatupWaitTimeLost = t - self._heatupWaitStartTime self._heatupWaitStartTime = t ##~~ SD Card handling elif 'SD init fail' in line: self._sdAvailable = False self._sdFiles = [] self._callback.mcSdStateChange(self._sdAvailable) elif 'Not SD printing' in line: if self.isSdFileSelected() and self.isPrinting(): # something went wrong, printer is reporting that we actually are not printing right now... self._sdFilePos = 0 self._changeState(self.STATE_OPERATIONAL) elif 'SD card ok' in line: self._sdAvailable = True self.refreshSdFiles() self._callback.mcSdStateChange(self._sdAvailable) elif 'Begin file list' in line: self._sdFiles = [] self._sdFileList = True elif 'End file list' in line: self._sdFileList = False self._callback.mcSdFiles(self._sdFiles) elif 'SD printing byte' in line: # answer to M27, at least on Marlin, Repetier and Sprinter: "SD printing byte %d/%d" match = re.search("([0-9]*)/([0-9]*)", line) self._currentFile.setFilepos(int(match.group(1))) self._callback.mcProgress() elif 'File opened' in line: # answer to M23, at least on Marlin, Repetier and Sprinter: "File opened:%s Size:%d" match = re.search("File opened:\s*(.*?)\s+Size:\s*([0-9]*)", line) self._currentFile = PrintingSdFileInformation(match.group(1), int(match.group(2))) elif 'File selected' in line: # final answer to M23, at least on Marlin, Repetier and Sprinter: "File selected" self._callback.mcFileSelected(self._currentFile.getFilename(), self._currentFile.getFilesize(), True) eventManager().fire("FileSelected", self._currentFile.getFilename()) elif 'Writing to file' in line: # anwer to M28, at least on Marlin, Repetier and Sprinter: "Writing to file: %s" self._printSection = "CUSTOM" self._changeState(self.STATE_PRINTING) elif 'Done printing file' in line: # printer is reporting file finished printing self._sdFilePos = 0 self._callback.mcPrintjobDone() self._changeState(self.STATE_OPERATIONAL) eventManager().fire("PrintDone") ##~~ Message handling elif line.strip() != '' and line.strip() != 'ok' and not line.startswith("wait") and not line.startswith('Resend:') and line != 'echo:Unknown command:""\n' and self.isOperational(): self._callback.mcMessage(line) ##~~ Parsing for feedback commands if feedbackControls: for name, matcher, template in feedbackControls: try: match = matcher.search(line) if match is not None: format = None if isinstance(template, str): format = str.format elif isinstance(template, unicode): format = unicode.format if format is not None: self._callback.mcReceivedRegisteredMessage(name, format(template, *(match.groups("n/a")))) except: if not name in feedbackErrors: self._logger.info("Something went wrong with feedbackControl \"%s\": " % name, exc_info=True) feedbackErrors.append(name) pass ##~~ Parsing for pause triggers if pauseTriggers: if "enable" in pauseTriggers.keys() and pauseTriggers["enable"].search(line) is not None: self.setPause(True) elif "disable" in pauseTriggers.keys() and pauseTriggers["disable"].search(line) is not None: self.setPause(False) elif "toggle" in pauseTriggers.keys() and pauseTriggers["toggle"].search(line) is not None: self.setPause(not self.isPaused()) if "ok" in line and heatingUp: heatingUp = False ### Baudrate detection if self._state == self.STATE_DETECT_BAUDRATE: if line == '' or time.time() > timeout: if len(self._baudrateDetectList) < 1: self.close() self._errorValue = "No more baudrates to test, and no suitable baudrate found." self._changeState(self.STATE_ERROR) eventManager().fire("Error", self.getErrorString()) elif self._baudrateDetectRetry > 0: self._baudrateDetectRetry -= 1 self._serial.write('\n') self._log("Baudrate test retry: %d" % (self._baudrateDetectRetry)) self._sendCommand("M105") self._testingBaudrate = True else: baudrate = self._baudrateDetectList.pop(0) try: self._serial.baudrate = baudrate self._serial.timeout = settings().getFloat(["serial", "timeout", "detection"]) self._log("Trying baudrate: %d" % (baudrate)) self._baudrateDetectRetry = 5 self._baudrateDetectTestOk = 0 timeout = getNewTimeout("communication") self._serial.write('\n') self._sendCommand("M105") self._testingBaudrate = True except: self._log("Unexpected error while setting baudrate: %d %s" % (baudrate, getExceptionString())) elif 'ok' in line and 'T:' in line: self._baudrateDetectTestOk += 1 if self._baudrateDetectTestOk < 10: self._log("Baudrate test ok: %d" % (self._baudrateDetectTestOk)) self._sendCommand("M105") else: self._sendCommand("M999") self._serial.timeout = settings().getFloat(["serial", "timeout", "connection"]) self._changeState(self.STATE_OPERATIONAL) if self._sdAvailable: self.refreshSdFiles() eventManager().fire("Connected", "%s at %s baud" % (self._port, self._baudrate)) else: self._testingBaudrate = False ### Connection attempt elif self._state == self.STATE_CONNECTING: if (line == "" or "wait" in line) and startSeen: self._sendCommand("M105") elif "start" in line: startSeen = True elif "ok" in line and startSeen: self._changeState(self.STATE_OPERATIONAL) if self._sdAvailable: self.refreshSdFiles() eventManager().fire("Connected", "%s at %s baud" % (self._port, self._baudrate)) elif time.time() > timeout: self.close() ### Operational elif self._state == self.STATE_OPERATIONAL or self._state == self.STATE_PAUSED: #Request the temperature on comm timeout (every 5 seconds) when we are not printing. if line == "" or "wait" in line: if self._resendDelta is not None: self._resendNextCommand() elif not self._commandQueue.empty(): self._sendCommand(self._commandQueue.get()) else: self._sendCommand("M105") tempRequestTimeout = getNewTimeout("communication") # resend -> start resend procedure from requested line elif line.lower().startswith("resend") or line.lower().startswith("rs"): if settings().get(["feature", "swallowOkAfterResend"]): swallowOk = True self._handleResendRequest(line) ### Printing elif self._state == self.STATE_PRINTING: if line == "" and time.time() > timeout: self._log("Communication timeout during printing, forcing a line") line = 'ok' if self.isSdPrinting(): if time.time() > tempRequestTimeout and not heatingUp: self._sendCommand("M105") tempRequestTimeout = getNewTimeout("communication") if time.time() > sdStatusRequestTimeout and not heatingUp: self._sendCommand("M27") sdStatusRequestTimeout = time.time() + 1 if 'ok' or 'SD printing byte' in line: timeout = getNewTimeout("communication") else: # Even when printing request the temperature every 5 seconds. if time.time() > tempRequestTimeout and not self.isStreaming(): self._commandQueue.put("M105") tempRequestTimeout = getNewTimeout("communication") if "ok" in line and swallowOk: swallowOk = False elif "ok" in line: timeout = getNewTimeout("communication") if self._resendDelta is not None: self._resendNextCommand() elif not self._commandQueue.empty() and not self.isStreaming(): self._sendCommand(self._commandQueue.get()) else: self._sendNext() elif line.lower().startswith("resend") or line.lower().startswith("rs"): if settings().get(["feature", "swallowOkAfterResend"]): swallowOk = True self._handleResendRequest(line) except: self._logger.exception("Something crashed inside the serial connection loop, please report this in OctoPrint's bug tracker:") errorMsg = "See octoprint.log for details" self._log(errorMsg) self._errorValue = errorMsg self._changeState(self.STATE_ERROR) eventManager().fire("Error", self.getErrorString()) self._log("Connection closed, closing down monitor")
def _monitor(self): feedbackControls = settings().getFeedbackControls() pauseTriggers = settings().getPauseTriggers() feedbackErrors = [] #Open the serial port. if not self._openSerial(): return self._log("Connected to: %s, starting monitor" % self._serial) if self._baudrate == 0: self._log("Starting baud rate detection") self._changeState(self.STATE_DETECT_BAUDRATE) else: self._changeState(self.STATE_CONNECTING) #Start monitoring the serial port. timeout = getNewTimeout("communication") tempRequestTimeout = getNewTimeout("temperature") sdStatusRequestTimeout = getNewTimeout("sdStatus") startSeen = not settings().getBoolean(["feature", "waitForStartOnConnect"]) self._heatingUp = False swallowOk = False supportRepetierTargetTemp = settings().getBoolean(["feature", "repetierTargetTemp"]) while True: try: line = self._readline() if line is None: break if line.strip() is not "" and line.isalnum(): timeout = getNewTimeout("communication") ##~~ Error handling line = self._handleErrors(line) ##~~ SD file list # if we are currently receiving an sd file list, each line is just a filename, so just read it and abort processing if self._sdFileList and not "End file list" in line: fileinfo = line.strip().split(None, 2) if len(fileinfo) > 1: # we got extended file information here, so let's split filename and size and try to make them a bit nicer filename, size = fileinfo filename = filename.lower() try: size = int(size) except ValueError: # whatever that was, it was not an integer, so we'll just ignore it and set size to None size = None else: # no extended file information, so only the filename is there and we set size to None filename = fileinfo[0].lower() size = None if self._callback.fileManager.isValidFilename(filename): if filterNonAscii(filename): self._logger.warn("Got a file from printer's SD that has a non-ascii filename (%s), that shouldn't happen according to the protocol" % filename) else: self._sdFiles.append((filename, size)) continue ##~~ Temperature processing if ' T:' in line or line.startswith('T:') or ' T0:' in line or line.startswith('T0:'): self._processTemperatures(line) self._callback.mcTempUpdate(self._temp, self._bedTemp) #If we are waiting for an M109 or M190 then measure the time we lost during heatup, so we can remove that time from our printing time estimate. if not 'ok' in line and self._heatupWaitStartTime != 0: t = time.time() self._heatupWaitTimeLost = t - self._heatupWaitStartTime self._heatupWaitStartTime = t elif supportRepetierTargetTemp and ('TargetExtr' in line or 'TargetBed' in line): matchExtr = self._regex_repetierTempExtr.match(line) matchBed = self._regex_repetierTempBed.match(line) if matchExtr is not None: toolNum = int(matchExtr.group(1)) try: target = float(matchExtr.group(2)) if toolNum in self._temp.keys() and self._temp[toolNum] is not None and isinstance(self._temp[toolNum], tuple): (actual, oldTarget) = self._temp[toolNum] self._temp[toolNum] = (actual, target) else: self._temp[toolNum] = (None, target) self._callback.mcTempUpdate(self._temp, self._bedTemp) except ValueError: pass elif matchBed is not None: try: target = float(matchBed.group(1)) if self._bedTemp is not None and isinstance(self._bedTemp, tuple): (actual, oldTarget) = self._bedTemp self._bedTemp = (actual, target) else: self._bedTemp = (None, target) self._callback.mcTempUpdate(self._temp, self._bedTemp) except ValueError: pass ##~~ SD Card handling elif 'SD init fail' in line or 'volume.init failed' in line or 'openRoot failed' in line: self._sdAvailable = False self._sdFiles = [] self._callback.mcSdStateChange(self._sdAvailable) elif 'Not SD printing' in line: if self.isSdFileSelected() and self.isPrinting(): # something went wrong, printer is reporting that we actually are not printing right now... self._sdFilePos = 0 self._changeState(self.STATE_OPERATIONAL) elif 'SD card ok' in line and not self._sdAvailable: self._sdAvailable = True self.refreshSdFiles() self._callback.mcSdStateChange(self._sdAvailable) elif 'Begin file list' in line: self._sdFiles = [] self._sdFileList = True elif 'End file list' in line: self._sdFileList = False self._callback.mcSdFiles(self._sdFiles) elif 'SD printing byte' in line: # answer to M27, at least on Marlin, Repetier and Sprinter: "SD printing byte %d/%d" match = self._regex_sdPrintingByte.search(line) self._currentFile.setFilepos(int(match.group(1))) self._callback.mcProgress() elif 'File opened' in line: # answer to M23, at least on Marlin, Repetier and Sprinter: "File opened:%s Size:%d" match = self._regex_sdFileOpened.search(line) self._currentFile = PrintingSdFileInformation(match.group(1), int(match.group(2))) elif 'File selected' in line: # final answer to M23, at least on Marlin, Repetier and Sprinter: "File selected" if self._currentFile is not None: self._callback.mcFileSelected(self._currentFile.getFilename(), self._currentFile.getFilesize(), True) eventManager().fire(Events.FILE_SELECTED, { "file": self._currentFile.getFilename(), "origin": self._currentFile.getFileLocation() }) elif 'Writing to file' in line: # anwer to M28, at least on Marlin, Repetier and Sprinter: "Writing to file: %s" self._printSection = "CUSTOM" self._changeState(self.STATE_PRINTING) line = "ok" elif 'Done printing file' in line: # printer is reporting file finished printing self._sdFilePos = 0 self._callback.mcPrintjobDone() self._changeState(self.STATE_OPERATIONAL) eventManager().fire(Events.PRINT_DONE, { "file": self._currentFile.getFilename(), "filename": os.path.basename(self._currentFile.getFilename()), "origin": self._currentFile.getFileLocation(), "time": self.getPrintTime(), "layerCount": self._currentLayer }) elif 'Done saving file' in line: self.refreshSdFiles() ##~~ Message handling elif line.strip() != '' \ and line.strip() != 'ok' and not line.startswith("wait") \ and not line.startswith('Resend:') \ and line != 'echo:Unknown command:""\n' \ and self.isOperational(): self._callback.mcMessage(line) ##~~ Parsing for feedback commands if feedbackControls: for name, matcher, template in feedbackControls: if name in feedbackErrors: # we previously had an error with that one, so we'll skip it now continue try: match = matcher.search(line) if match is not None: formatFunction = None if isinstance(template, str): formatFunction = str.format elif isinstance(template, unicode): formatFunction = unicode.format if formatFunction is not None: self._callback.mcReceivedRegisteredMessage(name, formatFunction(template, *(match.groups("n/a")))) except: if not name in feedbackErrors: self._logger.info("Something went wrong with feedbackControl \"%s\": " % name, exc_info=True) feedbackErrors.append(name) pass ##~~ Parsing for pause triggers if pauseTriggers and not self.isStreaming(): if "enable" in pauseTriggers.keys() and pauseTriggers["enable"].search(line) is not None: self.setPause(True) elif "disable" in pauseTriggers.keys() and pauseTriggers["disable"].search(line) is not None: self.setPause(False) elif "toggle" in pauseTriggers.keys() and pauseTriggers["toggle"].search(line) is not None: self.setPause(not self.isPaused()) if "ok" in line and self._heatingUp: self._heatingUp = False self._callback.mcHeatingUpUpdate(self._heatingUp) ### Baudrate detection if self._state == self.STATE_DETECT_BAUDRATE: if line == '' or time.time() > timeout: if len(self._baudrateDetectList) < 1: self.close() self._errorValue = "No more baudrates to test, and no suitable baudrate found." self._changeState(self.STATE_ERROR) eventManager().fire(Events.ERROR, {"error": self.getErrorString()}) elif self._baudrateDetectRetry > 0: self._baudrateDetectRetry -= 1 self._serial.write('\n') self._log("Baudrate test retry: %d" % (self._baudrateDetectRetry)) self._sendCommand("M105") self._testingBaudrate = True else: baudrate = self._baudrateDetectList.pop(0) try: self._serial.baudrate = baudrate self._serial.timeout = settings().getFloat(["serial", "timeout", "detection"]) self._log("Trying baudrate: %d" % (baudrate)) self._baudrateDetectRetry = 5 self._baudrateDetectTestOk = 0 timeout = getNewTimeout("communication") self._serial.write('\n') self._sendCommand("M105") self._testingBaudrate = True except: self._log("Unexpected error while setting baudrate: %d %s" % (baudrate, getExceptionString())) elif 'ok' in line and 'T:' in line: self._baudrateDetectTestOk += 1 if self._baudrateDetectTestOk < 10: self._log("Baudrate test ok: %d" % (self._baudrateDetectTestOk)) self._sendCommand("M105") else: self._sendCommand("M999") self._serial.timeout = settings().getFloat(["serial", "timeout", "connection"]) self._changeState(self.STATE_OPERATIONAL) if self._sdAvailable: self.refreshSdFiles() else: self.initSdCard() eventManager().fire(Events.CONNECTED, {"port": self._port, "baudrate": self._baudrate}) else: self._testingBaudrate = False ### Connection attempt elif self._state == self.STATE_CONNECTING: if (line == "" or "wait" in line) and startSeen: if time.time() > timeout: self.close() else: self._sendCommand("M105") elif "start" in line: startSeen = True elif "ok" in line and startSeen: self._changeState(self.STATE_OPERATIONAL) if self._sdAvailable: self.refreshSdFiles() else: self.initSdCard() eventManager().fire(Events.CONNECTED, {"port": self._port, "baudrate": self._baudrate}) elif time.time() > timeout: self.close() ### Operational elif self._state == self.STATE_OPERATIONAL or self._state == self.STATE_PAUSED: #Request the temperature on comm timeout (every 5 seconds) when we are not printing. if line == "" or "wait" in line: if self._resendDelta is not None: self._resendNextCommand() elif not self._commandQueue.empty(): self._sendCommand(self._commandQueue.get()) else: self._sendCommand("M105") tempRequestTimeout = getNewTimeout("temperature") # resend -> start resend procedure from requested line elif line.lower().startswith("resend") or line.lower().startswith("rs"): if settings().get(["feature", "swallowOkAfterResend"]): swallowOk = True self._handleResendRequest(line) else: positionMatch = self._regex_M114Response.search(line) if positionMatch: self._positionWhenPaused = ( float(positionMatch.group(1)), float(positionMatch.group(2)), float(positionMatch.group(3)), float(positionMatch.group(4)) ) if self.isPaused(): self.sendCommand("G1 F9000 X0 Y0 Z%.4f E%.4f" % (self._positionWhenPaused[2] + 5, self._positionWhenPaused[3] - 5)) ### Printing elif self._state == self.STATE_PRINTING: if line == "" and time.time() > timeout: self._log("Communication timeout during printing, forcing a line") line = 'ok' if self.isSdPrinting(): if time.time() > tempRequestTimeout and not self._heatingUp: self._sendCommand("M105") tempRequestTimeout = getNewTimeout("temperature") if time.time() > sdStatusRequestTimeout and not self._heatingUp: self._sendCommand("M27") sdStatusRequestTimeout = getNewTimeout("sdStatus") else: # Even when printing request the temperature every 5 seconds. if time.time() > tempRequestTimeout and not self.isStreaming(): self._commandQueue.put("M105") tempRequestTimeout = getNewTimeout("temperature") if "ok" in line and swallowOk: swallowOk = False elif "ok" in line: if self._resendDelta is not None: self._resendNextCommand() elif not self._commandQueue.empty() and not self.isStreaming(): self._sendCommand(self._commandQueue.get(), True) else: self._sendNext() elif line.lower().startswith("resend") or line.lower().startswith("rs"): if settings().get(["feature", "swallowOkAfterResend"]): swallowOk = True self._handleResendRequest(line) except: self._logger.exception("Something crashed inside the serial connection loop, please report this to AstroPrint:") errorMsg = "See astrobox.log for details" self._log(errorMsg) self._errorValue = errorMsg self._changeState(self.STATE_ERROR) eventManager().fire(Events.ERROR, {"error": self.getErrorString()}) self._log("Connection closed, closing down monitor")
def run(self): profile = self._printer._profile self._printer._heatingUp = True self._printer.mcHeatingUpUpdate(True) self._heatupWaitStartTime = time.time() self._heatingTool = True self._lastLayerHeight = 0.0 self._currentLayer = 0 try: self._printer._comm.reset() self._printer._comm.build_start_notification(os.path.basename(self._file['filename'])[:15]) self._printer._comm.set_build_percent(0) self._file['start_time'] = time.time() self._file['progress'] = 0 lastProgressReport = 0 lastProgressValueSentToPrinter = 0 lastHeatingCheck = self._file['start_time'] with open(self._file['filename'], 'rb') as f: while True: packet = bytearray() try: command = f.read(1) if self._canceled or len(command) == 0: break packet.append(ord(command)) command = struct.unpack("B",command) try: parse = self.commandTable[command[0]] except KeyError: raise Exception("Unexpected packet type: 0x%x" % command[0]) if type(parse) == type(""): packetLen = struct.calcsize(parse) packetData = f.read(packetLen) if len(packetData) != packetLen: raise Exception("Packet incomplete") else: packetData = parse(f) for c in packetData: packet.append(ord(c)) if self.send_packet(packet): self._serialLoggerEnabled and self._serialLogger.debug('{"event":"packet_sent", "data": "%s"}' % ' '.join('0x{:02x}'.format(x) for x in packet) ) now = time.time() if now - lastProgressReport > self.UPDATE_INTERVAL_SECS: position = f.tell() self._file['position'] = position self._file['progress'] = float(position) / float(self._file['size']) self._printer.mcProgress() printerProgress = int(self._file['progress'] * 100.0) if lastProgressValueSentToPrinter != printerProgress: try: self._printer._comm.set_build_percent(printerProgress) lastProgressValueSentToPrinter = printerProgress lastProgressReport = now except BufferOverflowError: time.sleep(.2) if self._printer._heatingUp and now - lastHeatingCheck > self.UPDATE_INTERVAL_SECS: lastHeatingCheck = now if ( not self._heatingPlatform or ( self._heatingPlatform and self._printer._comm.is_platform_ready(0) ) ) \ and ( not self._heatingTool or ( self._heatingTool and self._printer._comm.is_tool_ready(0) ) ): self._heatingTool = False self._heatingPlatform = False self._printer._heatingUp = False self._printer.mcHeatingUpUpdate(False) self._heatupWaitTimeLost = now - self._heatupWaitStartTime self._heatupWaitStartTime = now self._file['start_time'] += self._heatupWaitTimeLost except ProtocolError as e: self._logger.warn('ProtocolError: %s' % e) self._printer._comm.build_end_notification() if self._canceled: self._printer._comm.clear_buffer() #Is possible to get a BufferOverflowError when succesfully completing a job continueEndSequence = False findAxesTries = 0 while not continueEndSequence: try: self._printer._comm.find_axes_maximums(['x', 'y'], 200, 10) continueEndSequence = True except BufferOverflowError: if findAxesTries < 3: time.sleep(.2) findAxesTries += 1 else: continueEndSequence = True #find current z: moveToPosition, endStopsStates = self._printer._comm.get_extended_position() zEndStopReached = endStopsStates & 16 == 16 #endstop is a bitfield. See https://github.com/makerbot/s3g/blob/master/doc/s3gProtocol.md (command 21) if zEndStopReached: #calculate Z max moveToPosition[2] = self._printer._profile.values['axes']['Z']['platform_length'] * self._printer._profile.values['axes']['Z']['steps_per_mm'] #move to the bottom: self._printer._comm.queue_extended_point_classic(moveToPosition, 100) self._printer._comm.toggle_axes(['x','y','z','a','b'], False) self._printer._changeState(self._printer.STATE_OPERATIONAL) payload = { "file": self._file['filename'], "filename": os.path.basename(self._file['filename']), "origin": self._file['origin'], "time": self._printer.getPrintTime(), "layerCount": self._currentLayer } if self._canceled: self._printer.printJobCancelled() eventManager().fire(Events.PRINT_FAILED, payload) self._printer._fileManager.printFailed(payload['filename'], payload['time']) else: self._printer.mcPrintjobDone() self._printer._fileManager.printSucceeded(payload['filename'], payload['time'], payload['layerCount']) eventManager().fire(Events.PRINT_DONE, payload) except BuildCancelledError: self._logger.warn('Build Cancel detected') self._printer.printJobCancelled() payload = { "file": self._file['filename'], "filename": os.path.basename(self._file['filename']), "origin": self._file['origin'], "time": self._printer.getPrintTime() } eventManager().fire(Events.PRINT_FAILED, payload) self._printer._fileManager.printFailed(payload['filename'], payload['time']) self._printer._changeState(self._printer.STATE_OPERATIONAL) except ExternalStopError: self._logger.warn('External Stop detected') self._printer._comm.writer.set_external_stop(False) self._printer.printJobCancelled() payload = { "file": self._file['filename'], "filename": os.path.basename(self._file['filename']), "origin": self._file['origin'], "time": self._printer.getPrintTime() } eventManager().fire(Events.PRINT_FAILED, payload) self._printer._fileManager.printFailed(payload['filename'], payload['time']) self._printer._changeState(self._printer.STATE_OPERATIONAL) except Exception as e: self._errorValue = getExceptionString() self._printer._changeState(self._printer.STATE_ERROR) eventManager().fire(Events.ERROR, {"error": self._errorValue }) self._logger.error(self._errorValue)
def _connect(self): self.changeState(State.OPENING_CONNECTION) if self._port == "VIRTUAL": self._serial = VirtualPrinter(read_timeout=self._readTimeout, write_timeout=self._writeTimeout) self.changeState(State.CONNECTED) self._transport_logger.debug("Connected to %s" % self._serial) else: try: self._serial = serial.Serial(self._port, self._baudrate, timeout=self._readTimeout, writeTimeout=self._writeTimeout) self.changeState(State.CONNECTED) self._transport_logger.debug("Connected to %s" % self._serial) except: self.logError("Unexpected error while connecting to serial port: %s %s" % (self._port, getExceptionString())) self.onError("Failed to open serial port, permissions correct?") return False eventManager().fire(Events.CONNECTED, {"port": self._port, "baudrate": self._baudrate}) return True
def _work(self): import makerbot_driver.MachineFactory s = settings() retries = self.CONNECT_MAX_RETRIES try: while True: if self.isConnected(): self._comm.close() if retries < 0: self._changeState(self.STATE_ERROR) self._errorValue = "Error Connecting" self._logger.error('Error connecting to printer.') self._comm = None break; else: try: result = makerbot_driver.MachineFactory().build_from_port(self._port, condition= self._state_condition) self._comm = result.s3g self._profile = result.profile self._gcodeParser = result.gcodeparser version_info = self._comm.get_advanced_version() #We should update some of the profile values with stuff retrieved from the EEPROM axisLengths = self._comm.read_named_value_from_EEPROM('AXIS_LENGTHS_MM') stepsPerMM = self._comm.read_named_value_from_EEPROM('AXIS_STEPS_PER_MM') self._profile.values['axes']['X']['platform_length'] = axisLengths[0] self._profile.values['axes']['Y']['platform_length'] = axisLengths[1] self._profile.values['axes']['Z']['platform_length'] = axisLengths[2] self._profile.values['axes']['A']['platform_length'] = axisLengths[3] self._profile.values['axes']['X']['steps_per_mm'] = stepsPerMM[0]/1000000.0 self._profile.values['axes']['Y']['steps_per_mm'] = stepsPerMM[1]/1000000.0 self._profile.values['axes']['Z']['steps_per_mm'] = stepsPerMM[2]/1000000.0 self._profile.values['axes']['A']['steps_per_mm'] = -stepsPerMM[3]/1000000.0 if "B" in self._profile.values['axes']: self._profile.values['axes']['B']['steps_per_mm'] = -stepsPerMM[4]/1000000.0 self._profile.values['axes']['B']['platform_length'] = axisLengths[4] self._firmwareVersion = version_info['Version'] self._logger.info('Connected to Machine running version: %d, variant: 0x%x' % (self._firmwareVersion, version_info['SoftwareVariant']) ) self._changeState(self.STATE_OPERATIONAL) s.set(['serial', 'port'], self._port) s.save() break except makerbot_driver.errors.TransmissionError as e: retries -= 1 if retries > 0: self._logger.info('TransmissionError - Retrying. Retries left %d...' % retries) time.sleep(.2) except makerbot_driver.errors.UnknownResponseError as e: retries -= 1 if retries > 0: self._logger.info('UnknownResponseError - Retrying. Retries left %d...' % retries) time.sleep(.2) except makerbot_driver.errors.BuildCancelledError: self._logger.info("Build cancelled detected. No problem") if retries >=0: toolHeadCount = len(self._profile.values['tools']) while self._comm: try: for i in range(0, toolHeadCount): self._temp[i] = (self._comm.get_toolhead_temperature(i), self._comm.get_toolhead_target_temperature(i)) self._bedTemp = (self._comm.get_platform_temperature(0), self._comm.get_platform_target_temperature(0)) self.mcTempUpdate(self._temp, self._bedTemp) except makerbot_driver.BufferOverflowError: pass except makerbot_driver.TransmissionError: self._logger.error('Unfortunatelly an unrecoverable error occurred between the printer and the box') self.disconnect() break except makerbot_driver.BuildCancelledError: self._logger.warn('Build cancelled detected.') if self._printJob: self._logger.warn('Cancelling current job.') self._printJob.cancel() except makerbot_driver.ProtocolError: # It has been observed that sometimes the response comes back empty but # in a valid package. This was in a Flash Forge running Sailfish 7.7 self._logger.warn('Badly formatted response. skipping...') except SerialException as e: raise e except Exception as e: # we shouldn't kill the thread as this is only an informational # thread import traceback print traceback.format_exc() self._logger.warn(getExceptionString()) time.sleep(self.UPDATE_INTERVAL) except SerialException as e: self._logger.error(e) self._errorValue = "Serial Link failed" self._changeState(self.STATE_ERROR) eventManager().fire(Events.ERROR, {"error": self.getErrorString()}) self.disconnect()
def run(self): self._printer._heatingUp = True self._printer.mcHeatingUpUpdate(True) self._heatupWaitStartTime = time.time() self._heatingTool = True self._lastLayerHeight = 0.0 self._currentLayer = 0 try: self._printer._comm.reset() self._printer._comm.build_start_notification( os.path.basename(self._file['filename'])[:15]) self._printer._comm.set_build_percent(0) self._file['start_time'] = time.time() self._file['progress'] = 0 lastProgressReport = 0 lastProgressValueSentToPrinter = 0 lastHeatingCheck = self._file['start_time'] #Now we assume that the bed won't be clear from this point on self._printer.set_bed_clear(False) with open(self._file['filename'], 'rb') as f: while True: packet = bytearray() try: command = f.read(1) if self._canceled or len(command) == 0: break packet.append(ord(command)) command = struct.unpack("B", command) try: parse = self.commandTable[command[0]] except KeyError: raise Exception("Unexpected packet type: 0x%x" % command[0]) if type(parse) == type(""): packetLen = struct.calcsize(parse) packetData = f.read(packetLen) if len(packetData) != packetLen: raise Exception( "Packet incomplete when reading command 0x%x from file" % command[0]) else: packetData = parse(f) for c in packetData: packet.append(ord(c)) if self.send_packet(packet): self._serialLoggerEnabled and self._serialLogger.debug( '{"event":"packet_sent", "data": "%s"}' % ' '.join('0x{:02x}'.format(x) for x in packet)) now = time.time() if now - lastProgressReport > self.UPDATE_INTERVAL_SECS: position = f.tell() self._file['position'] = position self._file['progress'] = float( position) / float(self._file['size']) self._printer.mcProgress() printerProgress = int(self._file['progress'] * 100.0) if lastProgressValueSentToPrinter != printerProgress: try: self._printer._comm.set_build_percent( printerProgress) lastProgressValueSentToPrinter = printerProgress lastProgressReport = now except BufferOverflowError: time.sleep(.2) if self._printer._heatingUp and now - lastHeatingCheck > self.UPDATE_INTERVAL_SECS: lastHeatingCheck = now if ( not self._heatingPlatform or ( self._heatingPlatform and self._printer._comm.is_platform_ready(0) ) ) \ and ( not self._heatingTool or ( self._heatingTool and self._printer._comm.is_tool_ready(self._printer.getSelectedTool()) ) ): self._heatingTool = False self._heatingPlatform = False self._printer._heatingUp = False self._printer.mcHeatingUpUpdate(False) self._heatupWaitTimeLost = now - self._heatupWaitStartTime self._heatupWaitStartTime = now self._file[ 'start_time'] += self._heatupWaitTimeLost except ProtocolError as e: self._logger.warn('ProtocolError: %s' % e) self._printer._comm.build_end_notification() if self._canceled: self._printer._comm.clear_buffer() #Is possible to get a BufferOverflowError when succesfully completing a job continueEndSequence = False findAxesTries = 0 while not continueEndSequence: try: self._printer._comm.find_axes_maximums(['x', 'y'], 200, 10) continueEndSequence = True except BufferOverflowError: if findAxesTries < 3: time.sleep(.2) findAxesTries += 1 else: continueEndSequence = True # The ability to find out the platform length of an axis dissapeared in Sailfish 7.3 so we remove for now #find current z: #moveToPosition, endStopsStates = self._printer._comm.get_extended_position() #zEndStopReached = endStopsStates & 16 == 16 #endstop is a bitfield. See https://github.com/makerbot/s3g/blob/master/doc/s3gProtocol.md (command 21) #if zEndStopReached: #calculate Z max # moveToPosition[2] = self._printer._profile.values['axes']['Z']['platform_length'] * self._printer._profile.values['axes']['Z']['steps_per_mm'] #move to the bottom: # self._printer._comm.queue_extended_point_classic(moveToPosition, 100) self._printer._comm.toggle_axes(['x', 'y', 'z', 'a', 'b'], False) self._printer._changeState( self._printer.STATE_OPERATIONAL if self._printer. isBedClear else self._printer.STATE_NOT_READY_TO_PRINT) payload = { "file": self._file['filename'], "filename": os.path.basename(self._file['filename']), "origin": self._file['origin'], "time": self._printer.getPrintTime(), "layerCount": self._currentLayer } if self._canceled: self._printer.printJobCancelled() eventManager().fire(Events.PRINT_FAILED, payload) self._printer._fileManager.printFailed(payload['filename'], payload['time']) else: self._printer.mcPrintjobDone() self._printer._fileManager.printSucceeded( payload['filename'], payload['time'], payload['layerCount']) eventManager().fire(Events.PRINT_DONE, payload) except BuildCancelledError: self._logger.warn('Build Cancel detected') self._printer.printJobCancelled() payload = { "file": self._file['filename'], "filename": os.path.basename(self._file['filename']), "origin": self._file['origin'], "time": self._printer.getPrintTime() } eventManager().fire(Events.PRINT_FAILED, payload) self._printer._fileManager.printFailed(payload['filename'], payload['time']) self._printer._changeState( self._printer.STATE_OPERATIONAL if self._printer. isBedClear else self._printer.STATE_NOT_READY_TO_PRINT) except ExternalStopError: self._logger.warn('External Stop detected') self._printer._comm.writer.set_external_stop(False) self._printer.printJobCancelled() payload = { "file": self._file['filename'], "filename": os.path.basename(self._file['filename']), "origin": self._file['origin'], "time": self._printer.getPrintTime() } eventManager().fire(Events.PRINT_FAILED, payload) self._printer._fileManager.printFailed(payload['filename'], payload['time']) self._printer._changeState( self._printer.STATE_OPERATIONAL if self._printer. isBedClear else self._printer.STATE_NOT_READY_TO_PRINT) except Exception as e: self._errorValue = getExceptionString() self._printer._changeState(self._printer.STATE_ERROR) eventManager().fire(Events.ERROR, {"error": self._errorValue}) self._logger.error(self._errorValue)
def _work(self): import makerbot_driver.MachineFactory s = settings() retries = self.CONNECT_MAX_RETRIES try: while True: if self.isConnected(): self._comm.close() if retries < 0: self._changeState(self.STATE_ERROR) self._errorValue = "Error Connecting" self._logger.error('Error connecting to printer.') self._comm = None break else: try: result = makerbot_driver.MachineFactory( ).build_from_port(self._port, condition=self._state_condition) self._comm = result.s3g self._profile = result.profile self._gcodeParser = result.gcodeparser version_info = self._comm.get_advanced_version() # We should update some of the profile values # with stuff retrieved from the EEPROM axisLengths = self._comm.read_named_value_from_EEPROM( 'AXIS_LENGTHS_MM') stepsPerMM = self._comm.read_named_value_from_EEPROM( 'AXIS_STEPS_PER_MM') self._profile.values['axes']['X'][ 'platform_length'] = axisLengths[0] self._profile.values['axes']['Y'][ 'platform_length'] = axisLengths[1] self._profile.values['axes']['Z'][ 'platform_length'] = axisLengths[2] self._profile.values['axes']['A'][ 'platform_length'] = axisLengths[3] self._profile.values['axes']['X'][ 'steps_per_mm'] = stepsPerMM[0] / 1000000.0 self._profile.values['axes']['Y'][ 'steps_per_mm'] = stepsPerMM[1] / 1000000.0 self._profile.values['axes']['Z'][ 'steps_per_mm'] = stepsPerMM[2] / 1000000.0 self._profile.values['axes']['A'][ 'steps_per_mm'] = -stepsPerMM[3] / 1000000.0 if "B" in self._profile.values['axes']: self._profile.values['axes']['B'][ 'steps_per_mm'] = -stepsPerMM[4] / 1000000.0 self._profile.values['axes']['B'][ 'platform_length'] = axisLengths[4] self._firmwareVersion = version_info['Version'] self._logger.info( 'Connected to Machine running version: %d, variant: 0x%x' % \ (self._firmwareVersion, version_info['SoftwareVariant']) ) self._changeState(self.STATE_OPERATIONAL) s.set(['serial', 'port'], self._port) s.save() break except makerbot_driver.errors.TransmissionError as e: retries -= 1 if retries > 0: self._logger.info( 'TransmissionError - Retrying. Retries left %d...' % retries) time.sleep(.2) except makerbot_driver.errors.UnknownResponseError as e: retries -= 1 if retries > 0: self._logger.info( 'UnknownResponseError - Retrying. Retries left %d...' % \ retries) time.sleep(.2) except makerbot_driver.errors.BuildCancelledError: self._logger.info( "Build cancelled detected. No problem") if retries >= 0: toolHeadCount = len(self._profile.values['tools']) while self._comm: try: for i in range(0, toolHeadCount): self._temp[i] = ( self._comm.get_toolhead_temperature(i), self._comm.get_toolhead_target_temperature(i)) self._bedTemp = ( self._comm.get_platform_temperature(0), self._comm.get_platform_target_temperature(0)) self.mcTempUpdate(self._temp, self._bedTemp) except makerbot_driver.BufferOverflowError: pass except makerbot_driver.TransmissionError: self._logger.error( 'Unfortunatelly an unrecoverable error occurred between the printer and the box' ) self.disconnect() break except makerbot_driver.BuildCancelledError: self._logger.warn('Build cancelled detected.') if self._printJob: self._logger.warn('Cancelling current job.') self._printJob.cancel() except makerbot_driver.ProtocolError: # It has been observed that sometimes the # response comes back empty but in a valid package. # This was in a Flash Forge running Sailfish 7.7 self._logger.warn( 'Badly formatted response. skipping...') except SerialException as e: raise e except Exception as e: # we shouldn't kill the thread as this is only an # informational thread import traceback print traceback.format_exc() self._logger.warn(getExceptionString()) time.sleep(self.UPDATE_INTERVAL) except SerialException as e: self._logger.error(e) self._errorValue = "Serial Link failed" self._changeState(self.STATE_ERROR) eventManager().fire(Events.ERROR, {"error": self.getErrorString()}) self.disconnect()
def _monitor(self): feedbackControls = settings().getFeedbackControls() pauseTriggers = settings().getPauseTriggers() feedbackErrors = [] #Open the serial port. if self._port == 'AUTO': self._changeState(self.STATE_DETECT_SERIAL) programmer = stk500v2.Stk500v2() self._log("Serial port list: %s" % (str(serialList()))) for p in serialList(): try: self._log("Connecting to: %s" % (p)) programmer.connect(p) self._serial = programmer.leaveISP() break except ispBase.IspError as (e): self._log("Error while connecting to %s: %s" % (p, str(e))) pass except: self._log( "Unexpected error while connecting to serial port: %s %s" % (p, getExceptionString())) programmer.close() elif self._port == 'VIRTUAL': self._changeState(self.STATE_OPEN_SERIAL) self._serial = VirtualPrinter() else: self._changeState(self.STATE_OPEN_SERIAL) try: self._log("Connecting to: %s" % (self._port)) if self._baudrate == 0: self._serial = serial.Serial(str(self._port), 115200, timeout=0.1, writeTimeout=10000) else: self._serial = serial.Serial(str(self._port), self._baudrate, timeout=settings().getFloat([ "serial", "timeout", "connection" ]), writeTimeout=10000) except: self._log( "Unexpected error while connecting to serial port: %s %s" % (self._port, getExceptionString())) if self._serial == None: self._log("Failed to open serial port (%s)" % (self._port)) self._errorValue = 'Failed to autodetect serial port.' self._changeState(self.STATE_ERROR) eventManager().fire("Error", self.getErrorString()) return self._log("Connected to: %s, starting monitor" % (self._serial)) if self._baudrate == 0: self._changeState(self.STATE_DETECT_BAUDRATE) else: self._changeState(self.STATE_CONNECTING) #Start monitoring the serial port. timeout = getNewTimeout("communication") tempRequestTimeout = timeout sdStatusRequestTimeout = timeout startSeen = not settings().getBoolean( ["feature", "waitForStartOnConnect"]) heatingUp = False swallowOk = False while True: try: line = self._readline() if line == None: break ##~~ Error handling # No matter the state, if we see an error, goto the error state and store the error for reference. if line.startswith('Error:'): #Oh YEAH, consistency. # Marlin reports an MIN/MAX temp error as "Error:x\n: Extruder switched off. MAXTEMP triggered !\n" # But a bed temp error is reported as "Error: Temperature heated bed switched off. MAXTEMP triggered !!" # So we can have an extra newline in the most common case. Awesome work people. if self._regex_minMaxError.match(line): line = line.rstrip() + self._readline() #Skip the communication errors, as those get corrected. if 'checksum mismatch' in line \ or 'Wrong checksum' in line \ or 'Line Number is not Last Line Number' in line \ or 'expected line' in line \ or 'No Line Number with checksum' in line \ or 'No Checksum with line number' in line \ or 'Missing checksum' in line: pass elif not self.isError(): self._errorValue = line[6:] self._changeState(self.STATE_ERROR) eventManager().fire("Error", self.getErrorString()) ##~~ SD file list # if we are currently receiving an sd file list, each line is just a filename, so just read it and abort processing if self._sdFileList and not 'End file list' in line: self._sdFiles.append(line.strip().lower()) continue ##~~ Temperature processing if ' T:' in line or line.startswith('T:'): try: self._temp = float( self._regex_float.search( line.split('T:')[1]).group(0)) if ' B:' in line: self._bedTemp = float( self._regex_float.search( line.split(' B:')[1]).group(0)) self._callback.mcTempUpdate(self._temp, self._bedTemp, self._targetTemp, self._bedTargetTemp) except ValueError: # catch conversion issues, we'll rather just not get the temperature update instead of killing the connection pass #If we are waiting for an M109 or M190 then measure the time we lost during heatup, so we can remove that time from our printing time estimate. if not 'ok' in line: heatingUp = True if self._heatupWaitStartTime != 0: t = time.time() self._heatupWaitTimeLost = t - self._heatupWaitStartTime self._heatupWaitStartTime = t ##~~ SD Card handling elif 'SD init fail' in line: self._sdAvailable = False self._sdFiles = [] self._callback.mcSdStateChange(self._sdAvailable) elif 'Not SD printing' in line: if self.isSdFileSelected() and self.isPrinting(): # something went wrong, printer is reporting that we actually are not printing right now... self._sdFilePos = 0 self._changeState(self.STATE_OPERATIONAL) elif 'SD card ok' in line: self._sdAvailable = True self.refreshSdFiles() self._callback.mcSdStateChange(self._sdAvailable) elif 'Begin file list' in line: self._sdFiles = [] self._sdFileList = True elif 'End file list' in line: self._sdFileList = False self._callback.mcSdFiles(self._sdFiles) elif 'SD printing byte' in line: # answer to M27, at least on Marlin, Repetier and Sprinter: "SD printing byte %d/%d" match = self._regex_sdPrintingByte.search( "([0-9]*)/([0-9]*)", line) self._currentFile.setFilepos(int(match.group(1))) self._callback.mcProgress() elif 'File opened' in line: # answer to M23, at least on Marlin, Repetier and Sprinter: "File opened:%s Size:%d" match = self._regex_sdFileOpened.search(line) self._currentFile = PrintingSdFileInformation( match.group(1), int(match.group(2))) elif 'File selected' in line: # final answer to M23, at least on Marlin, Repetier and Sprinter: "File selected" self._callback.mcFileSelected( self._currentFile.getFilename(), self._currentFile.getFilesize(), True) eventManager().fire("FileSelected", self._currentFile.getFilename()) elif 'Writing to file' in line: # anwer to M28, at least on Marlin, Repetier and Sprinter: "Writing to file: %s" self._changeState(self.STATE_PRINTING) line = "ok" elif 'Done printing file' in line: # printer is reporting file finished printing self._sdFilePos = 0 self._callback.mcPrintjobDone() self._changeState(self.STATE_OPERATIONAL) eventManager().fire("PrintDone") ##~~ Message handling elif line.strip() != '' and line.strip( ) != 'ok' and not line.startswith( "wait" ) and not line.startswith( 'Resend:' ) and line != 'echo:Unknown command:""\n' and self.isOperational( ): self._callback.mcMessage(line) ##~~ Parsing for feedback commands if feedbackControls: for name, matcher, template in feedbackControls: try: match = matcher.search(line) if match is not None: format = None if isinstance(template, str): format = str.format elif isinstance(template, unicode): format = unicode.format if format is not None: self._callback.mcReceivedRegisteredMessage( name, format(template, *(match.groups("n/a")))) except: if not name in feedbackErrors: self._logger.info( "Something went wrong with feedbackControl \"%s\": " % name, exc_info=True) feedbackErrors.append(name) pass ##~~ Parsing for pause triggers if pauseTriggers and not self.isStreaming(): if "enable" in pauseTriggers.keys( ) and pauseTriggers["enable"].search(line) is not None: self.setPause(True) elif "disable" in pauseTriggers.keys( ) and pauseTriggers["disable"].search(line) is not None: self.setPause(False) elif "toggle" in pauseTriggers.keys( ) and pauseTriggers["toggle"].search(line) is not None: self.setPause(not self.isPaused()) if "ok" in line and heatingUp: heatingUp = False ### Baudrate detection if self._state == self.STATE_DETECT_BAUDRATE: if line == '' or time.time() > timeout: if len(self._baudrateDetectList) < 1: self.close() self._errorValue = "No more baudrates to test, and no suitable baudrate found." self._changeState(self.STATE_ERROR) eventManager().fire("Error", self.getErrorString()) elif self._baudrateDetectRetry > 0: self._baudrateDetectRetry -= 1 self._serial.write('\n') self._log("Baudrate test retry: %d" % (self._baudrateDetectRetry)) self._sendCommand("M105") self._testingBaudrate = True else: baudrate = self._baudrateDetectList.pop(0) try: self._serial.baudrate = baudrate self._serial.timeout = settings().getFloat( ["serial", "timeout", "detection"]) self._log("Trying baudrate: %d" % (baudrate)) self._baudrateDetectRetry = 5 self._baudrateDetectTestOk = 0 timeout = getNewTimeout("communication") self._serial.write('\n') self._sendCommand("M105") self._testingBaudrate = True except: self._log( "Unexpected error while setting baudrate: %d %s" % (baudrate, getExceptionString())) elif 'ok' in line and 'T:' in line: self._baudrateDetectTestOk += 1 if self._baudrateDetectTestOk < 10: self._log("Baudrate test ok: %d" % (self._baudrateDetectTestOk)) self._sendCommand("M105") else: self._sendCommand("M999") self._serial.timeout = settings().getFloat( ["serial", "timeout", "connection"]) self._changeState(self.STATE_OPERATIONAL) if self._sdAvailable: self.refreshSdFiles() eventManager().fire( "Connected", "%s at %s baud" % (self._port, self._baudrate)) else: self._testingBaudrate = False ### Connection attempt elif self._state == self.STATE_CONNECTING: if (line == "" or "wait" in line) and startSeen: self._sendCommand("M105") elif "start" in line: startSeen = True elif "ok" in line and startSeen: self._changeState(self.STATE_OPERATIONAL) if self._sdAvailable: self.refreshSdFiles() eventManager().fire( "Connected", "%s at %s baud" % (self._port, self._baudrate)) elif time.time() > timeout: self.close() ### Operational elif self._state == self.STATE_OPERATIONAL or self._state == self.STATE_PAUSED: #Request the temperature on comm timeout (every 5 seconds) when we are not printing. if line == "" or "wait" in line: if self._resendDelta is not None: self._resendNextCommand() elif not self._commandQueue.empty(): self._sendCommand(self._commandQueue.get()) else: self._sendCommand("M105") tempRequestTimeout = getNewTimeout("communication") # resend -> start resend procedure from requested line elif line.lower().startswith( "resend") or line.lower().startswith("rs"): if settings().get(["feature", "swallowOkAfterResend"]): swallowOk = True self._handleResendRequest(line) ### Printing elif self._state == self.STATE_PRINTING: if line == "" and time.time() > timeout: self._log( "Communication timeout during printing, forcing a line" ) line = 'ok' if self.isSdPrinting(): if time.time() > tempRequestTimeout and not heatingUp: self._sendCommand("M105") tempRequestTimeout = getNewTimeout("communication") if time.time( ) > sdStatusRequestTimeout and not heatingUp: self._sendCommand("M27") sdStatusRequestTimeout = time.time() + 1 if 'ok' or 'SD printing byte' in line: timeout = getNewTimeout("communication") else: # Even when printing request the temperature every 5 seconds. if time.time( ) > tempRequestTimeout and not self.isStreaming(): self._commandQueue.put("M105") tempRequestTimeout = getNewTimeout("communication") if "ok" in line and swallowOk: swallowOk = False elif "ok" in line: timeout = getNewTimeout("communication") if self._resendDelta is not None: self._resendNextCommand() elif not self._commandQueue.empty( ) and not self.isStreaming(): self._sendCommand(self._commandQueue.get()) else: self._sendNext() elif line.lower().startswith( "resend") or line.lower().startswith("rs"): if settings().get( ["feature", "swallowOkAfterResend"]): swallowOk = True self._handleResendRequest(line) except: self._logger.exception( "Something crashed inside the serial connection loop, please report this in OctoPrint's bug tracker:" ) errorMsg = "See octoprint.log for details" self._log(errorMsg) self._errorValue = errorMsg self._changeState(self.STATE_ERROR) eventManager().fire("Error", self.getErrorString()) self._log("Connection closed, closing down monitor")
def _monitor(self): feedbackControls = settings().getFeedbackControls() pauseTriggers = settings().getPauseTriggers() feedbackErrors = [] #Open the serial port. if not self._openSerial(): return self._log("Connected to: %s, starting monitor" % self._serial) if self._baudrate == 0: self._log("Starting baud rate detection") self._changeState(self.STATE_DETECT_BAUDRATE) else: self._changeState(self.STATE_CONNECTING) #Start monitoring the serial port. timeout = getNewTimeout("communication") tempRequestTimeout = getNewTimeout("temperature") sdStatusRequestTimeout = getNewTimeout("sdStatus") startSeen = not settings().getBoolean(["feature", "waitForStartOnConnect"]) heatingUp = False swallowOk = False supportRepetierTargetTemp = settings().getBoolean(["feature", "repetierTargetTemp"]) while True: try: line = self._readline() if line is None: break if line.strip() is not "": timeout = getNewTimeout("communication") ##~~ Error handling line = self._handleErrors(line) ##~~ SD file list # if we are currently receiving an sd file list, each line is just a filename, so just read it and abort processing if self._sdFileList and isGcodeFileName(line.strip().lower()) and not 'End file list' in line: filename = line.strip().lower() if filterNonAscii(filename): self._logger.warn("Got a file from printer's SD that has a non-ascii filename (%s), that shouldn't happen according to the protocol" % filename) else: self._sdFiles.append(filename) continue ##~~ Temperature processing if ' T:' in line or line.startswith('T:') or ' T0:' in line or line.startswith('T0:'): self._processTemperatures(line) self._callback.mcTempUpdate(self._temp, self._bedTemp) #If we are waiting for an M109 or M190 then measure the time we lost during heatup, so we can remove that time from our printing time estimate. if not 'ok' in line: heatingUp = True if self._heatupWaitStartTime != 0: t = time.time() self._heatupWaitTimeLost = t - self._heatupWaitStartTime self._heatupWaitStartTime = t elif supportRepetierTargetTemp: matchExtr = self._regex_repetierTempExtr.match(line) matchBed = self._regex_repetierTempBed.match(line) if matchExtr is not None: toolNum = int(matchExtr.group(1)) try: target = float(matchExtr.group(2)) if toolNum in self._temp.keys() and self._temp[toolNum] is not None and isinstance(self._temp[toolNum], tuple): (actual, oldTarget) = self._temp[toolNum] self._temp[toolNum] = (actual, target) else: self._temp[toolNum] = (None, target) self._callback.mcTempUpdate(self._temp, self._bedTemp) except ValueError: pass elif matchBed is not None: try: target = float(matchBed.group(1)) if self._bedTemp is not None and isinstance(self._bedTemp, tuple): (actual, oldTarget) = self._bedTemp self._bedTemp = (actual, target) else: self._bedTemp = (None, target) self._callback.mcTempUpdate(self._temp, self._bedTemp) except ValueError: pass ##~~ SD Card handling elif 'SD init fail' in line or 'volume.init failed' in line or 'openRoot failed' in line: self._sdAvailable = False self._sdFiles = [] self._callback.mcSdStateChange(self._sdAvailable) elif 'Not SD printing' in line: if self.isSdFileSelected() and self.isPrinting(): # something went wrong, printer is reporting that we actually are not printing right now... self._sdFilePos = 0 self._changeState(self.STATE_OPERATIONAL) elif 'SD card ok' in line and not self._sdAvailable: self._sdAvailable = True self.refreshSdFiles() self._callback.mcSdStateChange(self._sdAvailable) elif 'Begin file list' in line: self._sdFiles = [] self._sdFileList = True elif 'End file list' in line: self._sdFileList = False self._callback.mcSdFiles(self._sdFiles) elif 'SD printing byte' in line: # answer to M27, at least on Marlin, Repetier and Sprinter: "SD printing byte %d/%d" match = self._regex_sdPrintingByte.search(line) self._currentFile.setFilepos(int(match.group(1))) self._callback.mcProgress() elif 'File opened' in line: # answer to M23, at least on Marlin, Repetier and Sprinter: "File opened:%s Size:%d" match = self._regex_sdFileOpened.search(line) self._currentFile = PrintingSdFileInformation(match.group(1), int(match.group(2))) elif 'File selected' in line: # final answer to M23, at least on Marlin, Repetier and Sprinter: "File selected" if self._currentFile is not None: self._callback.mcFileSelected(self._currentFile.getFilename(), self._currentFile.getFilesize(), True) eventManager().fire(Events.FILE_SELECTED, { "file": self._currentFile.getFilename(), "origin": self._currentFile.getFileLocation() }) elif 'Writing to file' in line: # anwer to M28, at least on Marlin, Repetier and Sprinter: "Writing to file: %s" self._printSection = "CUSTOM" self._changeState(self.STATE_PRINTING) line = "ok" elif 'Done printing file' in line: # printer is reporting file finished printing self._sdFilePos = 0 self._callback.mcPrintjobDone() self._changeState(self.STATE_OPERATIONAL) eventManager().fire(Events.PRINT_DONE, { "file": self._currentFile.getFilename(), "filename": os.path.basename(self._currentFile.getFilename()), "origin": self._currentFile.getFileLocation(), "time": self.getPrintTime() }) elif 'Done saving file' in line: self.refreshSdFiles() ##~~ Message handling elif line.strip() != '' \ and line.strip() != 'ok' and not line.startswith("wait") \ and not line.startswith('Resend:') \ and line != 'echo:Unknown command:""\n' \ and self.isOperational(): self._callback.mcMessage(line) ##~~ Parsing for feedback commands if feedbackControls: for name, matcher, template in feedbackControls: if name in feedbackErrors: # we previously had an error with that one, so we'll skip it now continue try: match = matcher.search(line) if match is not None: formatFunction = None if isinstance(template, str): formatFunction = str.format elif isinstance(template, unicode): formatFunction = unicode.format if formatFunction is not None: self._callback.mcReceivedRegisteredMessage(name, formatFunction(template, *(match.groups("n/a")))) except: if not name in feedbackErrors: self._logger.info("Something went wrong with feedbackControl \"%s\": " % name, exc_info=True) feedbackErrors.append(name) pass ##~~ Parsing for pause triggers if pauseTriggers and not self.isStreaming(): if "enable" in pauseTriggers.keys() and pauseTriggers["enable"].search(line) is not None: self.setPause(True) elif "disable" in pauseTriggers.keys() and pauseTriggers["disable"].search(line) is not None: self.setPause(False) elif "toggle" in pauseTriggers.keys() and pauseTriggers["toggle"].search(line) is not None: self.setPause(not self.isPaused()) if "ok" in line and heatingUp: heatingUp = False ### Baudrate detection if self._state == self.STATE_DETECT_BAUDRATE: if line == '' or time.time() > timeout: if len(self._baudrateDetectList) < 1: self.close() self._errorValue = "No more baudrates to test, and no suitable baudrate found." self._changeState(self.STATE_ERROR) eventManager().fire(Events.ERROR, {"error": self.getErrorString()}) elif self._baudrateDetectRetry > 0: self._baudrateDetectRetry -= 1 self._serial.write('\n') self._log("Baudrate test retry: %d" % (self._baudrateDetectRetry)) self._sendCommand("M105") self._testingBaudrate = True else: baudrate = self._baudrateDetectList.pop(0) try: self._serial.baudrate = baudrate self._serial.timeout = settings().getFloat(["serial", "timeout", "detection"]) self._log("Trying baudrate: %d" % (baudrate)) self._baudrateDetectRetry = 5 self._baudrateDetectTestOk = 0 timeout = getNewTimeout("communication") self._serial.write('\n') self._sendCommand("M105") self._testingBaudrate = True except: self._log("Unexpected error while setting baudrate: %d %s" % (baudrate, getExceptionString())) elif 'ok' in line and 'T:' in line: self._baudrateDetectTestOk += 1 if self._baudrateDetectTestOk < 10: self._log("Baudrate test ok: %d" % (self._baudrateDetectTestOk)) self._sendCommand("M105") else: self._sendCommand("M999") self._serial.timeout = settings().getFloat(["serial", "timeout", "connection"]) self._changeState(self.STATE_OPERATIONAL) if self._sdAvailable: self.refreshSdFiles() else: self.initSdCard() eventManager().fire(Events.CONNECTED, {"port": self._port, "baudrate": self._baudrate}) else: self._testingBaudrate = False ### Connection attempt elif self._state == self.STATE_CONNECTING: if (line == "" or "wait" in line) and startSeen: self._sendCommand("M105") elif "start" in line: startSeen = True elif "ok" in line and startSeen: self._changeState(self.STATE_OPERATIONAL) if self._sdAvailable: self.refreshSdFiles() else: self.initSdCard() eventManager().fire(Events.CONNECTED, {"port": self._port, "baudrate": self._baudrate}) elif time.time() > timeout: self.close() ### Operational elif self._state == self.STATE_OPERATIONAL or self._state == self.STATE_PAUSED: #Request the temperature on comm timeout (every 5 seconds) when we are not printing. if line == "" or "wait" in line: if self._resendDelta is not None: self._resendNextCommand() elif not self._commandQueue.empty(): self._sendCommand(self._commandQueue.get()) else: self._sendCommand("M105") tempRequestTimeout = getNewTimeout("temperature") # resend -> start resend procedure from requested line elif line.lower().startswith("resend") or line.lower().startswith("rs"): if settings().get(["feature", "swallowOkAfterResend"]): swallowOk = True self._handleResendRequest(line) ### Printing elif self._state == self.STATE_PRINTING: if line == "" and time.time() > timeout: self._log("Communication timeout during printing, forcing a line") line = 'ok' if self.isSdPrinting(): if time.time() > tempRequestTimeout and not heatingUp: self._sendCommand("M105") tempRequestTimeout = getNewTimeout("temperature") if time.time() > sdStatusRequestTimeout and not heatingUp: self._sendCommand("M27") sdStatusRequestTimeout = getNewTimeout("sdStatus") else: # Even when printing request the temperature every 5 seconds. if time.time() > tempRequestTimeout and not self.isStreaming(): self._commandQueue.put("M105") tempRequestTimeout = getNewTimeout("temperature") if "ok" in line and swallowOk: swallowOk = False elif "ok" in line: if self._resendDelta is not None: self._resendNextCommand() elif not self._commandQueue.empty() and not self.isStreaming(): self._sendCommand(self._commandQueue.get()) else: self._sendNext() elif line.lower().startswith("resend") or line.lower().startswith("rs"): if settings().get(["feature", "swallowOkAfterResend"]): swallowOk = True self._handleResendRequest(line) except: self._logger.exception("Something crashed inside the serial connection loop, please report this in OctoPrint's bug tracker:") errorMsg = "See octoprint.log for details" self._log(errorMsg) self._errorValue = errorMsg self._changeState(self.STATE_ERROR) eventManager().fire(Events.ERROR, {"error": self.getErrorString()}) self._log("Connection closed, closing down monitor")
def _monitor(self): feedbackControls = settings().getFeedbackControls() pauseTriggers = settings().getPauseTriggers() feedbackErrors = [] #Open the serial port. if not self._openSerial(): return self._log("Connected to: %s, starting monitor" % self._serial) if self._baudrate == 0: self._log("Starting baud rate detection") self._changeState(self.STATE_DETECT_BAUDRATE) else: self._changeState(self.STATE_CONNECTING) #Start monitoring the serial port. timeout = getNewTimeout("communication") tempRequestTimeout = timeout sdStatusRequestTimeout = timeout startSeen = not settings().getBoolean(["feature", "waitForStartOnConnect"]) heatingUp = False swallowOk = False while True: try: line = self._readline() if line is None: break ##~~ Error handling line = self._handleErrors(line) ##~~ SD file list # if we are currently receiving an sd file list, each line is just a filename, so just read it and abort processing if self._sdFileList and isGcodeFileName(line.strip().lower()) and not 'End file list' in line: filename = line.strip().lower() if filterNonAscii(filename): self._logger.warn("Got a file from printer's SD that has a non-ascii filename (%s), that shouldn't happen according to the protocol" % filename) else: self._sdFiles.append(filename) continue ##~~ Temperature processing if ' T:' in line or line.startswith('T:'): try: self._temp = float(self._regex_float.search(line.split('T:')[1]).group(0)) if ' B:' in line: self._bedTemp = float(self._regex_float.search(line.split(' B:')[1]).group(0)) self._callback.mcTempUpdate(self._temp, self._bedTemp, self._targetTemp, self._bedTargetTemp) except ValueError: # catch conversion issues, we'll rather just not get the temperature update instead of killing the connection pass #If we are waiting for an M109 or M190 then measure the time we lost during heatup, so we can remove that time from our printing time estimate. if not 'ok' in line: heatingUp = True if self._heatupWaitStartTime != 0: t = time.time() self._heatupWaitTimeLost = t - self._heatupWaitStartTime self._heatupWaitStartTime = t ##~~ SD Card handling elif 'SD init fail' in line or 'volume.init failed' in line or 'openRoot failed' in line: self._sdAvailable = False self._sdFiles = [] self._callback.mcSdStateChange(self._sdAvailable) elif 'Not SD printing' in line: if self.isSdFileSelected() and self.isPrinting(): # something went wrong, printer is reporting that we actually are not printing right now... self._sdFilePos = 0 self._changeState(self.STATE_OPERATIONAL) elif 'SD card ok' in line: self._sdAvailable = True self.refreshSdFiles() self._callback.mcSdStateChange(self._sdAvailable) elif 'Begin file list' in line: self._sdFiles = [] self._sdFileList = True elif 'End file list' in line: self._sdFileList = False self._callback.mcSdFiles(self._sdFiles) elif 'SD printing byte' in line: # answer to M27, at least on Marlin, Repetier and Sprinter: "SD printing byte %d/%d" match = self._regex_sdPrintingByte.search(line) self._currentFile.setFilepos(int(match.group(1))) self._callback.mcProgress() elif 'File opened' in line: # answer to M23, at least on Marlin, Repetier and Sprinter: "File opened:%s Size:%d" match = self._regex_sdFileOpened.search(line) self._currentFile = PrintingSdFileInformation(match.group(1), int(match.group(2))) elif 'File selected' in line: # final answer to M23, at least on Marlin, Repetier and Sprinter: "File selected" if self._currentFile is not None: self._callback.mcFileSelected(self._currentFile.getFilename(), self._currentFile.getFilesize(), True) eventManager().fire("FileSelected", self._currentFile.getFilename()) elif 'Writing to file' in line: # anwer to M28, at least on Marlin, Repetier and Sprinter: "Writing to file: %s" self._changeState(self.STATE_PRINTING) line = "ok" elif 'Done printing file' in line: # printer is reporting file finished printing self._sdFilePos = 0 self._callback.mcPrintjobDone() self._changeState(self.STATE_OPERATIONAL) eventManager().fire("PrintDone") elif 'Done saving file' in line: self.refreshSdFiles() ##~~ Message handling elif line.strip() != '' \ and line.strip() != 'ok' and not line.startswith("wait") \ and not line.startswith('Resend:') \ and line != 'echo:Unknown command:""\n' \ and self.isOperational(): self._callback.mcMessage(line) ##~~ Parsing for feedback commands if feedbackControls: for name, matcher, template in feedbackControls: if name in feedbackErrors: # we previously had an error with that one, so we'll skip it now continue try: match = matcher.search(line) if match is not None: formatFunction = None if isinstance(template, str): formatFunction = str.format elif isinstance(template, unicode): formatFunction = unicode.format if formatFunction is not None: self._callback.mcReceivedRegisteredMessage(name, formatFunction(template, *(match.groups("n/a")))) except: if not name in feedbackErrors: self._logger.info("Something went wrong with feedbackControl \"%s\": " % name, exc_info=True) feedbackErrors.append(name) pass ##~~ Parsing for pause triggers if pauseTriggers and not self.isStreaming(): if "enable" in pauseTriggers.keys() and pauseTriggers["enable"].search(line) is not None: self.setPause(True) elif "disable" in pauseTriggers.keys() and pauseTriggers["disable"].search(line) is not None: self.setPause(False) elif "toggle" in pauseTriggers.keys() and pauseTriggers["toggle"].search(line) is not None: self.setPause(not self.isPaused()) if "ok" in line and heatingUp: heatingUp = False ### Baudrate detection if self._state == self.STATE_DETECT_BAUDRATE: if line == '' or time.time() > timeout: if len(self._baudrateDetectList) < 1: self.close() self._errorValue = "No more baudrates to test, and no suitable baudrate found." self._changeState(self.STATE_ERROR) eventManager().fire("Error", self.getErrorString()) elif self._baudrateDetectRetry > 0: self._baudrateDetectRetry -= 1 self._serial.write('\n') self._log("Baudrate test retry: %d" % (self._baudrateDetectRetry)) self._sendCommand("M105") self._testingBaudrate = True else: baudrate = self._baudrateDetectList.pop(0) try: self._serial.baudrate = baudrate self._serial.timeout = settings().getFloat(["serial", "timeout", "detection"]) self._log("Trying baudrate: %d" % (baudrate)) self._baudrateDetectRetry = 5 self._baudrateDetectTestOk = 0 timeout = getNewTimeout("communication") self._serial.write('\n') self._sendCommand("M105") self._testingBaudrate = True except: self._log("Unexpected error while setting baudrate: %d %s" % (baudrate, getExceptionString())) elif 'ok' in line and 'T:' in line: self._baudrateDetectTestOk += 1 if self._baudrateDetectTestOk < 10: self._log("Baudrate test ok: %d" % (self._baudrateDetectTestOk)) self._sendCommand("M105") else: self._sendCommand("M999") self._serial.timeout = settings().getFloat(["serial", "timeout", "connection"]) self._changeState(self.STATE_OPERATIONAL) if self._sdAvailable: self.refreshSdFiles() eventManager().fire("Connected", "%s at %s baud" % (self._port, self._baudrate)) else: self._testingBaudrate = False ### Connection attempt elif self._state == self.STATE_CONNECTING: if (line == "" or "wait" in line) and startSeen: self._sendCommand("M105") elif "start" in line: startSeen = True elif "ok" in line and startSeen: self._changeState(self.STATE_OPERATIONAL) if not self._sdAvailable: self.initSdCard() eventManager().fire("Connected", "%s at %s baud" % (self._port, self._baudrate)) elif time.time() > timeout: self.close() ### Operational elif self._state == self.STATE_OPERATIONAL or self._state == self.STATE_PAUSED: #Request the temperature on comm timeout (every 5 seconds) when we are not printing. if line == "" or "wait" in line: if self._resendDelta is not None: self._resendNextCommand() elif not self._commandQueue.empty(): self._sendCommand(self._commandQueue.get()) else: self._sendCommand("M105") tempRequestTimeout = getNewTimeout("communication") # resend -> start resend procedure from requested line elif line.lower().startswith("resend") or line.lower().startswith("rs"): if settings().get(["feature", "swallowOkAfterResend"]): swallowOk = True self._handleResendRequest(line) ### Printing elif self._state == self.STATE_PRINTING: if line == "" and time.time() > timeout: self._log("Communication timeout during printing, forcing a line") line = 'ok' if self.isSdPrinting(): if time.time() > tempRequestTimeout and not heatingUp: self._sendCommand("M105") tempRequestTimeout = getNewTimeout("communication") if time.time() > sdStatusRequestTimeout and not heatingUp: self._sendCommand("M27") sdStatusRequestTimeout = time.time() + 1 if 'ok' or 'SD printing byte' in line: timeout = getNewTimeout("communication") else: # Even when printing request the temperature every 5 seconds. if time.time() > tempRequestTimeout and not self.isStreaming(): self._commandQueue.put("M105") tempRequestTimeout = getNewTimeout("communication") if "ok" in line and swallowOk: swallowOk = False elif "ok" in line: timeout = getNewTimeout("communication") if self._resendDelta is not None: self._resendNextCommand() elif not self._commandQueue.empty() and not self.isStreaming(): self._sendCommand(self._commandQueue.get()) else: self._sendNext() elif line.lower().startswith("resend") or line.lower().startswith("rs"): if settings().get(["feature", "swallowOkAfterResend"]): swallowOk = True self._handleResendRequest(line) except: self._logger.exception("Something crashed inside the serial connection loop, please report this in OctoPrint's bug tracker:") errorMsg = "See octoprint.log for details" self._log(errorMsg) self._errorValue = errorMsg self._changeState(self.STATE_ERROR) eventManager().fire("Error", self.getErrorString()) self._log("Connection closed, closing down monitor")