Exemple #1
0
    def run(self, progressCallback=None):
        try:
            printer.disconnect()
        except:
            pass
        time.sleep(0.5)

        hexFile = intelHex.readHex(self._filename)
        programmer = stk500v2.Stk500v2()
        programmer.progressCallback = progressCallback if progressCallback else self.onProgress

        try:
            programmer.connect(self._port)
        except ispBase.IspError:
            self._logger.error(
                'Failed to find machine for firmware upgrade! Is your machine had been connected?'
            )

        if programmer.isConnected():
            self._logger.info("Uploading firmware...")
            try:
                programmer.programChip(hexFile)
                self._logger.info("Done! Installed firmware: %s" %
                                  (os.path.basename(self._filename)))
            except ispBase.IspError as e:
                self._logger.error("Failed to write firmware.\n" + str(e))
            try:
                programmer.close()
            except:
                pass
            time.sleep(0.5)

        printer.connect(port=self._port,
                        baudrate=settings().get(["serial", "baudrate"]))
Exemple #2
0
 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
Exemple #3
0
    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")
Exemple #4
0
	def _monitor(self):
		#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=2, 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)
			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 = time.time() + 5
		tempRequestTimeout = timeout
		startSeen = not settings().getBoolean(["feature", "waitForStartOnConnect"])
		while True:
			line = self._readline()
			if line == None:
				break
			
			#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 'Line Number is not Last Line Number' in line or 'No Line Number with checksum' in line or 'No Checksum with line number' in line:
					pass
				elif not self.isError():
					self._errorValue = line[6:]
					self._changeState(self.STATE_ERROR)
			if ' T:' in line or line.startswith('T:'):
				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)
				#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 line.strip() != '' and line.strip() != 'ok' and not line.startswith('Resend:') and line != 'echo:Unknown command:""\n' and self.isOperational():
				self._callback.mcMessage(line)

			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)
					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 = 0.5
							self._log("Trying baudrate: %d" % (baudrate))
							self._baudrateDetectRetry = 5
							self._baudrateDetectTestOk = 0
							timeout = time.time() + 5
							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 = 2
						self._changeState(self.STATE_OPERATIONAL)
				else:
					self._testingBaudrate = False
			elif self._state == self.STATE_CONNECTING:
				if line == '' and startSeen:
					self._sendCommand("M105")
				elif 'start' in line:
					startSeen = True
				elif 'ok' in line and startSeen:
					self._changeState(self.STATE_OPERATIONAL)
				elif time.time() > timeout:
					self.close()
			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 == '':
					self._sendCommand("M105")
					tempRequestTimeout = time.time() + 5
			elif self._state == self.STATE_PRINTING:
				if line == '' and time.time() > timeout:
					self._log("Communication timeout during printing, forcing a line")
					line = 'ok'
				#Even when printing request the temperture every 5 seconds.
				if time.time() > tempRequestTimeout:
					self._commandQueue.put("M105")
					tempRequestTimeout = time.time() + 5
				if 'ok' in line:
					timeout = time.time() + 5
					if not self._commandQueue.empty():
						self._sendCommand(self._commandQueue.get())
					else:
						self._sendNext()
				elif "resend" in line.lower() or "rs" in line:
					try:
						self._gcodePos = int(line.replace("N:"," ").replace("N"," ").replace(":"," ").split()[-1])
					except:
						if "rs" in line:
							self._gcodePos = int(line.split()[1])
		self._log("Connection closed, closing down monitor")
Exemple #5
0
	def _monitor(self):
		#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=2, 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)
			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 = time.time() + 5
		tempRequestTimeout = timeout
		sdStatusRequestTimeout = timeout
		startSeen = not settings().getBoolean(["feature", "waitForStartOnConnect"])
		while True:
			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)

			##~~ 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)
				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 and 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 '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._sdFilePos = int(match.group(1))
				self._sdFileSize = int(match.group(2))
				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._sdFile = match.group(1)
				self._sdFileSize = int(match.group(2))
			elif 'File selected' in line:
				# final answer to M23, at least on Marlin, Repetier and Sprinter: "File selected"
				self._callback.mcSdSelected(self._sdFile, self._sdFileSize)
			elif 'Done printing file' in line:
				# printer is reporting file finished printing
				self._sdPrinting = False
				self._sdFilePos = 0
				self._changeState(self.STATE_OPERATIONAL)
				self._callback.mcSdPrintingDone()

			##~~ 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)

			### 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)
					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 = 0.5
							self._log("Trying baudrate: %d" % (baudrate))
							self._baudrateDetectRetry = 5
							self._baudrateDetectTestOk = 0
							timeout = time.time() + 5
							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 = 2
						self._changeState(self.STATE_OPERATIONAL)
				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)
				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 = time.time() + 5
				# resend -> start resend procedure from requested line
				elif "resend" in line.lower() or "rs" in line:
					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._sdPrinting:
					if time.time() > tempRequestTimeout:
						self._sendCommand("M105")
						tempRequestTimeout = time.time() + 5

					if time.time() > sdStatusRequestTimeout:
						self._sendCommand("M27")
						sdStatusRequestTimeout = time.time() + 1

					if 'ok' or 'SD printing byte' in line:
						timeout = time.time() + 5
				else:
					# Even when printing request the temperature every 5 seconds.
					if time.time() > tempRequestTimeout:
						self._commandQueue.put("M105")
						tempRequestTimeout = time.time() + 5

					if 'ok' in line:
						timeout = time.time() + 5
						if self._resendDelta is not None:
							self._resendNextCommand()
						elif not self._commandQueue.empty():
							self._sendCommand(self._commandQueue.get())
						else:
							self._sendNext()
					elif "resend" in line.lower() or "rs" in line:
						self._handleResendRequest(line)
		self._log("Connection closed, closing down monitor")