From 48d74ef2fd1dfad437a573ba9e76bfa2d3abd621 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gina=20H=C3=A4u=C3=9Fge?= Date: Thu, 13 Aug 2015 13:07:18 +0200 Subject: [PATCH] Improved handshake procedure on comm layer "Hello" command sent to printer to trigger initial handshake can now be configured. Commands that _always_ necessitate to be sent with checksum/ line number (e.g. M110 on Marlin) can be configured as such too. Also fixed an issue causing the "Hello" command to not be actually enqueued first thing on opening a connection. Seems to not have caused harm in the wild, but was unintentional. (cherry picked from commit 5c2ae37) --- docs/configuration/config_yaml.rst | 21 +++++++++++++ src/octoprint/settings.py | 1 + src/octoprint/util/comm.py | 47 +++++++++++++++++++----------- 3 files changed, 52 insertions(+), 17 deletions(-) diff --git a/docs/configuration/config_yaml.rst b/docs/configuration/config_yaml.rst index e182e6bb..2b75ba93 100644 --- a/docs/configuration/config_yaml.rst +++ b/docs/configuration/config_yaml.rst @@ -611,6 +611,27 @@ Use the following settings to configure the serial connection to the printer: additionalPorts: - /dev/myPrinterSymlink + # 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 9454e483..38a197f0 100644 --- a/src/octoprint/settings.py +++ b/src/octoprint/settings.py @@ -86,6 +86,7 @@ default_settings = { }, "additionalPorts": [], "longRunningCommands": ["G4", "G28", "G29", "G30", "G32"], + "checksumRequiringCommands": ["M110"], "disconnectOnErrors": True, "ignoreErrorsFromFirmware": False }, diff --git a/src/octoprint/util/comm.py b/src/octoprint/util/comm.py index 6bea89a9..4cb8894d 100644 --- a/src/octoprint/util/comm.py +++ b/src/octoprint/util/comm.py @@ -229,6 +229,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"]) @@ -246,6 +248,9 @@ class MachineCom(object): self._disconnect_on_errors = settings().getBoolean(["serial", "disconnectOnErrors"]) self._ignore_errors = settings().getBoolean(["serial", "ignoreErrorsFromFirmware"]) + self._long_running_commands = settings().get(["serial", "longRunningCommands"]) + self._checksum_requiring_commands = settings().get(["serial", "checksumRequiringCommands"]) + self._clear_to_send = CountedEvent(max=10, name="comm.clear_to_send") self._send_queue = TypedQueue() self._temperature_timer = None @@ -277,10 +282,6 @@ class MachineCom(object): # print job self._currentFile = None - # regexes - - self._long_running_commands = settings().get(["serial", "longRunningCommands"]) - # multithreading locks self._sendNextLock = threading.Lock() self._sendingLock = threading.RLock() @@ -498,7 +499,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 = to_unicode(cmd, errors="replace") if not processed: cmd = process_gcode_line(cmd) @@ -507,7 +508,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): @@ -579,7 +580,7 @@ class MachineCom(object): self._changeState(self.STATE_PRINTING) - self.sendCommand("M110 N0") + self.resetLineNumbers() payload = { "file": self._currentFile.getFilename(), @@ -809,6 +810,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) + ##~~ record aborted file positions def _recordFilePosition(self): @@ -887,10 +898,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: @@ -1122,8 +1132,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: @@ -1134,8 +1143,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: @@ -1151,8 +1159,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 line.startswith("ok"): self._onConnected() elif time.time() > self._timeout: @@ -1276,6 +1283,8 @@ class MachineCom(object): self._changeState(self.STATE_OPERATIONAL) + self.resetLineNumbers() + if self._sdAvailable: self.refreshSdFiles() else: @@ -1653,8 +1662,12 @@ class MachineCom(object): continue # now comes the part where we increase line numbers and send stuff - no turning back now + 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 + command_to_send = command.encode("ascii", errors="replace") - if (gcode is not None or self._sendChecksumWithUnknownCommands) and (self.isPrinting() or self._alwaysSendChecksum): + if command_requiring_checksum or (command_allowing_checksum and checksum_enabled): self._doIncrementAndSendWithChecksum(command_to_send) else: self._doSendWithoutChecksum(command_to_send)