diff --git a/docs/configuration/config_yaml.rst b/docs/configuration/config_yaml.rst index dc513fa9..27a20352 100644 --- a/docs/configuration/config_yaml.rst +++ b/docs/configuration/config_yaml.rst @@ -613,8 +613,30 @@ Use the following settings to configure the serial connection to the printer: # Use this to define additional baud rates to offer for connecting to serial ports. Must be a # valid integer. Defaults to not set + additionalBaudrates: - 123456 + # Commands which are known to take a long time to be acknowledged by the firmware. E.g. + # homing, dwelling, auto leveling etc. Defaults to the below commands. + longRunningCommands: + - G4 + - G28 + - G29 + - G30 + - G32 + - M400 + - M226 + + # Commands which need to always be send with a checksum. Defaults to only M110 + checksumRequiringCommands: + - M110 + + # Command to send in order to initiate a handshake with the printer. + # Defaults to "M110 N0" which simply resets the line numbers in the firmware and which + # should be acknowledged with a simple "ok". + helloCommand: + - M110 N0 + .. _sec-configuration-config_yaml-server: Server diff --git a/src/octoprint/settings.py b/src/octoprint/settings.py index 86d722b9..d20b56b9 100644 --- a/src/octoprint/settings.py +++ b/src/octoprint/settings.py @@ -84,7 +84,9 @@ default_settings = { }, "additionalPorts": [], "additionalBaudrates": [], - "longRunningCommands": ["G4", "G28", "G29", "G30", "G32", "M400", "M226"] + "longRunningCommands": ["G4", "G28", "G29", "G30", "G32", "M400", "M226"], + "checksumRequiringCommands": ["M110"], + "helloCommand": "M110 N0" }, "server": { "host": "0.0.0.0", diff --git a/src/octoprint/util/comm.py b/src/octoprint/util/comm.py index c13abc78..31f3cb3e 100644 --- a/src/octoprint/util/comm.py +++ b/src/octoprint/util/comm.py @@ -165,6 +165,8 @@ class MachineCom(object): self._timeout = None + self._hello_command = settings().get(["serial", "helloCommand"]) + self._alwaysSendChecksum = settings().getBoolean(["feature", "alwaysSendChecksum"]) self._sendChecksumWithUnknownCommands = settings().getBoolean(["feature", "sendChecksumWithUnknownCommands"]) self._unknownCommandsNeedAck = settings().getBoolean(["feature", "unknownCommandsNeedAck"]) @@ -175,6 +177,7 @@ class MachineCom(object): self._lastResendNumber = None self._currentResendCount = 0 self._resendSwallowNextOk = False + self._checksum_requiring_commands = settings().get(["serial", "checksumRequiringCommands"]) self._clear_to_send = CountedEvent(max=10, name="comm.clear_to_send") self._send_queue = TypedQueue() @@ -478,7 +481,7 @@ class MachineCom(object): def fakeOk(self): self._clear_to_send.set() - def sendCommand(self, cmd, cmd_type=None, processed=False): + def sendCommand(self, cmd, cmd_type=None, processed=False, force=False): cmd = cmd.encode('ascii', 'replace') if not processed: cmd = process_gcode_line(cmd) @@ -487,7 +490,7 @@ class MachineCom(object): if self.isPrinting() and not self.isSdFileSelected(): self._commandQueue.put((cmd, cmd_type)) - elif self.isOperational(): + elif self.isOperational() or force: self._sendCommand(cmd, cmd_type=cmd_type) def sendGcodeScript(self, scriptName, replacements=None): @@ -559,7 +562,7 @@ class MachineCom(object): self._changeState(self.STATE_PRINTING) - self.sendCommand("M110 N0") + self.resetLineNumbers() payload = { "file": self._currentFile.getFilename(), @@ -757,6 +760,16 @@ class MachineCom(object): self._callback.on_comm_sd_state_change(self._sdAvailable) self._callback.on_comm_sd_files(self._sdFiles) + def sayHello(self): + self.sendCommand(self._hello_command, force=True) + self._clear_to_send.set() + + def resetLineNumbers(self, number=0): + if not self.isOperational(): + return + + self.sendCommand("M110 N%d" % number) + ##~~ communication monitoring and handling def _parseTemperatures(self, line): @@ -865,10 +878,9 @@ class MachineCom(object): connection_timeout = settings().getFloat(["serial", "timeout", "connection"]) detection_timeout = settings().getFloat(["serial", "timeout", "detection"]) - # enqueue an M105 first thing + # enqueue the "hello command" first thing if try_hello: - self._sendCommand("M110") - self._clear_to_send.set() + self.sayHello() while self._monitoring_active: try: @@ -1089,8 +1101,7 @@ class MachineCom(object): self._baudrateDetectRetry -= 1 self._serial.write('\n') self._log("Baudrate test retry: %d" % (self._baudrateDetectRetry)) - self._sendCommand("M110") - self._clear_to_send.set() + self.sayHello() elif len(self._baudrateDetectList) > 0: baudrate = self._baudrateDetectList.pop(0) try: @@ -1101,8 +1112,7 @@ class MachineCom(object): self._baudrateDetectRetry = 5 self._timeout = get_new_timeout("communication") self._serial.write('\n') - self._sendCommand("M110") - self._clear_to_send.set() + self.sayHello() except: self._log("Unexpected error while setting baudrate: %d %s" % (baudrate, get_exception_string())) else: @@ -1118,8 +1128,7 @@ class MachineCom(object): elif self._state == self.STATE_CONNECTING: if "start" in line and not startSeen: startSeen = True - self._sendCommand("M110") - self._clear_to_send.set() + self.sayHello() elif "ok" in line: self._onConnected() elif time.time() > self._timeout: @@ -1241,6 +1250,8 @@ class MachineCom(object): self._changeState(self.STATE_OPERATIONAL) + self.resetLineNumbers() + if self._sdAvailable: self.refreshSdFiles() else: @@ -1588,7 +1599,11 @@ class MachineCom(object): continue # now comes the part where we increase line numbers and send stuff - no turning back now - if (gcode is not None or self._sendChecksumWithUnknownCommands) and (self.isPrinting() or self._alwaysSendChecksum): + command_requiring_checksum = gcode is not None and gcode in self._checksum_requiring_commands + command_allowing_checksum = gcode is not None or self._sendChecksumWithUnknownCommands + checksum_enabled = self.isPrinting() or self._alwaysSendChecksum + + if command_requiring_checksum or (command_allowing_checksum and checksum_enabled): linenumber = self._currentLine self._addToLastLines(command) self._currentLine += 1