Handling of non gcode SD file transfers

No guarantees however that transporting anything BUT gcode via the usual
M28/M29 interface will even remotely work. Note that it most likely
won't work if the transferred file contains an M29 (= end transfer),
just like with transferred GCODE files.

Also note that stuff like config files or some such that might be
transferred might contain lines that are too large to fit into the
buffer of the printer. This is really just to enable plugins to maybe do
some nifty stuff, no official support of streaming arbitrary files to
the printer's SD (for that we'd need WAY more firmware support first).

See jneilliii/OctoPrint-SmoothiewareConfig#1
This commit is contained in:
Gina Häußge 2017-11-24 13:11:23 +01:00
parent 9b3c1947d9
commit 0de0e4ea9b
2 changed files with 36 additions and 8 deletions

View file

@ -595,12 +595,16 @@ class Printer(PrinterInterface, comm.MachineComPrintCallback):
self.refresh_sd_files(blocking=True)
existingSdFiles = map(lambda x: x[0], self._comm.getSdFiles())
remoteName = util.get_dos_filename(filename,
existing_filenames=existingSdFiles,
extension="gco",
whitelisted_extensions=["gco", "g"])
if valid_file_type(filename, "gcode"):
remoteName = util.get_dos_filename(filename,
existing_filenames=existingSdFiles,
extension="gco",
whitelisted_extensions=["gco", "g"])
else:
# probably something else added through a plugin, use it's basename as-is
remoteName = os.path.basename(filename)
self._timeEstimationData = TimeEstimationHelper()
self._comm.startFileTransfer(absolutePath, filename, "/" + remoteName)
self._comm.startFileTransfer(absolutePath, filename, "/" + remoteName, special=not valid_file_type(filename, "gcode"))
return remoteName

View file

@ -877,7 +877,7 @@ class MachineCom(object):
self._changeState(self.STATE_ERROR)
eventManager().fire(Events.ERROR, {"error": self.getErrorString()})
def startFileTransfer(self, filename, localFilename, remoteFilename):
def startFileTransfer(self, filename, localFilename, remoteFilename, special=False):
if not self.isOperational() or self.isBusy():
self._logger.info("Printer is not operational or busy")
return
@ -885,7 +885,10 @@ class MachineCom(object):
with self._jobLock:
self.resetLineNumbers()
self._currentFile = StreamingGcodeFileInformation(filename, localFilename, remoteFilename)
if special:
self._currentFile = SpecialStreamingGcodeFileInformation(filename, localFilename, remoteFilename)
else:
self._currentFile = StreamingGcodeFileInformation(filename, localFilename, remoteFilename)
self._currentFile.start()
self.sendCommand("M28 %s" % remoteFilename)
@ -2356,7 +2359,7 @@ class MachineCom(object):
# 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 = not self._neverSendChecksum and (self.isPrinting() or
checksum_enabled = not self._neverSendChecksum and ((self.isPrinting() and self._currentFile and self._currentFile.checksum) or
self._alwaysSendChecksum or
not self._firmware_info_received)
@ -2825,6 +2828,8 @@ class PrintingFileInformation(object):
value between 0 and 1.
"""
checksum = True
def __init__(self, filename):
self._logger = logging.getLogger(__name__)
self._filename = filename
@ -2879,6 +2884,8 @@ class PrintingSdFileInformation(PrintingFileInformation):
Encapsulates information regarding an ongoing print from SD.
"""
checksum = False
def __init__(self, filename, size):
PrintingFileInformation.__init__(self, filename)
self._size = size
@ -3025,6 +3032,23 @@ class StreamingGcodeFileInformation(PrintingGcodeFileInformation):
self._logger.info("Finished in {duration:.3f} s. Approx. transfer rate of {rate:.3f} lines/s or {time_per_line:.3f} ms per line".format(**stats))
class SpecialStreamingGcodeFileInformation(StreamingGcodeFileInformation):
"""
For streaming files to the printer that aren't GCODE.
Difference to regular StreamingGcodeFileInformation: no checksum requirement, only rudimentary line processing
(stripping of whitespace from the end and ignoring of empty lines)
"""
checksum = False
def _process(self, line, offsets, current_tool):
line = line.rstrip()
if not len(line):
return None
return line
class SendQueue(PrependableQueue):
def __init__(self, maxsize=0):