diff --git a/octoprint/printer.py b/octoprint/printer.py index b82f1d5..1927fbf 100644 --- a/octoprint/printer.py +++ b/octoprint/printer.py @@ -177,7 +177,7 @@ class Printer(): if self._selectedFile is None: return - self._setCurrentZ(-1) + self._setCurrentZ(None) self._comm.startPrint() def togglePausePrint(self): diff --git a/octoprint/settings.py b/octoprint/settings.py index 42b469c..71251b4 100644 --- a/octoprint/settings.py +++ b/octoprint/settings.py @@ -43,7 +43,7 @@ default_settings = { "waitForWaitOnConnect": False, "alwaysSendChecksum": False, "resetLineNumbersWithPrefixedN": False, - "sdSupport": False + "sdSupport": True }, "folder": { "uploads": None, diff --git a/octoprint/static/gcodeviewer/js/Worker.js b/octoprint/static/gcodeviewer/js/Worker.js index 98b39b2..feb4d95 100644 --- a/octoprint/static/gcodeviewer/js/Worker.js +++ b/octoprint/static/gcodeviewer/js/Worker.js @@ -223,42 +223,31 @@ var assumeNonDC = false; for(var i=0;i0&&prevRetract < 0){ prevRetract = 0; retract = 1; } else { - // prevRetract = retract; retract = 0; } prev_extrude[argChar] = numSlice; @@ -317,24 +301,24 @@ prev_extrude["abs"] = Math.sqrt((prevX-x)*(prevX-x)+(prevY-y)*(prevY-y)); } if(!model[layer])model[layer]=[]; - if(typeof(x) !== 'undefined' || typeof(y) !== 'undefined' ||typeof(z) !== 'undefined'||retract!=0) model[layer][model[layer].length] = {x: Number(x), y: Number(y), z: Number(z), extrude: extrude, retract: Number(retract), noMove: false, extrusion: (extrude||retract)?Number(prev_extrude["abs"]):0, prevX: Number(prevX), prevY: Number(prevY), prevZ: Number(prevZ), speed: Number(lastF), gcodeLine: Number(i)}; + if(typeof(x) !== 'undefined' || typeof(y) !== 'undefined' ||typeof(z) !== 'undefined'||retract!=0) model[layer][model[layer].length] = {x: Number(x), y: Number(y), z: Number(z), extrude: extrude, retract: Number(retract), noMove: false, extrusion: (extrude||retract)?Number(prev_extrude["abs"]):0, prevX: Number(prevX), prevY: Number(prevY), prevZ: Number(prevZ), speed: Number(lastF), gcodeLine: Number(i), percentage: percentage}; //{x: x, y: y, z: z, extrude: extrude, retract: retract, noMove: false, extrusion: (extrude||retract)?prev_extrude["abs"]:0, prevX: prevX, prevY: prevY, prevZ: prevZ, speed: lastF, gcodeLine: i}; if(typeof(x) !== 'undefined') prevX = x; if(typeof(y) !== 'undefined') prevY = y; - } else if(gcode[i].match(/^(?:M82)/i)){ + } else if(line.match(/^(?:M82)/i)){ extrudeRelative = false; - }else if(gcode[i].match(/^(?:G91)/i)){ + }else if(line.match(/^(?:G91)/i)){ extrudeRelative=true; - }else if(gcode[i].match(/^(?:G90)/i)){ + }else if(line.match(/^(?:G90)/i)){ extrudeRelative=false; - }else if(gcode[i].match(/^(?:M83)/i)){ + }else if(line.match(/^(?:M83)/i)){ extrudeRelative=true; - }else if(gcode[i].match(/^(?:M101)/i)){ + }else if(line.match(/^(?:M101)/i)){ dcExtrude=true; - }else if(gcode[i].match(/^(?:M103)/i)){ + }else if(line.match(/^(?:M103)/i)){ dcExtrude=false; - }else if(gcode[i].match(/^(?:G92)/i)){ - var args = gcode[i].split(/\s/); + }else if(line.match(/^(?:G92)/i)){ + var args = line.split(/\s/); for(j=0;j gcode.length*0.02 && sendMultiLayer.length != 0){ lastSend = i; @@ -429,13 +406,7 @@ sendLayerZ = undefined; } } -// sendMultiLayer[sendMultiLayer.length] = layer; -// sendMultiLayerZ[sendMultiLayerZ.length] = z; sendMultiLayerToParent(sendMultiLayer, sendMultiLayerZ, i/gcode.length*100); - -// if(gCodeOptions["sortLayers"])sortLayers(); -// if(gCodeOptions["purgeEmptyLayers"])purgeLayers(); - }; diff --git a/octoprint/static/gcodeviewer/js/gCodeReader.js b/octoprint/static/gcodeviewer/js/gCodeReader.js index 190bc57..f30fdc6 100644 --- a/octoprint/static/gcodeviewer/js/gCodeReader.js +++ b/octoprint/static/gcodeviewer/js/gCodeReader.js @@ -23,57 +23,73 @@ GCODE.gCodeReader = (function(){ purgeEmptyLayers: true, analyzeModel: false }; - var linesCmdIndex = {}; - var prepareGCode = function(){ + var percentageTree = undefined; + + var prepareGCode = function(totalSize){ if(!lines)return; gcode = []; - var i, tmp; + var i, tmp, byteCount; + + byteCount = 0; for(i=0;i 1 || tmp === -1) { - gcode.push(lines[i]); + gcode.push({line: lines[i], percentage: byteCount * 100 / totalSize}); } } lines = []; -// console.log("GCode prepared"); }; var sortLayers = function(){ var sortedZ = []; var tmpModel = []; -// var cnt = 0; -// console.log(z_heights); + for(var layer in z_heights){ sortedZ[z_heights[layer]] = layer; -// cnt++; } -// console.log("cnt is " + cnt); + sortedZ.sort(function(a,b){ return a-b; }); -// console.log(sortedZ); -// console.log(model.length); + for(var i=0;i rdepth + 1) { + // LR or LL rotation + var lldepth = self.left.left == null ? 0 : self.left.left.depth; + var lrdepth = self.left.right == null ? 0 : self.left.right.depth; + + if (lldepth < lrdepth) { + // LR rotation consists of a RR rotation of the left child + self.left.rotateRR(); + // plus a LL rotation of self node, which happens anyway + } + self.rotateLL(); + } else if (ldepth + 1 < rdepth) { + // RR or RL rorarion + var rrdepth = self.right.right == null ? 0 : self.right.right.depth; + var rldepth = self.right.left == null ? 0 : self.right.left.depth; + + if (rldepth > rrdepth) { + // RR rotation consists of a LL rotation of the right child + self.right.rotateLL(); + // plus a RR rotation of self node, which happens anyway + } + self.rotateRR(); + } + } + + self.rotateLL = function() { + // the left side is too long => rotate from the left (_not_ leftwards) + var nodeBefore = self.node; + var elementsBefore = self.elements; + var rightBefore = self.right; + self.node = self.left.node; + self.elements = self.left.elements; + self.right = self.left; + self.left = self.left.left; + self.right.left = self.right.right; + self.right.right = rightBefore; + self.right.node = nodeBefore; + self.right.elements = elementsBefore; + self.right.updateInNewLocation(); + self.updateInNewLocation(); + } + + self.rotateRR = function() { + // the right side is too long => rotate from the right (_not_ rightwards) + var nodeBefore = self.node; + var elementsBefore = self.elements; + var leftBefore = self.left; + self.node = self.right.node; + self.elements = self.right.elements; + self.left = self.right; + self.right = self.right.right; + self.left.right = self.left.left; + self.left.left = leftBefore; + self.left.node = nodeBefore; + self.left.elements = elementsBefore; + self.left.updateInNewLocation(); + self.updateInNewLocation(); + } + + self.updateInNewLocation = function() { + self.getDepthFromChildren(); + } + + self.getDepthFromChildren = function() { + self.depth = self.node == null ? 0 : 1; + if (self.left != null) { + self.depth = self.left.depth + 1; + } + if (self.right != null && self.depth <= self.right.depth) { + self.depth = self.right.depth + 1; + } + } + + self.compare = function(n1, n2) { + var v1 = n1[self.attr]; + var v2 = n2[self.attr]; + if (v1 == v2) { + return 0; + } + if (v1 < v2) { + return -1; + } + return 1; + } + + self.add = function(n) { + var o = self.compare(n, self.node); + if (o == 0) { + self.elements.push(n); + return false; + } + + var ret = false; + if (o == -1) { + if (self.left == null) { + self.left = new AVLTree(n, self.attr); + ret = true; + } else { + ret = self.left.add(n); + if (ret) { + self.balance(); + } + } + } else if (o == 1) { + if (self.right == null) { + self.right = new AVLTree(n, self.attr); + ret = true; + } else { + ret = self.right.add(n); + if (ret) { + self.balance(); + } + } + } + + if (ret) { + self.getDepthFromChildren(); + } + return ret; + } + + self.findBest = function(value) { + if (value < self.node[self.attr]) { + if (self.left != null) { + return self.left.findBest(value); + } + } else if (value > self.node[self.attr]) { + if (self.right != null) { + return self.right.findBest(value); + } + } + + return self.elements; + } + + self.find = function(value) { + var elements = self.findBest(value); + for (var i = 0; i < elements.length; i++) { + if (elements[i][self.attr] == value) { + return elements; + } + } + + return false; + } +} diff --git a/octoprint/static/js/ui.js b/octoprint/static/js/ui.js index 31a5982..e585a75 100644 --- a/octoprint/static/js/ui.js +++ b/octoprint/static/js/ui.js @@ -234,7 +234,11 @@ function PrinterStateViewModel(loginStateViewModel) { var filepos = self.filepos() ? self.filepos() : "-"; return filepos + " / " + self.filesize(); }); - + self.heightString = ko.computed(function() { + if (!self.currentHeight()) + return "-"; + return self.currentHeight(); + }) self.progressString = ko.computed(function() { if (!self.progress()) return 0; @@ -1077,13 +1081,16 @@ function GcodeViewModel(loginStateViewModel) { } self._processData = function(data) { - if(!self.enabled)return; + if (!self.enabled) return; + if (!data.job.filename) return; - if(self.loadedFilename == data.job.filename) { - var cmdIndex = GCODE.gCodeReader.getLinesCmdIndex(data.progress.progress); - if(cmdIndex){ - GCODE.renderer.render(cmdIndex.layer, 0, cmdIndex.cmd); - GCODE.ui.updateLayerInfo(cmdIndex.layer); + if(self.loadedFilename && self.loadedFilename == data.job.filename) { + if (data.state.flags && (data.state.flags.printing || data.state.flags.paused)) { + var cmdIndex = GCODE.gCodeReader.getCmdIndexForPercentage(data.progress.progress * 100); + if(cmdIndex){ + GCODE.renderer.render(cmdIndex.layer, 0, cmdIndex.cmd); + GCODE.ui.updateLayerInfo(cmdIndex.layer); + } } self.errorCount = 0 } else if (data.job.filename) { @@ -1729,43 +1736,48 @@ function ItemListHelper(listType, supportedSorting, supportedFilters, defaultSor //~~ local storage self._saveCurrentSortingToLocalStorage = function() { - self._initializeLocalStorage(); - - var currentSorting = self.currentSorting(); - if (currentSorting !== undefined) - localStorage[self.listType + "." + "currentSorting"] = currentSorting; - else - localStorage[self.listType + "." + "currentSorting"] = undefined; + if ( self._initializeLocalStorage() ) { + var currentSorting = self.currentSorting(); + if (currentSorting !== undefined) + localStorage[self.listType + "." + "currentSorting"] = currentSorting; + else + localStorage[self.listType + "." + "currentSorting"] = undefined; + } } self._loadCurrentSortingFromLocalStorage = function() { - self._initializeLocalStorage(); - - if (_.contains(_.keys(supportedSorting), localStorage[self.listType + "." + "currentSorting"])) - self.currentSorting(localStorage[self.listType + "." + "currentSorting"]); - else - self.currentSorting(defaultSorting); + if ( self._initializeLocalStorage() ) { + if (_.contains(_.keys(supportedSorting), localStorage[self.listType + "." + "currentSorting"])) + self.currentSorting(localStorage[self.listType + "." + "currentSorting"]); + else + self.currentSorting(defaultSorting); + } } self._saveCurrentFiltersToLocalStorage = function() { - self._initializeLocalStorage(); - - var filters = _.intersection(_.keys(self.supportedFilters), self.currentFilters()); - localStorage[self.listType + "." + "currentFilters"] = JSON.stringify(filters); + if ( self._initializeLocalStorage() ) { + var filters = _.intersection(_.keys(self.supportedFilters), self.currentFilters()); + localStorage[self.listType + "." + "currentFilters"] = JSON.stringify(filters); + } } self._loadCurrentFiltersFromLocalStorage = function() { - self._initializeLocalStorage(); - - self.currentFilters(_.intersection(_.keys(self.supportedFilters), JSON.parse(localStorage[self.listType + "." + "currentFilters"]))); + if ( self._initializeLocalStorage() ) { + self.currentFilters(_.intersection(_.keys(self.supportedFilters), JSON.parse(localStorage[self.listType + "." + "currentFilters"]))); + } } self._initializeLocalStorage = function() { + if (!Modernizr.localstorage) + return false; + if (localStorage[self.listType + "." + "currentSorting"] !== undefined && localStorage[self.listType + "." + "currentFilters"] !== undefined && JSON.parse(localStorage[self.listType + "." + "currentFilters"]) instanceof Array) - return; + return true; localStorage[self.listType + "." + "currentSorting"] = self.defaultSorting; localStorage[self.listType + "." + "currentFilters"] = JSON.stringify(self.defaultFilters); + + return true; } self._loadCurrentFiltersFromLocalStorage(); diff --git a/octoprint/templates/index.jinja2 b/octoprint/templates/index.jinja2 index f10be39..5a106bd 100644 --- a/octoprint/templates/index.jinja2 +++ b/octoprint/templates/index.jinja2 @@ -111,7 +111,7 @@ File:  (SD)
Filament:
Estimated Print Time:
- Height:
+ Height:
Print Time:
Print Time Left:
Printed:
@@ -579,6 +579,7 @@ + diff --git a/octoprint/util/__init__.py b/octoprint/util/__init__.py index f762414..921ea9f 100644 --- a/octoprint/util/__init__.py +++ b/octoprint/util/__init__.py @@ -2,6 +2,8 @@ __author__ = "Gina Häußge " __license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html' +import re + def getFormattedSize(num): """ Taken from http://stackoverflow.com/questions/1094841/reusable-library-to-get-human-readable-version-of-file-size @@ -38,4 +40,7 @@ def getClass(name): m = __import__(module) for comp in parts[1:]: m = getattr(m, comp) - return m \ No newline at end of file + return m + +def matchesGcode(line, gcode): + return re.search("^\s*%s\D" % gcode, line, re.I) \ No newline at end of file diff --git a/octoprint/util/comm.py b/octoprint/util/comm.py index fa5e804..3a6ce59 100644 --- a/octoprint/util/comm.py +++ b/octoprint/util/comm.py @@ -16,6 +16,8 @@ import serial from octoprint.util.avr_isp import stk500v2 from octoprint.util.avr_isp import ispBase +from octoprint.util import matchesGcode + from octoprint.settings import settings try: @@ -358,7 +360,7 @@ class MachineCom(object): self._bedTargetTemp = 0 self._commandQueue = queue.Queue() self._logQueue = queue.Queue(256) - self._currentZ = -1 + self._currentZ = None self._heatupWaitStartTime = 0 self._heatupWaitTimeLost = 0.0 @@ -846,20 +848,20 @@ class MachineCom(object): with self._sendingLock: if self._serial is None: return - if 'M109' in cmd or 'M190' in cmd: + if matchesGcode(cmd, "M109") or matchesGcode(cmd, "M190"): self._heatupWaitStartTime = time.time() - if 'M104' in cmd or 'M109' in cmd: + if matchesGcode(cmd, "M104") or matchesGcode(cmd, "M109"): try: self._targetTemp = float(re.search('S([0-9]+)', cmd).group(1)) except: pass - if 'M140' in cmd or 'M190' in cmd: + if matchesGcode(cmd, "M140") or matchesGcode(cmd, "M190"): try: self._bedTargetTemp = float(re.search('S([0-9]+)', cmd).group(1)) except: pass - if "M110" in cmd: + if matchesGcode(cmd, "M110"): newLineNumber = None if " N" in cmd: try: @@ -945,17 +947,19 @@ class MachineCom(object): line = line[0] if not self.isStreaming(): - try: - if line == 'M0' or line == 'M1': - self.setPause(True) - line = 'M105' #Don't send the M0 or M1 to the machine, as M0 and M1 are handled as an LCD menu pause. - if ('G0' in line or 'G1' in line) and 'Z' in line: - z = float(re.search('Z([0-9\.]*)', line).group(1)) - if self._currentZ != z: - self._currentZ = z - self._callback.mcZChange(z) - except: - self._log("Unexpected error: %s" % (getExceptionString())) + try: + if matchesGcode(line, "M0") or matchesGcode(line, "M1"): + self.setPause(True) + line = "M105" # Don't send the M0 or M1 to the machine, as M0 and M1 are handled as an LCD menu pause. + if self._printSection in self._feedRateModifier: + line = re.sub('F([0-9]*)', lambda m: 'F' + str(int(int(m.group(1)) * self._feedRateModifier[self._printSection])), line) + if (matchesGcode(line, "G0") or matchesGcode(line, "G1")) and 'Z' in line: + z = float(re.search('Z([0-9\.]*)', line).group(1)) + if self._currentZ != z: + self._currentZ = z + self._callback.mcZChange(z) + except: + self._log("Unexpected error: %s" % (getExceptionString())) self._sendCommand(line, True) self._callback.mcProgress()