diff --git a/octoprint/server.py b/octoprint/server.py index 9a342da..d61d8b5 100644 --- a/octoprint/server.py +++ b/octoprint/server.py @@ -359,7 +359,8 @@ def getSettings(): }, "feature": { "gcodeViewer": s.getBoolean(["feature", "gCodeVisualizer"]), - "waitForStart": s.getBoolean(["feature", "waitForStartOnConnect"]) + "waitForStart": s.getBoolean(["feature", "waitForStartOnConnect"]), + "alwaysSendChecksum": s.getBoolean(["feature", "alwaysSendChecksum"]) }, "folder": { "uploads": s.getBaseFolder("uploads"), @@ -401,6 +402,7 @@ def setSettings(): if "feature" in data.keys(): if "gcodeViewer" in data["feature"].keys(): s.setBoolean(["feature", "gCodeVisualizer"], data["feature"]["gcodeViewer"]) if "waitForStart" in data["feature"].keys(): s.setBoolean(["feature", "waitForStartOnConnect"], data["feature"]["waitForStart"]) + if "alwaysSendChecksum" in data["feature"].keys(): s.setBoolean(["feature", "alwaysSendChecksum"], data["feature"]["alwaysSendChecksum"]) if "folder" in data.keys(): if "uploads" in data["folder"].keys(): s.setBaseFolder("uploads", data["folder"]["uploads"]) diff --git a/octoprint/settings.py b/octoprint/settings.py index 0c7dfad..93a94d1 100644 --- a/octoprint/settings.py +++ b/octoprint/settings.py @@ -39,7 +39,8 @@ default_settings = { }, "feature": { "gCodeVisualizer": True, - "waitForStartOnConnect": False + "waitForStartOnConnect": False, + "alwaysSendChecksum": False }, "folder": { "uploads": None, diff --git a/octoprint/static/js/ui.js b/octoprint/static/js/ui.js index 48df520..7b0942d 100644 --- a/octoprint/static/js/ui.js +++ b/octoprint/static/js/ui.js @@ -959,6 +959,7 @@ function SettingsViewModel() { self.feature_gcodeViewer = ko.observable(undefined); self.feature_waitForStart = ko.observable(undefined); + self.feature_alwaysSendChecksum = ko.observable(undefined); self.folder_uploads = ko.observable(undefined); self.folder_timelapse = ko.observable(undefined); @@ -1003,6 +1004,7 @@ function SettingsViewModel() { self.feature_gcodeViewer(response.feature.gcodeViewer); self.feature_waitForStart(response.feature.waitForStart); + self.feature_alwaysSendChecksum(response.feature.alwaysSendChecksum); self.folder_uploads(response.folder.uploads); self.folder_timelapse(response.folder.timelapse); @@ -1035,7 +1037,8 @@ function SettingsViewModel() { }, "feature": { "gcodeViewer": self.feature_gcodeViewer(), - "waitForStart": self.feature_waitForStart() + "waitForStart": self.feature_waitForStart(), + "alwaysSendChecksum": self.feature_alwaysSendChecksum() }, "folder": { "uploads": self.folder_uploads(), diff --git a/octoprint/templates/settings.html b/octoprint/templates/settings.html index 9e93f1e..80a4840 100644 --- a/octoprint/templates/settings.html +++ b/octoprint/templates/settings.html @@ -106,6 +106,13 @@ +
+
+ +
+
diff --git a/octoprint/util/comm.py b/octoprint/util/comm.py index 00d63fe..807b86a 100644 --- a/octoprint/util/comm.py +++ b/octoprint/util/comm.py @@ -174,7 +174,10 @@ class MachineCom(object): self._heatupWaitStartTime = 0 self._heatupWaitTimeLost = 0.0 self._printStartTime100 = None - + + self._alwaysSendChecksum = settings().getBoolean(["feature", "alwaysSendChecksum"]) + self._currentLine = 0 + self.thread = threading.Thread(target=self._monitor) self.thread.daemon = True self.thread.start() @@ -344,7 +347,7 @@ class MachineCom(object): 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(): + 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) if self._state == self.STATE_DETECT_BAUDRATE: @@ -385,28 +388,28 @@ class MachineCom(object): else: self._testingBaudrate = False elif self._state == self.STATE_CONNECTING: - if line == '' and startSeen: + if (line == "" or "wait" in line) and startSeen: self._sendCommand("M105") - elif 'start' in line: + elif "start" in line: startSeen = True - elif 'ok' in line and startSeen: + 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 == '': + if line == "" or "wait" in line: self._sendCommand("M105") tempRequestTimeout = time.time() + 5 elif self._state == self.STATE_PRINTING: - if line == '' and time.time() > timeout: + if line == "" and time.time() > timeout: self._log("Communication timeout during printing, forcing a line") - line = 'ok' + 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: + if "ok" in line: timeout = time.time() + 5 if not self._commandQueue.empty(): self._sendCommand(self._commandQueue.get()) @@ -460,7 +463,7 @@ class MachineCom(object): def __del__(self): self.close() - def _sendCommand(self, cmd): + def _sendCommand(self, cmd, sendChecksum=False): cmd = cmd.upper() if self._serial is None: return @@ -476,13 +479,23 @@ class MachineCom(object): self._bedTargetTemp = float(re.search('S([0-9]+)', cmd).group(1)) except: pass - self._log('Send: %s' % (cmd)) + + commandToSend = cmd + self._currentLine += 1 + if sendChecksum or self._alwaysSendChecksum: + lineNumber = self._gcodePos + if self._alwaysSendChecksum: + lineNumber = self._currentLine + checksum = reduce(lambda x,y:x^y, map(ord, "N%d%s" % (lineNumber, cmd))) + commandToSend = "N%d%s*%d" % (lineNumber, cmd, checksum) + + self._log('Send: %s' % (commandToSend)) try: - self._serial.write(cmd + '\n') + self._serial.write(commandToSend + '\n') except serial.SerialTimeoutException: self._log("Serial timeout while writing to serial port, trying again.") try: - self._serial.write(cmd + '\n') + self._serial.write(commandToSend + '\n') except: self._log("Unexpected error while writing serial port: %s" % (getExceptionString())) self._errorValue = getExceptionString() @@ -491,7 +504,16 @@ class MachineCom(object): self._log("Unexpected error while writing serial port: %s" % (getExceptionString())) self._errorValue = getExceptionString() self.close(True) - + finally: + if "M110" in cmd: + if " N" in cmd: + try: + self._currentLine = int(re.search("N([0-9]+)", cmd).group(1)) + except: + pass + else: + self._currentLine = 0 + def _sendNext(self): if self._gcodePos >= len(self._gcodeList): self._changeState(self.STATE_OPERATIONAL) @@ -515,8 +537,7 @@ class MachineCom(object): self._callback.mcZChange(z) except: self._log("Unexpected error: %s" % (getExceptionString())) - checksum = reduce(lambda x,y:x^y, map(ord, "N%d%s" % (self._gcodePos, line))) - self._sendCommand("N%d%s*%d" % (self._gcodePos, line, checksum)) + self._sendCommand(line, True) self._gcodePos += 1 self._callback.mcProgress(self._gcodePos)