Allow specification of known long running commands through settings

This should allow users to adjust the behaviour of the communication stack more granularly in case the regular settings which only consider G4, G28, G29, G30, G32 to be real long runners without output are not sufficient.
This commit is contained in:
Gina Häußge 2015-06-03 12:34:00 +02:00
parent d2bca10ac9
commit b714c59004
7 changed files with 45 additions and 24 deletions

View file

@ -153,7 +153,8 @@
``python setup.py sdist``
* [#330](https://github.com/foosel/OctoPrint/issues/330) - Ping pong sending to fix potential acknowledgement errors.
Also affects [#166](https://github.com/foosel/OctoPrint/issues/166), [#470](https://github.com/foosel/OctoPrint/issues/470)
and [#490](https://github.com/foosel/OctoPrint/issues/490).
and [#490](https://github.com/foosel/OctoPrint/issues/490). A big thank you to all people involved in these tickets
in getting to the ground of this.
* [#825](https://github.com/foosel/OctoPrint/issues/825) - Fixed "please visualize" button of large GCODE files
* Various fixes of bugs in newly introduced features and improvements:
* [#625](https://github.com/foosel/OctoPrint/pull/625) - Newly added GCODE files were not being added to the analysis

View file

@ -80,7 +80,8 @@ def getSettings():
"timeoutTemperature": s.getFloat(["serial", "timeout", "temperature"]),
"timeoutSdStatus": s.getFloat(["serial", "timeout", "sdStatus"]),
"log": s.getBoolean(["serial", "log"]),
"additionalPorts": s.get(["serial", "additionalPorts"])
"additionalPorts": s.get(["serial", "additionalPorts"]),
"longRunningCommands": s.get(["serial", "longRunningCommands"])
},
"folder": {
"uploads": s.getBaseFolder("uploads"),
@ -192,6 +193,7 @@ def setSettings():
if "timeoutTemperature" in data["serial"].keys(): s.setFloat(["serial", "timeout", "temperature"], data["serial"]["timeoutTemperature"])
if "timeoutSdStatus" in data["serial"].keys(): s.setFloat(["serial", "timeout", "sdStatus"], data["serial"]["timeoutSdStatus"])
if "additionalPorts" in data["serial"] and isinstance(data["serial"]["additionalPorts"], (list, tuple)): s.set(["serial", "additionalPorts"], data["serial"]["additionalPorts"])
if "longRunningCommands" in data["serial"] and isinstance(data["serial"]["longRunningCommands"], (list, tuple)): s.set(["serial", "longRunningCommands"], data["serial"]["longRunningCommands"])
oldLog = s.getBoolean(["serial", "log"])
if "log" in data["serial"].keys(): s.setBoolean(["serial", "log"], data["serial"]["log"])

View file

@ -82,7 +82,8 @@ default_settings = {
"temperature": 5,
"sdStatus": 1
},
"additionalPorts": []
"additionalPorts": [],
"longRunningCommands": ["G4", "G28", "G29", "G30", "G32"]
},
"server": {
"host": "0.0.0.0",

View file

@ -447,3 +447,17 @@ function showConfirmationDialog(message, onacknowledge) {
});
confirmationDialog.modal("show");
}
function commentableLinesToArray(lines) {
return splitTextToArray(lines, "\n", true, function(item) {return !_.startsWith(item, "#")});
}
function splitTextToArray(text, sep, stripEmpty, filter) {
return _.filter(
_.map(
text.split(sep),
function(item) { return (item) ? item.trim() : ""; }
),
function(item) { return (stripEmpty ? item : true) && (filter ? filter(item) : true); }
);
}

View file

@ -126,6 +126,7 @@ $(function() {
self.serial_timeoutSdStatus = ko.observable(undefined);
self.serial_log = ko.observable(undefined);
self.serial_additionalPorts = ko.observable(undefined);
self.serial_longRunningCommands = ko.observable(undefined);
self.folder_uploads = ko.observable(undefined);
self.folder_timelapse = ko.observable(undefined);
@ -385,6 +386,7 @@ $(function() {
self.serial_timeoutSdStatus(response.serial.timeoutSdStatus);
self.serial_log(response.serial.log);
self.serial_additionalPorts(response.serial.additionalPorts.join("\n"));
self.serial_longRunningCommands(response.serial.longRunningCommands.join(", "));
self.folder_uploads(response.folder.uploads);
self.folder_timelapse(response.folder.timelapse);
@ -462,13 +464,8 @@ $(function() {
"timeoutTemperature": self.serial_timeoutTemperature(),
"timeoutSdStatus": self.serial_timeoutSdStatus(),
"log": self.serial_log(),
"additionalPorts": _.filter(
_.map(
self.serial_additionalPorts().split("\n"),
function(item) { return (item) ? item.trim() : ""; }
),
function(item) { return item && !_.startsWith(item, "#"); }
)
"additionalPorts": commentableLinesToArray(self.serial_additionalPorts()),
"longRunningCommands": splitTextToArray(self.serial_longRunningCommands(), ",", true)
},
"folder": {
"uploads": self.folder_uploads(),

View file

@ -70,6 +70,13 @@
</label>
</div>
</div>
<div class="control-group">
<label class="control-label" for="settings-serialLongRunningCommands">{{ _('Long running commands') }}</label>
<div class="controls">
<input type="text" class="input-block-level" id="settings-serialLongRunningCommands" data-bind="value: serial_longRunningCommands">
<span class="help-inline">{{ _('Use this to specify the commands known to take a long time to complete without output from your printer and hence might cause timeout issues. Just the G or M code, comma separated.')|format(glob_url="http://docs.python.org/2/library/glob.html") }}</span>
</div>
</div>
<div class="control-group">
<label class="control-label" for="settings-serialAdditionalPorts">{{ _('Additional serial ports') }}</label>
<div class="controls">

View file

@ -149,7 +149,7 @@ class MachineCom(object):
self._pauseWaitTimeLost = 0.0
self._currentTool = 0
self._blocking_command = False
self._long_running_command = False
self._heating = False
self._timeout = None
@ -218,7 +218,7 @@ class MachineCom(object):
self._regex_repetierTempExtr = re.compile("TargetExtr([0-9]+):(%s)" % positiveFloatPattern)
self._regex_repetierTempBed = re.compile("TargetBed:(%s)" % positiveFloatPattern)
self._blocking_commands = ("G28", "G29", "G30", "G32")
self._long_running_commands = settings().get(["serial", "longRunningCommands"])
# multithreading locks
self._sendNextLock = threading.Lock()
@ -883,7 +883,7 @@ class MachineCom(object):
##~~ process oks
if line.strip().startswith("ok") or (self.isPrinting() and supportWait and line.strip().startswith("wait")):
self._clear_to_send.set()
self._blocking_command = False
self._long_running_command = False
##~~ Temperature processing
if ' T:' in line or line.startswith('T:') or ' T0:' in line or line.startswith('T0:') or ' B:' in line or line.startswith('B:'):
@ -1088,12 +1088,12 @@ class MachineCom(object):
### Printing
elif self._state == self.STATE_PRINTING:
if line == "" and time.time() > self._timeout:
if not self._blocking_command:
if not self._long_running_command:
self._log("Communication timeout during printing, forcing a line")
self._sendCommand("M105")
self._clear_to_send.set()
else:
self._logger.debug("Ran into a communication timeout, but a blocking command is currently active")
self._logger.debug("Ran into a communication timeout, but a command known to be a long runner is currently active")
if "ok" in line or (supportWait and "wait" in line):
# a wait while printing means our printer's buffer ran out, probably due to some ok getting
@ -1161,22 +1161,22 @@ class MachineCom(object):
"""
Polls the temperature after the temperature timeout, re-enqueues itself.
If the printer is not operational, not printing from sd, busy with a blocking command or heating, no poll
If the printer is not operational, not printing from sd, busy with a long running command or heating, no poll
will be done.
"""
if self.isOperational() and not self.isStreaming() and not self._blocking_command and not self._heating:
if self.isOperational() and not self.isStreaming() and not self._long_running_command and not self._heating:
self.sendCommand("M105", cmd_type="temperature_poll")
def _poll_sd_status(self):
"""
Polls the sd printing status after the sd status timeout, re-enqueues itself.
If the printer is not operational, not printing from sd, busy with a blocking command or heating, no poll
If the printer is not operational, not printing from sd, busy with a long running command or heating, no poll
will be done.
"""
if self.isOperational() and self.isSdPrinting() and not self._blocking_command and not self._heating:
if self.isOperational() and self.isSdPrinting() and not self._long_running_command and not self._heating:
self.sendCommand("M27", cmd_type="sd_status_poll")
def _onConnected(self):
@ -1693,13 +1693,13 @@ class MachineCom(object):
def _gcode_M109_sent(self, cmd, cmd_type=None):
self._heatupWaitStartTime = time.time()
self._blocking_command = True
self._long_running_command = True
self._heating = True
self._gcode_M104_sent(cmd, cmd_type)
def _gcode_M190_sent(self, cmd, cmd_type=None):
self._heatupWaitStartTime = time.time()
self._blocking_command = True
self._long_running_command = True
self._heating = True
self._gcode_M140_sent(cmd, cmd_type)
@ -1737,13 +1737,12 @@ class MachineCom(object):
# dwell time is specified in seconds
_timeout = float(cmd[s_idx+1:])
self._timeout = get_new_timeout("communication") + _timeout
self._blocking_command = True
##~~ command phase handlers
def _command_phase_sending(self, cmd, cmd_type=None, gcode=None):
if gcode is not None and gcode in self._blocking_commands:
self._blocking_command = True
if gcode is not None and gcode in self._long_running_commands:
self._long_running_command = True
### MachineCom callback ################################################################################################