Changed SD filename generation, made SD handling more reliable as a whole
This commit is contained in:
parent
63555d2c4b
commit
717ec0419f
8 changed files with 139 additions and 31 deletions
|
|
@ -69,6 +69,7 @@ class Printer():
|
|||
# sd handling
|
||||
self._sdPrinting = False
|
||||
self._sdStreaming = False
|
||||
self._sdFilelistAvailable = threading.Event()
|
||||
|
||||
self._selectedFile = None
|
||||
|
||||
|
|
@ -432,6 +433,7 @@ class Printer():
|
|||
|
||||
def mcSdFiles(self, files):
|
||||
self._sendTriggerUpdateCallbacks("gcodeFiles")
|
||||
self._sdFilelistAvailable.set()
|
||||
|
||||
def mcFileSelected(self, filename, filesize, sd):
|
||||
self._setJobData(filename, filesize, sd)
|
||||
|
|
@ -465,34 +467,47 @@ class Printer():
|
|||
#~~ sd file handling
|
||||
|
||||
def getSdFiles(self):
|
||||
if self._comm is None:
|
||||
return
|
||||
if self._comm is None or not self._comm.isSdReady():
|
||||
return []
|
||||
return self._comm.getSdFiles()
|
||||
|
||||
def addSdFile(self, filename, path):
|
||||
if not self._comm or self._comm.isBusy():
|
||||
if not self._comm or self._comm.isBusy() or not self._comm.isSdReady():
|
||||
return
|
||||
self._comm.startFileTransfer(path, filename[:8].lower() + ".gco")
|
||||
|
||||
self.refreshSdFiles(blocking=True)
|
||||
existingSdFiles = self._comm.getSdFiles()
|
||||
|
||||
sdFilename = util.getDosFilename(filename, existingSdFiles)
|
||||
self._comm.startFileTransfer(path, sdFilename)
|
||||
|
||||
def deleteSdFile(self, filename):
|
||||
if not self._comm:
|
||||
if not self._comm or not self._comm.isSdReady():
|
||||
return
|
||||
self._comm.deleteSdFile(filename)
|
||||
|
||||
def initSdCard(self):
|
||||
if not self._comm:
|
||||
if not self._comm or self._comm.isSdReady():
|
||||
return
|
||||
self._comm.initSdCard()
|
||||
|
||||
def releaseSdCard(self):
|
||||
if not self._comm:
|
||||
if not self._comm or not self._comm.isSdReady():
|
||||
return
|
||||
self._comm.releaseSdCard()
|
||||
|
||||
def refreshSdFiles(self):
|
||||
if not self._comm:
|
||||
def refreshSdFiles(self, blocking=False):
|
||||
"""
|
||||
Refreshs the list of file stored on the SD card attached to printer (if available and printer communication
|
||||
available). Optional blocking parameter allows making the method block (max 10s) until the file list has been
|
||||
received (and can be accessed via self._comm.getSdFiles()). Defaults to a asynchronous operation.
|
||||
"""
|
||||
if not self._comm or not self._comm.isSdReady():
|
||||
return
|
||||
self._sdFilelistAvailable.clear()
|
||||
self._comm.refreshSdFiles()
|
||||
if blocking:
|
||||
self._sdFilelistAvailable.wait(10000)
|
||||
|
||||
#~~ state reports
|
||||
|
||||
|
|
|
|||
|
|
@ -451,7 +451,7 @@ def deleteGcodeFile():
|
|||
printer.unselectFile()
|
||||
|
||||
if not (currentFilename == filename and currentSd == sd and (printer.isPrinting() or printer.isPaused())):
|
||||
if currentSd:
|
||||
if sd:
|
||||
printer.deleteSdFile(filename)
|
||||
else:
|
||||
gcodeManager.removeFile(filename)
|
||||
|
|
|
|||
|
|
@ -82,23 +82,29 @@ $(function() {
|
|||
}
|
||||
}
|
||||
|
||||
var localTarget;
|
||||
if (CONFIG_SD_SUPPORT) {
|
||||
localTarget = $("#drop_locally");
|
||||
} else {
|
||||
localTarget = $("#drop");
|
||||
function enable_local_dropzone() {
|
||||
$("#gcode_upload").fileupload({
|
||||
dataType: "json",
|
||||
dropZone: localTarget,
|
||||
formData: {target: "local"},
|
||||
done: gcode_upload_done,
|
||||
fail: gcode_upload_fail,
|
||||
progressall: gcode_upload_progress
|
||||
});
|
||||
}
|
||||
|
||||
$("#gcode_upload").fileupload({
|
||||
dataType: "json",
|
||||
dropZone: localTarget,
|
||||
formData: {target: "local"},
|
||||
done: gcode_upload_done,
|
||||
fail: gcode_upload_fail,
|
||||
progressall: gcode_upload_progress
|
||||
});
|
||||
function disable_local_dropzone() {
|
||||
$("#gcode_upload").fileupload({
|
||||
dataType: "json",
|
||||
dropZone: null,
|
||||
formData: {target: "local"},
|
||||
done: gcode_upload_done,
|
||||
fail: gcode_upload_fail,
|
||||
progressall: gcode_upload_progress
|
||||
});
|
||||
}
|
||||
|
||||
if (CONFIG_SD_SUPPORT) {
|
||||
function enable_sd_dropzone() {
|
||||
$("#gcode_upload_sd").fileupload({
|
||||
dataType: "json",
|
||||
dropZone: $("#drop_sd"),
|
||||
|
|
@ -109,6 +115,62 @@ $(function() {
|
|||
});
|
||||
}
|
||||
|
||||
function disable_sd_dropzone() {
|
||||
$("#gcode_upload_sd").fileupload({
|
||||
dataType: "json",
|
||||
dropZone: null,
|
||||
formData: {target: "sd"},
|
||||
done: gcode_upload_done,
|
||||
fail: gcode_upload_fail,
|
||||
progressall: gcode_upload_progress
|
||||
});
|
||||
}
|
||||
|
||||
var localTarget;
|
||||
if (CONFIG_SD_SUPPORT) {
|
||||
localTarget = $("#drop_locally");
|
||||
} else {
|
||||
localTarget = $("#drop");
|
||||
}
|
||||
|
||||
loginStateViewModel.isUser.subscribe(function(newValue) {
|
||||
if (newValue === true) {
|
||||
enable_local_dropzone();
|
||||
} else {
|
||||
disable_local_dropzone();
|
||||
}
|
||||
});
|
||||
|
||||
if (loginStateViewModel.isUser()) {
|
||||
enable_local_dropzone();
|
||||
} else {
|
||||
disable_local_dropzone();
|
||||
}
|
||||
|
||||
if (CONFIG_SD_SUPPORT) {
|
||||
printerStateViewModel.isSdReady.subscribe(function(newValue) {
|
||||
if (newValue === true && loginStateViewModel.isUser()) {
|
||||
enable_sd_dropzone();
|
||||
} else {
|
||||
disable_sd_dropzone();
|
||||
}
|
||||
});
|
||||
|
||||
loginStateViewModel.isUser.subscribe(function(newValue) {
|
||||
if (newValue === true && printerStateViewModel.isSdReady()) {
|
||||
enable_sd_dropzone();
|
||||
} else {
|
||||
disable_sd_dropzone();
|
||||
}
|
||||
});
|
||||
|
||||
if (printerStateViewModel.isSdReady() && loginStateViewModel.isUser()) {
|
||||
enable_sd_dropzone();
|
||||
} else {
|
||||
disable_sd_dropzone();
|
||||
}
|
||||
}
|
||||
|
||||
$(document).bind("dragover", function (e) {
|
||||
var dropOverlay = $("#drop_overlay");
|
||||
var dropZone = $("#drop");
|
||||
|
|
@ -146,7 +208,7 @@ $(function() {
|
|||
if (foundLocal) {
|
||||
dropZoneLocalBackground.addClass("hover");
|
||||
dropZoneSdBackground.removeClass("hover");
|
||||
} else if (foundSd) {
|
||||
} else if (foundSd && printerStateViewModel.isSdReady()) {
|
||||
dropZoneSdBackground.addClass("hover");
|
||||
dropZoneLocalBackground.removeClass("hover");
|
||||
} else if (found) {
|
||||
|
|
@ -201,7 +263,7 @@ $(function() {
|
|||
ko.applyBindings(settingsViewModel, document.getElementById("settings_dialog"));
|
||||
ko.applyBindings(navigationViewModel, document.getElementById("navbar"));
|
||||
ko.applyBindings(appearanceViewModel, document.getElementsByTagName("head")[0]);
|
||||
ko.applyBindings(loginStateViewModel, document.getElementById("drop_overlay"));
|
||||
ko.applyBindings(printerStateViewModel, document.getElementById("drop_overlay"));
|
||||
|
||||
var timelapseElement = document.getElementById("timelapse");
|
||||
if (timelapseElement) {
|
||||
|
|
|
|||
|
|
@ -17,13 +17,13 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div id="drop_overlay" data-bind="visible: isUser()">
|
||||
<div id="drop_overlay" data-bind="visible: loginState.isUser()">
|
||||
<div id="drop_overlay_background"></div>
|
||||
<div id="drop_overlay_wrapper">
|
||||
{% if enableSdSupport %}
|
||||
<div class="dropzone" id="drop_locally"><span class="centered"><i class="icon-upload-alt"></i><br>Upload locally</span></div>
|
||||
<div class="dropzone_background" id="drop_locally_background"></div>
|
||||
<div class="dropzone" id="drop_sd"><span class="centered"><i class="icon-upload-alt"></i><br>Upload to SD</span></div>
|
||||
<div class="dropzone" id="drop_sd"><span class="centered"><i class="icon-upload-alt"></i><br>Upload to SD<br><small data-bind="visible: !isSdReady()">(SD not initialized)</small></span></div>
|
||||
<div class="dropzone_background" id="drop_sd_background"></div>
|
||||
{% else %}
|
||||
<div class="dropzone" id="drop"><span class="centered"><i class="icon-upload-alt"></i><br>Upload</span></div>
|
||||
|
|
|
|||
|
|
@ -211,10 +211,10 @@
|
|||
<span>Upload</span>
|
||||
<input id="gcode_upload" type="file" name="gcode_file" class="fileinput-button" data-url="/ajax/gcodefiles/upload" data-bind="enable: loginState.isUser()">
|
||||
</span>
|
||||
<span class="btn btn-primary fileinput-button span6" data-bind="css: {disabled: !$root.loginState.isUser()}" style="margin-bottom: 10px">
|
||||
<span class="btn btn-primary fileinput-button span6" data-bind="css: {disabled: !$root.loginState.isUser() || !$root.isSdReady()}" style="margin-bottom: 10px">
|
||||
<i class="icon-upload-alt icon-white"></i>
|
||||
<span>Upload to SD</span>
|
||||
<input id="gcode_upload_sd" type="file" name="gcode_file" class="fileinput-button" data-url="/ajax/gcodefiles/upload" data-bind="enable: loginState.isUser()">
|
||||
<input id="gcode_upload_sd" type="file" name="gcode_file" class="fileinput-button" data-url="/ajax/gcodefiles/upload" data-bind="enable: loginState.isUser() && isSdReady()">
|
||||
</span>
|
||||
{% else %}
|
||||
<span class="btn btn-primary fileinput-button span12" data-bind="css: {disabled: !$root.loginState.isUser()}" style="margin-bottom: 10px">
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import os
|
|||
import traceback
|
||||
import sys
|
||||
import time
|
||||
import re
|
||||
|
||||
from octoprint.settings import settings
|
||||
|
||||
|
|
@ -110,3 +111,30 @@ def getRemoteAddress(request):
|
|||
if forwardedFor is not None:
|
||||
return forwardedFor.split(",")[0]
|
||||
return request.remote_addr
|
||||
|
||||
|
||||
def getDosFilename(input, existingFilenames, extension=None):
|
||||
if input is None:
|
||||
return None
|
||||
|
||||
if extension is None:
|
||||
extension = "gco"
|
||||
|
||||
filename, ext = input.rsplit(".", 1)
|
||||
return findCollisionfreeName(filename, extension, existingFilenames)
|
||||
|
||||
|
||||
def findCollisionfreeName(input, extension, existingFilenames):
|
||||
filename = re.sub(r"\s+", "_", input.lower().translate(None, ".\"/\\[]:;=,"))
|
||||
|
||||
counter = 1
|
||||
power = 1
|
||||
while counter < (10 * power):
|
||||
result = filename[:(6 - power + 1)] + "~" + str(counter) + "." + extension
|
||||
if result not in existingFilenames:
|
||||
return result
|
||||
counter += 1
|
||||
if counter == 10 * power:
|
||||
power += 1
|
||||
|
||||
raise ValueError("Can't create a collision free filename")
|
||||
|
|
|
|||
|
|
@ -609,6 +609,7 @@ class MachineCom(object):
|
|||
# anwer to M28, at least on Marlin, Repetier and Sprinter: "Writing to file: %s"
|
||||
self._printSection = "CUSTOM"
|
||||
self._changeState(self.STATE_PRINTING)
|
||||
line = "ok"
|
||||
elif 'Done printing file' in line:
|
||||
# printer is reporting file finished printing
|
||||
self._sdFilePos = 0
|
||||
|
|
@ -641,7 +642,7 @@ class MachineCom(object):
|
|||
pass
|
||||
|
||||
##~~ Parsing for pause triggers
|
||||
if pauseTriggers:
|
||||
if pauseTriggers and not self.isStreaming():
|
||||
if "enable" in pauseTriggers.keys() and pauseTriggers["enable"].search(line) is not None:
|
||||
self.setPause(True)
|
||||
elif "disable" in pauseTriggers.keys() and pauseTriggers["disable"].search(line) is not None:
|
||||
|
|
@ -800,6 +801,7 @@ class MachineCom(object):
|
|||
self._callback.mcFileTransferDone()
|
||||
self._changeState(self.STATE_OPERATIONAL)
|
||||
eventManager().fire("TransferDone", filename)
|
||||
self.refreshSdFiles()
|
||||
else:
|
||||
self._callback.mcPrintjobDone()
|
||||
self._changeState(self.STATE_OPERATIONAL)
|
||||
|
|
|
|||
|
|
@ -76,6 +76,7 @@ class VirtualPrinter():
|
|||
return
|
||||
else:
|
||||
self.lastN = linenumber
|
||||
data = data.split(None, 1)[1].strip()
|
||||
|
||||
data += "\n"
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue