From 9f975426a78056c966e2f284727c782527b49fb0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gina=20H=C3=A4u=C3=9Fge?= Date: Sun, 2 Jun 2013 13:41:03 +0200 Subject: [PATCH 1/6] Added requirements for BeagleBone Black Difference to regular dependencies is to not fetch pyserial and numpy via pip but instead install those from the available packages. (cherry picked from commit 41aa633) --- requirements-bbb.txt | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 requirements-bbb.txt diff --git a/requirements-bbb.txt b/requirements-bbb.txt new file mode 100644 index 0000000..f107e8e --- /dev/null +++ b/requirements-bbb.txt @@ -0,0 +1,6 @@ +flask>=0.9 +tornado>=2.4.1 +tornadio2>=0.0.4 +PyYAML>=3.10 +Flask-Login>=0.1.3 +Flask-Principal>=0.3.5 \ No newline at end of file From 57932ff78c94cf2e6145ae6636914ba251d9c58f Mon Sep 17 00:00:00 2001 From: Dale Price Date: Thu, 6 Jun 2013 00:23:30 -0500 Subject: [PATCH 2/6] Check for localStorage with Modernizr before attempting to use it. Solves foosel/OctoPrint#91 --- octoprint/static/js/ui.js | 47 ++++++++++++++++++++++----------------- 1 file changed, 26 insertions(+), 21 deletions(-) diff --git a/octoprint/static/js/ui.js b/octoprint/static/js/ui.js index d2d0882..970aaa9 100644 --- a/octoprint/static/js/ui.js +++ b/octoprint/static/js/ui.js @@ -1655,43 +1655,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(); From 003109d59e969daeb06abe57d9f01c2fab5fcb8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gina=20H=C3=A4u=C3=9Fge?= Date: Sun, 9 Jun 2013 14:00:15 +0200 Subject: [PATCH 3/6] Made gcode viewer capable of handling progress information GCode viewer now updates its visualization (during printing) based on the current progress percentage, not based on the current line (which will not be available any more as part of the progress tuple with gcode streaming) --- octoprint/static/gcodeviewer/js/Worker.js | 67 ++----- .../static/gcodeviewer/js/gCodeReader.js | 78 ++++---- octoprint/static/js/avltree.js | 169 ++++++++++++++++++ octoprint/static/js/ui.js | 15 +- octoprint/templates/index.jinja2 | 1 + 5 files changed, 242 insertions(+), 88 deletions(-) create mode 100644 octoprint/static/js/avltree.js 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 01a01d8..fc3c779 100644 --- a/octoprint/static/js/ui.js +++ b/octoprint/static/js/ui.js @@ -1093,13 +1093,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) { diff --git a/octoprint/templates/index.jinja2 b/octoprint/templates/index.jinja2 index 7b3c28c..d5530fe 100644 --- a/octoprint/templates/index.jinja2 +++ b/octoprint/templates/index.jinja2 @@ -579,6 +579,7 @@ + From d5a620f476c2e8af8c4850b4ecf19c72983baa3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gina=20H=C3=A4u=C3=9Fge?= Date: Sun, 9 Jun 2013 18:03:41 +0200 Subject: [PATCH 4/6] Introduced new function matchesGcode to properly test if a line contains a specific gcode --- octoprint/util/__init__.py | 7 ++++++- octoprint/util/comm.py | 16 +++++++++------- 2 files changed, 15 insertions(+), 8 deletions(-) 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 cea6dd3..3954872 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: @@ -833,20 +835,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: @@ -926,12 +928,12 @@ class MachineCom(object): self._printSection = line[1] line = line[0] try: - if line == 'M0' or line == 'M1': + 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. + 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 ('G0' in line or 'G1' in line) and 'Z' in 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 From 4509eab81677d3bc14d581cf3a368efa22a43246 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gina=20H=C3=A4u=C3=9Fge?= Date: Sun, 9 Jun 2013 18:04:25 +0200 Subject: [PATCH 5/6] Enable sd support by default --- octoprint/settings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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, From 9963c523c012c9e14d78bd8362624797267fb5db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gina=20H=C3=A4u=C3=9Fge?= Date: Sun, 9 Jun 2013 18:13:12 +0200 Subject: [PATCH 6/6] Do not display -1mm when printing from sd --- octoprint/printer.py | 2 +- octoprint/static/js/ui.js | 5 +++++ octoprint/templates/index.jinja2 | 2 +- octoprint/util/comm.py | 2 +- 4 files changed, 8 insertions(+), 3 deletions(-) diff --git a/octoprint/printer.py b/octoprint/printer.py index 76bc285..8ddc707 100644 --- a/octoprint/printer.py +++ b/octoprint/printer.py @@ -201,7 +201,7 @@ class Printer(): if self._comm.isPrinting(): return - self._setCurrentZ(-1) + self._setCurrentZ(None) if self._sdFile is not None: # we are working in sd mode self._sdPrinting = True diff --git a/octoprint/static/js/ui.js b/octoprint/static/js/ui.js index fc3c779..3ddd486 100644 --- a/octoprint/static/js/ui.js +++ b/octoprint/static/js/ui.js @@ -231,6 +231,11 @@ function PrinterStateViewModel(loginStateViewModel) { var currentLine = self.currentLine() ? self.currentLine() : "-"; return currentLine + " / " + self.totalLines(); }); + self.heightString = ko.computed(function() { + if (!self.currentHeight()) + return "-"; + return self.currentHeight(); + }) self.progressString = ko.computed(function() { if (!self.progress()) return 0; diff --git a/octoprint/templates/index.jinja2 b/octoprint/templates/index.jinja2 index d5530fe..fc78ec8 100644 --- a/octoprint/templates/index.jinja2 +++ b/octoprint/templates/index.jinja2 @@ -112,7 +112,7 @@ Filament:
Estimated Print Time:
Line:
- Height:
+ Height:
Print Time:
Print Time Left:
diff --git a/octoprint/util/comm.py b/octoprint/util/comm.py index 3954872..c846e93 100644 --- a/octoprint/util/comm.py +++ b/octoprint/util/comm.py @@ -358,7 +358,7 @@ class MachineCom(object): self._commandQueue = queue.Queue() self._logQueue = queue.Queue(256) self._feedRateModifier = {} - self._currentZ = -1 + self._currentZ = None self._heatupWaitStartTime = 0 self._heatupWaitTimeLost = 0.0 self._printStartTime = None