Changed SD filename generation, made SD handling more reliable as a whole (cherry picked from commit 717ec041)

This commit is contained in:
Gina Häußge 2013-09-23 18:40:46 +02:00
parent df05a80201
commit 4b05f125a0
8 changed files with 141 additions and 36 deletions

View file

@ -70,6 +70,7 @@ class Printer():
# sd handling
self._sdPrinting = False
self._sdStreaming = False
self._sdFilelistAvailable = threading.Event()
self._selectedFile = None
@ -434,6 +435,7 @@ class Printer():
def mcSdFiles(self, files):
self._sendTriggerUpdateCallbacks("gcodeFiles")
self._sdFilelistAvailable.set()
def mcFileSelected(self, filename, filesize, sd):
self._setJobData(filename, filesize, sd)
@ -467,15 +469,15 @@ 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, absolutePath):
from octoprint.util import isGcodeFileName
from octoprint.util import isSTLFileName
if not self._comm or self._comm.isBusy():
if not self._comm or self._comm.isBusy() or not self._comm.isSdReady():
logging.error("No connection to printer or printer is busy")
return
@ -492,32 +494,42 @@ class Printer():
absolutePath, callBack, callBackArgs)
def streamSdFile(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
sdFilename = filename[:filename.find(".")].lower()
if len(sdFilename) > 8:
sdFilename = sdFilename[:8]
self._comm.startFileTransfer(path, sdFilename + ".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

View file

@ -471,7 +471,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)

View file

@ -84,23 +84,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"),
@ -111,6 +117,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");
@ -148,7 +210,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) {
@ -203,7 +265,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) {

View file

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

View file

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

View file

@ -6,6 +6,7 @@ import os
import traceback
import sys
import time
import re
from octoprint.settings import settings
@ -151,3 +152,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")

View file

@ -611,6 +611,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
@ -645,7 +646,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:
@ -804,6 +805,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)
@ -1162,4 +1164,4 @@ class PrintingGcodeFileInformation(PrintingFileInformation):
class StreamingGcodeFileInformation(PrintingGcodeFileInformation):
def __init__(self, filename):
PrintingGcodeFileInformation.__init__(self, filename, None)
PrintingGcodeFileInformation.__init__(self, filename, None)

View file

@ -76,6 +76,7 @@ class VirtualPrinter():
return
else:
self.lastN = linenumber
data = data.split(None, 1)[1].strip()
data += "\n"