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)
This commit is contained in:
Gina Häußge 2015-08-13 13:07:18 +02:00
parent 35e20162ec
commit 48d74ef2fd
3 changed files with 52 additions and 17 deletions

View file

@ -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

View file

@ -86,6 +86,7 @@ default_settings = {
},
"additionalPorts": [],
"longRunningCommands": ["G4", "G28", "G29", "G30", "G32"],
"checksumRequiringCommands": ["M110"],
"disconnectOnErrors": True,
"ignoreErrorsFromFirmware": False
},

View file

@ -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)