Fix handling of "missing line number" errors

We so far assumed that a resend request would follow that. Alas, it
won't and we'll simply get stuck due to a missing ack from the printer.
So let's simulate that here to keep things flowing.

Fixes #2226
This commit is contained in:
Gina Häußge 2017-11-20 18:07:15 +01:00
parent 59ca2188d9
commit c7e248b142

View file

@ -1243,7 +1243,7 @@ class MachineCom(object):
return stripped_line, stripped_line.lower()
##~~ Error handling
line = self._handleErrors(line)
line = self._handle_errors(line)
line, lower_line = convert_line(line)
##~~ SD file list
@ -1950,36 +1950,53 @@ class MachineCom(object):
return False
def _handleErrors(self, line):
_resend_request_communication_errors = ("line number",
"wrong checksum",
"missing checksum",
"format error",
"expected line")
_recoverable_communication_errors = ("no line number with checksum",)
_sd_card_errors = ("volume.init",
"openroot",
"workdir",
"error writing to file",
"cannot open",
"cannot enter")
def _handle_errors(self, line):
if line is None:
return
lower_line = line.lower()
# No matter the state, if we see an error, goto the error state and store the error for reference.
if lower_line.startswith('error:') or line.startswith('!!'):
#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 regex_minMaxError.match(line):
# special delivery for firmware that goes "Error:x\n: Extruder switched off. MAXTEMP triggered !\n"
line = line.rstrip() + self._readline()
if 'line number' in lower_line or 'checksum' in lower_line or 'format error' in lower_line or 'expected line' in lower_line:
#Skip the communication errors, as those get corrected.
if any(map(lambda x: x in lower_line, self._recoverable_communication_errors)):
# manually trigger an ack for comm errors the printer doesn't send a resend request for but
# from which we can recover from by just pushing on (because that then WILL trigger a fitting
# resend request)
self._handle_ok()
elif any(map(lambda x: x in lower_line, self._resend_request_communication_errors)):
# skip comm errors that the printer sends a resend request for anyhow
self._lastCommError = line[6:] if lower_line.startswith("error:") else line[2:]
elif any(map(lambda x: x in lower_line, self._sd_card_errors)):
# skip errors with the SD card
pass
elif 'volume.init' in lower_line or "openroot" in lower_line or 'workdir' in lower_line\
or "error writing to file" in lower_line or "cannot open" in lower_line\
or "cannot enter" in lower_line:
#Also skip errors with the SD card
pass
elif 'unknown command' in lower_line:
#Ignore unknown command errors, it could be a typo or some missing feature
# ignore unknown command errors, it could be a typo or some missing feature
pass
elif not self.isError():
# handle everything else
error_text = line[6:] if lower_line.startswith("error:") else line[2:]
self._to_logfile_with_terminal("Received an error from the printer's firmware: {}".format(error_text), level=logging.WARN)
self._to_logfile_with_terminal("Received an error from the printer's firmware: {}".format(error_text),
level=logging.WARN)
if not self._ignore_errors:
if self._disconnect_on_errors:
self._errorValue = error_text
@ -1991,6 +2008,8 @@ class MachineCom(object):
else:
self._log("WARNING! Received an error from the printer's firmware, ignoring that as configured but you might want to investigate what happened here! Error: {}".format(error_text))
self._clear_to_send.set()
# finally return the line
return line
def _readline(self):
@ -2077,7 +2096,8 @@ class MachineCom(object):
# an active (prior) resend request.
#
# We will ignore this resend request and just continue normally.
self._logger.debug("Ignoring resend request for line %d == current line, we haven't sent that yet so the printer got N-1 twice from us, probably due to a timeout" % lineToResend)
self._logger.info("Ignoring resend request for line %d == current line, we haven't sent that yet so "
"the printer got N-1 twice from us, probably due to a timeout" % lineToResend)
return False
lastCommError = self._lastCommError
@ -2089,7 +2109,8 @@ class MachineCom(object):
and ("line number" in lastCommError.lower() or "expected line" in lastCommError.lower()) \
and lineToResend == self._lastResendNumber \
and self._resendDelta is not None and self._currentResendCount < self._resendDelta:
self._logger.debug("Ignoring resend request for line %d, that still originates from lines we sent before we got the first resend request" % lineToResend)
self._logger.info("Ignoring resend request for line %d, that still originates from lines we sent "
"before we got the first resend request" % lineToResend)
self._currentResendCount += 1
return True
@ -2097,7 +2118,8 @@ class MachineCom(object):
# need to do this now. If the same line number has been requested we
# already saw and resent, we'll ignore it up to <counter> times.
if self._resendSwallowRepetitions and lineToResend == self._lastResendNumber and self._resendSwallowRepetitionsCounter > 0:
self._logger.debug("Ignoring resend request for line %d, that is probably a repetition sent by the firmware to ensure it arrives, not a real request" % lineToResend)
self._logger.info("Ignoring resend request for line %d, that is probably a repetition sent by the "
"firmware to ensure it arrives, not a real request" % lineToResend)
self._resendSwallowRepetitionsCounter -= 1
return True