From 46d9cd38eb10f956ecd22de021f9238696b3f191 Mon Sep 17 00:00:00 2001 From: Joseph Coffland Date: Sun, 7 Oct 2018 16:08:00 -0700 Subject: [PATCH] Fixed rapid view, fixed timing --- package-lock.json | 51 +++++++ package.json | 2 + src/js/control-view.js | 19 ++- src/js/main.js | 9 +- src/js/path-viewer.js | 15 +- src/js/tool-button.js | 32 ----- src/pug/index.pug | 2 +- src/pug/templates/admin-network-view.pug | 4 +- src/pug/templates/axis-control.pug | 4 +- src/pug/templates/cheat-sheet-view.pug | 168 +++++++++++------------ src/pug/templates/control-view.pug | 67 ++++----- src/pug/templates/help-view.pug | 28 ++-- src/pug/templates/indicators.pug | 12 +- src/pug/templates/path-viewer.pug | 32 +++-- src/pug/templates/settings-view.pug | 4 +- src/pug/templates/tool-button.pug | 28 ---- src/pug/templates/tool-view.pug | 34 +++-- src/py/bbctrl/Ctrl.py | 1 + src/py/bbctrl/PlanTimer.py | 106 ++++++++++++++ src/py/bbctrl/Planner.py | 23 ++-- src/py/bbctrl/Preplanner.py | 36 +++-- src/py/bbctrl/Web.py | 1 + src/py/bbctrl/__init__.py | 1 + src/stylus/style.styl | 9 ++ 24 files changed, 424 insertions(+), 264 deletions(-) delete mode 100644 src/js/tool-button.js delete mode 100644 src/pug/templates/tool-button.pug create mode 100644 src/py/bbctrl/PlanTimer.py diff --git a/package-lock.json b/package-lock.json index e87ebe8..d88c5c8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1870,6 +1870,17 @@ "through2": "^2.0.3" } }, + "gulp-inline-images": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/gulp-inline-images/-/gulp-inline-images-1.2.6.tgz", + "integrity": "sha1-vNNBcHfF3Zvkq42XFO2mZNLVufo=", + "requires": { + "cheerio": "^0.22.0", + "gulp": "^3.9.1", + "gulp-util": "^3.0.8", + "through2": "^2.0.3" + } + }, "gulp-pug": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/gulp-pug/-/gulp-pug-4.0.1.tgz", @@ -1956,6 +1967,33 @@ "vinyl-sourcemaps-apply": "^0.2.0" } }, + "gulp-uglify": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/gulp-uglify/-/gulp-uglify-3.0.1.tgz", + "integrity": "sha512-KVffbGY9d4Wv90bW/B1KZJyunLMyfHTBbilpDvmcrj5Go0/a1G3uVpt+1gRBWSw/11dqR3coJ1oWNTt1AiXuWQ==", + "requires": { + "gulplog": "^1.0.0", + "has-gulplog": "^0.1.0", + "lodash": "^4.13.1", + "make-error-cause": "^1.1.1", + "safe-buffer": "^5.1.2", + "through2": "^2.0.0", + "uglify-js": "^3.0.5", + "vinyl-sourcemaps-apply": "^0.2.0" + }, + "dependencies": { + "lodash": { + "version": "4.17.11", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", + "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==" + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + } + } + }, "gulp-util": { "version": "3.0.8", "resolved": "https://registry.npmjs.org/gulp-util/-/gulp-util-3.0.8.tgz", @@ -2697,6 +2735,19 @@ "es5-ext": "~0.10.2" } }, + "make-error": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.5.tgz", + "integrity": "sha512-c3sIjNUow0+8swNwVpqoH4YCShKNFkMaw6oH1mNS2haDZQqkeZFlHS3dhoeEbKKmJB4vXpJucU6oH75aDYeE9g==" + }, + "make-error-cause": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/make-error-cause/-/make-error-cause-1.2.2.tgz", + "integrity": "sha1-3wOI/NCzeBbf8KX7gQiTl3fcvJ0=", + "requires": { + "make-error": "^1.2.0" + } + }, "make-iterator": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/make-iterator/-/make-iterator-1.0.1.tgz", diff --git a/package.json b/package.json index 42aff74..81516c6 100644 --- a/package.json +++ b/package.json @@ -10,9 +10,11 @@ "gulp-concat": "^2.6.1", "gulp-csso": "^3.0.1", "gulp-inline": "^0.1.3", + "gulp-inline-images": "^1.2.6", "gulp-pug": "^4.0.1", "gulp-sourcemaps": "^2.6.4", "gulp-stylus": "^2.7.0", + "gulp-uglify": "^3.0.1", "jshint": "", "pug-cli": "^1.0.0-alpha6", "stylus": ">=0.42.3", diff --git a/src/js/control-view.js b/src/js/control-view.js index 2648fca..1e38a21 100644 --- a/src/js/control-view.js +++ b/src/js/control-view.js @@ -139,7 +139,24 @@ module.exports = { }, - highlight_reason: function () {return this.reason != ''} + highlight_reason: function () {return this.reason != ''}, + plan_time: function () {return this.state.plan_time}, + + + eta: function () { + if (this.mach_state != 'RUNNING') return ''; + var remaining = this.toolpath.time - this.plan_time; + var d = new Date(); + d.setSeconds(d.getSeconds() + remaining); + return d.toLocaleString(); + }, + + + progress: function () { + if (!this.toolpath.time) return 0; + var p = this.plan_time / this.toolpath.time; + return p < 1 ? p : 1; + } }, diff --git a/src/js/main.js b/src/js/main.js index 9aa3aad..1a742c2 100644 --- a/src/js/main.js +++ b/src/js/main.js @@ -88,12 +88,13 @@ $(function() { if (MIN <= value) { parts.push(value / MIN); value %= MIN; - } - parts.push(value.toFixed(precision)); + } else parts.push(0); + + parts.push(value); - for (var i = 0; i < parts.length - 1; i++) { - parts[i] = parts[i].toFixed(0); + for (var i = 0; i < parts.length; i++) { + parts[i] = parts[i].toFixed(i == parts.length - 1 ? precision : 0); if (i && parts[i] < 10) parts[i] = '0' + parts[i]; } diff --git a/src/js/path-viewer.js b/src/js/path-viewer.js index 2fe9d67..4529999 100644 --- a/src/js/path-viewer.js +++ b/src/js/path-viewer.js @@ -62,11 +62,6 @@ module.exports = { }, - components: { - 'tool-button': require('./tool-button') - }, - - computed: { hasPath: function () {return typeof this.toolpath.path != 'undefined'} }, @@ -385,7 +380,8 @@ module.exports = { var step = this.toolpath.path[i]; var newColor = step.rapid ? rapid : cutting; - if (!i) { + // Handle color change + if (!i || newColor != color) { color = newColor; positions.push(x, y, z); colors.push.apply(colors, color); @@ -397,13 +393,6 @@ module.exports = { positions.push(x, y, z); colors.push.apply(colors, color); - - // Handle type change - if (newColor != color) { - color = newColor; - positions.push(x, y, z); - colors.push.apply(colors, color); - } } var geometry = new THREE.BufferGeometry(); diff --git a/src/js/tool-button.js b/src/js/tool-button.js deleted file mode 100644 index f77d0fd..0000000 --- a/src/js/tool-button.js +++ /dev/null @@ -1,32 +0,0 @@ -/******************************************************************************\ - - Copyright 2018. Buildbotics LLC - All Rights Reserved. - - For information regarding this software email: - Joseph Coffland - joseph@buildbotics.com - - This software is free software: you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public License - as published by the Free Software Foundation, either version 2.1 of - the License, or (at your option) any later version. - - This software is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the C! library. If not, see - . - -\******************************************************************************/ - -'use strict' - - -module.exports = { - template: '#tool-button-template', - props: ['name', 'active'] -} diff --git a/src/pug/index.pug b/src/pug/index.pug index d50f5ae..ef26fc6 100644 --- a/src/pug/index.pug +++ b/src/pug/index.pug @@ -160,7 +160,7 @@ html(lang="en") message(:show.sync="confirmUpload") h3(slot="header") Upload Firmware? div(slot="body") - p Are you sure you want to upload firmware {{firmwareName}}? + p Are you sure you want to upload firmware #[em {{firmwareName}}]? p.pure-control-group label(for="pass") Password diff --git a/src/pug/templates/admin-network-view.pug b/src/pug/templates/admin-network-view.pug index 1ff0b4b..341a4b8 100644 --- a/src/pug/templates/admin-network-view.pug +++ b/src/pug/templates/admin-network-view.pug @@ -37,7 +37,7 @@ script#admin-network-view-template(type="text/x-template") message(:show.sync="hostnameSet") h3(slot="header") Hostname Set div(slot="body") - p Hostname was successfuly set to {{hostname}}. + p Hostname was successfuly set to #[strong {{hostname}}]. p Rebooting to apply changes. p Redirecting to new hostname in {{redirectTimeout}} seconds. div(slot="footer") @@ -84,7 +84,7 @@ script#admin-network-view-template(type="text/x-template") label(for="wifi_ch") Channel select(name="wifi_ch", v-model="wifi_ch") each ch in [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11] - option(value="#{ch}")= ch + option(value=ch)= ch .pure-control-group(v-if="wifi_mode != 'disabled'") label(for="ssid") Network (SSID) input(name="ssid", v-model="wifi_ssid") diff --git a/src/pug/templates/axis-control.pug b/src/pug/templates/axis-control.pug index 37ec1f3..e41a76c 100644 --- a/src/pug/templates/axis-control.pug +++ b/src/pug/templates/axis-control.pug @@ -56,11 +56,11 @@ script#axis-control-template(type="text/x-template") each color in 'red green blue orange cyan purple'.split(' ') - lineargradient(xlink:href="##{color}", id="#{color}-1", + lineargradient(xlink:href="#" + color, id=color + "-1", gradientunits="userSpaceOnUse", gradienttransform="rotate(180 7 5)", x1="0", y1="0", x2="15", y2="10") - lineargradient(xlink:href="##{color}", id="#{color}-2", + lineargradient(xlink:href="#" + color, id=color + "-2", gradientunits="userSpaceOnUse", x1="10", y1="10", x2="40", y2="40") diff --git a/src/pug/templates/cheat-sheet-view.pug b/src/pug/templates/cheat-sheet-view.pug index 41f422f..bbe04ca 100644 --- a/src/pug/templates/cheat-sheet-view.pug +++ b/src/pug/templates/cheat-sheet-view.pug @@ -42,47 +42,47 @@ script#cheat-sheet-view-template(type="text/x-template") th(colspan='3') Motion tr td - a(href="#{base}/g-code.html#gcode:g0") G0 + a(href=`${base}/g-code.html#gcode:g0`) G0 td td Rapid Move tr td - a(target="_blank", href="#{base}/g-code.html#gcode:g1") G1 + a(target="_blank", href=`${base}/g-code.html#gcode:g1`) G1 td td Linear Move tr td - a(target="_blank", href="#{base}/g-code.html#gcode:g2-g3") G2, G3 + a(target="_blank", href=`${base}/g-code.html#gcode:g2-g3`) G2, G3 td I J K or R, P td Arc Move tr td - a(target="_blank", href="#{base}/g-code.html#gcode:g4") G4 + a(target="_blank", href=`${base}/g-code.html#gcode:g4`) G4 td P td Dwell tr.unimplemented(v-if="showUnimplemented") td - a(target="_blank", href="#{base}/g-code.html#gcode:g5") G5 + a(target="_blank", href=`${base}/g-code.html#gcode:g5`) G5 td I J P Q td Cubic Spline tr.unimplemented(v-if="showUnimplemented") td - a(target="_blank", href="#{base}/g-code.html#gcode:g5.1") G5.1 + a(target="_blank", href=`${base}/g-code.html#gcode:g5.1`) G5.1 td I J td Quadratic Spline tr.unimplemented(v-if="showUnimplemented") td - a(target="_blank", href="#{base}/g-code.html#gcode:g5.2-g5.3") G5.2 + a(target="_blank", href=`${base}/g-code.html#gcode:g5.2-g5.3`) G5.2 td P L td NURBS tr td - a(target="_blank", href="#{base}/g-code.html#gcode:g38") G38.2 - G38.5 + a(target="_blank", href=`${base}/g-code.html#gcode:g38`) G38.2 - G38.5 td td Straight Probe tr.unimplemented(v-if="showUnimplemented") td - a(target="_blank", href="#{base}/g-code.html#gcode:g33.1") G33.1 + a(target="_blank", href=`${base}/g-code.html#gcode:g33.1`) G33.1 td K td Rigid Tapping @@ -91,52 +91,52 @@ script#cheat-sheet-view-template(type="text/x-template") th(colspan='3') Tool Control tr td - a(href="#{base}/other-code.html#sec:select-tool") T + a(href=`${base}/other-code.html#sec:select-tool`) T td td Select Tool tr td - a(target="_blank", href="#{base}/m-code.html#mcode:m6") M6 + a(target="_blank", href=`${base}/m-code.html#mcode:m6`) M6 td T td Tool Change tr.unimplemented(v-if="showUnimplemented") td - a(target="_blank", href="#{base}/m-code.html#mcode:m61") M61 + a(target="_blank", href=`${base}/m-code.html#mcode:m61`) M61 td Q td Set Current Tool tr.unimplemented(v-if="showUnimplemented") td - a(target="_blank", href="#{base}/g-code.html#gcode:g10-l1") G10 L1 + a(target="_blank", href=`${base}/g-code.html#gcode:g10-l1`) G10 L1 td P Q R td Set Tool Table tr.unimplemented(v-if="showUnimplemented") td - a(target="_blank", href="#{base}/g-code.html#gcode:g10-l10") G10 L10 + a(target="_blank", href=`${base}/g-code.html#gcode:g10-l10`) G10 L10 td P td Set Tool Table tr.unimplemented(v-if="showUnimplemented") td - a(target="_blank", href="#{base}/g-code.html#gcode:g10-l11") G10 L11 + a(target="_blank", href=`${base}/g-code.html#gcode:g10-l11`) G10 L11 td P td Set Tool Table tr.unimplemented(v-if="showUnimplemented") td - a(target="_blank", href="#{base}/g-code.html#gcode:g43") G43 + a(target="_blank", href=`${base}/g-code.html#gcode:g43`) G43 td H td Tool Length Offset tr.unimplemented(v-if="showUnimplemented") td - a(target="_blank", href="#{base}/g-code.html#gcode:g43.1") G43.1 + a(target="_blank", href=`${base}/g-code.html#gcode:g43.1`) G43.1 td td Dynamic Tool Length Offset tr.unimplemented(v-if="showUnimplemented") td - a(target="_blank", href="#{base}/g-code.html#gcode:g43.2") G43.2 + a(target="_blank", href=`${base}/g-code.html#gcode:g43.2`) G43.2 td H td Apply additional Tool Length Offset tr.unimplemented(v-if="showUnimplemented") td - a(target="_blank", href="#{base}/g-code.html#gcode:g49") G49 + a(target="_blank", href=`${base}/g-code.html#gcode:g49`) G49 td td Cancel Tool Length Compensation @@ -145,23 +145,23 @@ script#cheat-sheet-view-template(type="text/x-template") th(colspan='3') Feed Control tr td - a(href="#{base}/other-code.html#sec:set-feed-rate") F + a(href=`${base}/other-code.html#sec:set-feed-rate`) F td td Set Feed Rate tr.unimplemented(v-if="showUnimplemented") td - a(target="_blank", href="#{base}/g-code.html#gcode:g93-g94-g95") + a(target="_blank", href=`${base}/g-code.html#gcode:g93-g94-g95`) | G93, G94, G95 td td Feed Rate Mode tr.unimplemented(v-if="showUnimplemented") td - a(target="_blank", href="#{base}/m-code.html#mcode:m52") M52 + a(target="_blank", href=`${base}/m-code.html#mcode:m52`) M52 td P0 (off) or P1 (on) td Adaptive Feed Control tr.unimplemented(v-if="showUnimplemented") td - a(target="_blank", href="#{base}/m-code.html#mcode:m53") M53 + a(target="_blank", href=`${base}/m-code.html#mcode:m53`) M53 td P0 (off) or P1 (on) td Feed Stop Control @@ -170,28 +170,28 @@ script#cheat-sheet-view-template(type="text/x-template") th(colspan='3') Spindle Control tr td - a(href="#{base}/other-code.html#sec:set-spindle-speed") S + a(href=`${base}/other-code.html#sec:set-spindle-speed`) S td td Set Spindle Speed tr td - a(target="_blank", href="#{base}/m-code.html#mcode:m3-m4-m5") + a(target="_blank", href=`${base}/m-code.html#mcode:m3-m4-m5`) | M3, M4, M5 td S td Spindle Control tr.unimplemented(v-if="showUnimplemented") td - a(target="_blank", href="#{base}/m-code.html#mcode:m19") M19 + a(target="_blank", href=`${base}/m-code.html#mcode:m19`) M19 td td Orient Spindle tr.unimplemented(v-if="showUnimplemented") td - a(target="_blank", href="#{base}/g-code.html#gcode:g96-g97") G96, G97 + a(target="_blank", href=`${base}/g-code.html#gcode:g96-g97`) G96, G97 td S D td Spindle Control Mode tr.unimplemented(v-if="showUnimplemented") td - a(target="_blank", href="#{base}/g-code.html#gcode:g33") G33 + a(target="_blank", href=`${base}/g-code.html#gcode:g33`) G33 td K td Spindle Synchronized Motion @@ -200,7 +200,7 @@ script#cheat-sheet-view-template(type="text/x-template") th(colspan='3') Coolant tr td - a(target="_blank", href="#{base}/m-code.html#mcode:m7-m8-m9") + a(target="_blank", href=`${base}/m-code.html#mcode:m7-m8-m9`) | M7, M8, M9 td td Coolant Control @@ -210,17 +210,17 @@ script#cheat-sheet-view-template(type="text/x-template") th(colspan='3') Stopping tr td - a(target="_blank", href="#{base}/m-code.html#mcode:m0-m1") M0, M1 + a(target="_blank", href=`${base}/m-code.html#mcode:m0-m1`) M0, M1 td td Program Pause tr td - a(target="_blank", href="#{base}/m-code.html#mcode:m2-m30") M2, M30 + a(target="_blank", href=`${base}/m-code.html#mcode:m2-m30`) M2, M30 td td Program End tr.unimplemented(v-if="showUnimplemented") td - a(target="_blank", href="#{base}/m-code.html#mcode:m60") M60 + a(target="_blank", href=`${base}/m-code.html#mcode:m60`) M60 td td Pallet Change Pause @@ -229,7 +229,7 @@ script#cheat-sheet-view-template(type="text/x-template") th(colspan='3') Units tr td - a(target="_blank", href="#{base}/g-code.html#gcode:g20-g21") G20, G21 + a(target="_blank", href=`${base}/g-code.html#gcode:g20-g21`) G20, G21 td td Units (inch, mm) @@ -238,23 +238,23 @@ script#cheat-sheet-view-template(type="text/x-template") th(colspan='3') Distance Mode tr td - a(target="_blank", href="#{base}/g-code.html#gcode:g90-g91") G90, G91 + a(target="_blank", href=`${base}/g-code.html#gcode:g90-g91`) G90, G91 td td Distance Mode tr td - a(target="_blank", href="#{base}/g-code.html#gcode:g90.1-g91.1") + a(target="_blank", href=`${base}/g-code.html#gcode:g90.1-g91.1`) | G90.1, G91.1 td td Arc Distance Mode tr.unimplemented(v-if="showUnimplemented") td - a(target="_blank", href="#{base}/g-code.html#gcode:g7") G7 + a(target="_blank", href=`${base}/g-code.html#gcode:g7`) G7 td td Lathe Diameter Mode tr.unimplemented(v-if="showUnimplemented") td - a(target="_blank", href="#{base}/g-code.html#gcode:g8") G8 + a(target="_blank", href=`${base}/g-code.html#gcode:g8`) G8 td td Lathe Radius Mode @@ -263,17 +263,17 @@ script#cheat-sheet-view-template(type="text/x-template") th(colspan='3') Cutter Radius Compensation tr.unimplemented(v-if="showUnimplemented") td - a(target="_blank", href="#{base}/g-code.html#gcode:g40") G40 + a(target="_blank", href=`${base}/g-code.html#gcode:g40`) G40 td td Compensation Off tr.unimplemented(v-if="showUnimplemented") td - a(target="_blank", href="#{base}/g-code.html#gcode:g41-g42") G41,G42 + a(target="_blank", href=`${base}/g-code.html#gcode:g41-g42`) G41,G42 td D td Cutter Compensation tr.unimplemented(v-if="showUnimplemented") td - a(target="_blank", href="#{base}/g-code.html#gcode:g41.1-g42.1") + a(target="_blank", href=`${base}/g-code.html#gcode:g41.1-g42.1`) | G41.1, G42.1 td D L td Dynamic Cutter Compensation @@ -283,13 +283,13 @@ script#cheat-sheet-view-template(type="text/x-template") th(colspan='3') Path Control Mode tr.unimplemented(v-if="showUnimplemented") td - a(target="_blank", href="#{base}/g-code.html#gcode:g61-g61.1") + a(target="_blank", href=`${base}/g-code.html#gcode:g61-g61.1`) | G61 G61.1 td td Exact Path Mode tr.unimplemented(v-if="showUnimplemented") td - a(target="_blank", href="#{base}/g-code.html#gcode:g64") G64 + a(target="_blank", href=`${base}/g-code.html#gcode:g64`) G64 td P Q td Path Blending @@ -298,17 +298,17 @@ script#cheat-sheet-view-template(type="text/x-template") th(colspan='3') Overrides tr.unimplemented(v-if="showUnimplemented") td - a(target="_blank", href="#{base}/m-code.html#mcode:m48-m49") M48, M49 + a(target="_blank", href=`${base}/m-code.html#mcode:m48-m49`) M48, M49 td td Speed and Feed Override Control tr.unimplemented(v-if="showUnimplemented") td - a(target="_blank", href="#{base}/m-code.html#mcode:m50") M50 + a(target="_blank", href=`${base}/m-code.html#mcode:m50`) M50 td P0 (off) or P1 (on) td Feed Override Control tr.unimplemented(v-if="showUnimplemented") td - a(target="_blank", href="#{base}/m-code.html#mcode:m51") M51 + a(target="_blank", href=`${base}/m-code.html#mcode:m51`) M51 td P0 (off) or P1 (on) td Spindle Speed Override Control @@ -317,56 +317,56 @@ script#cheat-sheet-view-template(type="text/x-template") th(colspan='3') Coordinate Systems, Offsets & Planes tr td - a(target="_blank", href="#{base}/g-code.html#gcode:g54-g59.3") + a(target="_blank", href=`${base}/g-code.html#gcode:g54-g59.3`) | G54-G59.3 td td Select Coordinate System tr td - a(target="_blank", href="#{base}/g-code.html#gcode:g10-l2") G10 L2 + a(target="_blank", href=`${base}/g-code.html#gcode:g10-l2`) G10 L2 td P R td Set Coordinate System tr td - a(target="_blank", href="#{base}/g-code.html#gcode:g10-l20") G10 L20 + a(target="_blank", href=`${base}/g-code.html#gcode:g10-l20`) G10 L20 td P td Set Coordinate System tr td - a(target="_blank", href="#{base}/g-code.html#gcode:g53") G53 + a(target="_blank", href=`${base}/g-code.html#gcode:g53`) G53 td td Move in Machine Coordinates tr td - a(target="_blank", href="#{base}/g-code.html#gcode:g92") G92 + a(target="_blank", href=`${base}/g-code.html#gcode:g92`) G92 td td Coordinate System Offset tr td - a(target="_blank", href="#{base}/g-code.html#gcode:g92.1-g92.2") + a(target="_blank", href=`${base}/g-code.html#gcode:g92.1-g92.2`) | G92.1, G92.2 td td Reset G92 Offsets tr td - a(target="_blank", href="#{base}/g-code.html#gcode:g92.3") G92.3 + a(target="_blank", href=`${base}/g-code.html#gcode:g92.3`) G92.3 td td Restore G92 Offsets tr td - a(target="_blank", href="#{base}/g-code.html#gcode:g28-g28.1") + a(target="_blank", href=`${base}/g-code.html#gcode:g28-g28.1`) | G28, G28.1 td td Go/Set Predefined Position tr td - a(target="_blank", href="#{base}/g-code.html#gcode:g30-g30.1") + a(target="_blank", href=`${base}/g-code.html#gcode:g30-g30.1`) | G30, G30.1 td td Go/Set Predefined Position tr td - a(target="_blank", href="#{base}/g-code.html#gcode:g17-g19.1") + a(target="_blank", href=`${base}/g-code.html#gcode:g17-g19.1`) | G17 - G19.1 td (affects G2, G3, G81…G89, G40…G42) td Plane Select @@ -376,33 +376,33 @@ script#cheat-sheet-view-template(type="text/x-template") th(colspan='3') Flow-control Codes tr td - a(target="_blank", href="#{base}/o-code.html#ocode:subroutines") + a(target="_blank", href=`${base}/o-code.html#ocode:subroutines`) | o sub/endsub/call td td Subroutines, sub/endsub call tr td - a(target="_blank", href="#{base}/o-code.html#ocode:looping") o while + a(target="_blank", href=`${base}/o-code.html#ocode:looping`) o while td td Looping, while/endwhile do/while tr td - a(target="_blank", href="#{base}/o-code.html#ocode:conditional") o if + a(target="_blank", href=`${base}/o-code.html#ocode:conditional`) o if td td Conditional, if/else/endif tr td - a(target="_blank", href="#{base}/o-code.html#ocode:repeat") o repeat + a(target="_blank", href=`${base}/o-code.html#ocode:repeat`) o repeat td td Repeat a loop of code tr td - a(target="_blank", href="#{base}/o-code.html#ocode:indirection") [] + a(target="_blank", href=`${base}/o-code.html#ocode:indirection`) [] td td Indirection tr.unimplemented(v-if="showUnimplemented") td - a(target="_blank", href="#{base}/o-code.html#ocode:calling-files") + a(target="_blank", href=`${base}/o-code.html#ocode:calling-files`) | o call td td Call named or numbered file @@ -412,22 +412,22 @@ script#cheat-sheet-view-template(type="text/x-template") th(colspan='3') Modal State tr td - a(target="_blank", href="#{base}/m-code.html#mcode:m70") M70 + a(target="_blank", href=`${base}/m-code.html#mcode:m70`) M70 td td Save modal state tr td - a(target="_blank", href="#{base}/m-code.html#mcode:m71") M71 + a(target="_blank", href=`${base}/m-code.html#mcode:m71`) M71 td td Invalidate stored state tr td - a(target="_blank", href="#{base}/m-code.html#mcode:m72") M72 + a(target="_blank", href=`${base}/m-code.html#mcode:m72`) M72 td td Restore modal state tr td - a(target="_blank", href="#{base}/m-code.html#mcode:m73") M73 + a(target="_blank", href=`${base}/m-code.html#mcode:m73`) M73 td td Save and Auto-restore modal state @@ -436,22 +436,22 @@ script#cheat-sheet-view-template(type="text/x-template") th(colspan='3') Input/Output tr.unimplemented(v-if="showUnimplemented") td - a(target="_blank", href="#{base}/m-code.html#mcode:m62-m65") M62 - M65 + a(target="_blank", href=`${base}/m-code.html#mcode:m62-m65`) M62 - M65 td P td Digital Output Control tr.unimplemented(v-if="showUnimplemented") td - a(target="_blank", href="#{base}/m-code.html#mcode:m66") M66 + a(target="_blank", href=`${base}/m-code.html#mcode:m66`) M66 td P E L Q td Wait on Input tr.unimplemented(v-if="showUnimplemented") td - a(target="_blank", href="#{base}/m-code.html#mcode:m67") M67 + a(target="_blank", href=`${base}/m-code.html#mcode:m67`) M67 td T td Analog Output,Synchronized tr.unimplemented(v-if="showUnimplemented") td - a(target="_blank", href="#{base}/m-code.html#mcode:m68") M68 + a(target="_blank", href=`${base}/m-code.html#mcode:m68`) M68 td T td Analog Output, Immediate @@ -460,7 +460,7 @@ script#cheat-sheet-view-template(type="text/x-template") th(colspan='3') User Defined Commands tr.unimplemented(v-if="showUnimplemented") td - a(target="_blank", href="#{base}/m-code.html#mcode:m100-m199") + a(target="_blank", href=`${base}/m-code.html#mcode:m100-m199`) | M101 - M199 td P Q td User Defined Commands @@ -470,47 +470,47 @@ script#cheat-sheet-view-template(type="text/x-template") th(colspan='3') Canned cycles tr td - a(target="_blank", href="#{base}/g-code.html#gcode:g80") G80 + a(target="_blank", href=`${base}/g-code.html#gcode:g80`) G80 td td Cancel Canned Cycle tr td - a(target="_blank", href="#{base}/g-code.html#gcode:g81") G81 + a(target="_blank", href=`${base}/g-code.html#gcode:g81`) G81 td R L (P) td Drilling Cycle tr td - a(target="_blank", href="#{base}/g-code.html#gcode:g82") G82 + a(target="_blank", href=`${base}/g-code.html#gcode:g82`) G82 td R L (P) td Drilling Cycle, Dwell tr.unimplemented(v-if="showUnimplemented") td - a(target="_blank", href="#{base}/g-code.html#gcode:g83") G83 + a(target="_blank", href=`${base}/g-code.html#gcode:g83`) G83 td R L Q td Drilling Cycle, Peck tr td - a(target="_blank", href="#{base}/g-code.html#gcode:g73") G73 + a(target="_blank", href=`${base}/g-code.html#gcode:g73`) G73 td R L Q td Drilling Cycle, Chip Breaking tr td - a(target="_blank", href="#{base}/g-code.html#gcode:g85") G85 + a(target="_blank", href=`${base}/g-code.html#gcode:g85`) G85 td R L (P) td Boring Cycle, Feed Out tr td - a(target="_blank", href="#{base}/g-code.html#gcode:g89") G89 + a(target="_blank", href=`${base}/g-code.html#gcode:g89`) G89 td R L (P) td Boring Cycle, Dwell, Feed Out tr.unimplemented(v-if="showUnimplemented") td - a(target="_blank", href="#{base}/g-code.html#gcode:g76") G76 + a(target="_blank", href=`${base}/g-code.html#gcode:g76`) G76 td P Z I J R K Q H L E td Threading Cycle tr.unimplemented(v-if="showUnimplemented") td - a(target="_blank", href="#{base}/g-code.html#gcode:g98-g99") G98, G99 + a(target="_blank", href=`${base}/g-code.html#gcode:g98-g99`) G98, G99 td td Canned Cycle Return Level @@ -519,23 +519,23 @@ script#cheat-sheet-view-template(type="text/x-template") th(colspan='3') Comments & Messages tr td - a(target="_blank", href="#{base}/overview.html#gcode:comments") ; (…) + a(target="_blank", href=`${base}/overview.html#gcode:comments`) ; (…) td td Comments tr td - a(target="_blank", href="#{base}/overview.html#gcode:messages") + a(target="_blank", href=`${base}/overview.html#gcode:messages`) | (MSG,…) td td Messages tr.unimplemented(v-if="showUnimplemented") td - a(target="_blank", href="#{base}/overview.html#gcode:debug") (DEBUG,…) + a(target="_blank", href=`${base}/overview.html#gcode:debug`) (DEBUG,…) td td Debug Messages tr.unimplemented(v-if="showUnimplemented") td - a(target="_blank", href="#{base}/overview.html#gcode:print") (PRINT,…) + a(target="_blank", href=`${base}/overview.html#gcode:print`) (PRINT,…) td td Print Messages @@ -548,7 +548,7 @@ script#cheat-sheet-view-template(type="text/x-template") p | The Buildbotics controller implements a subset of LinuxCNC GCode. | Supported commands are listed above. You can find further help with - | GCode + | #[a(href="http://wikipedia.com/wiki/G-code", target="_blank") GCode] | programming on the LinuxCNC website: ul diff --git a/src/pug/templates/control-view.pug b/src/pug/templates/control-view.pug index 7b753bb..e965f55 100644 --- a/src/pug/templates/control-view.pug +++ b/src/pug/templates/control-view.pug @@ -42,29 +42,29 @@ script#control-view-template(type="text/x-template") .fa.fa-home each axis in 'xyzabc' - tr.axis(:class="{'homed': is_homed('#{axis}'), 'axis-#{axis}': true}", - v-if="enabled('#{axis}')") - th.name #{axis} + tr.axis(:class=`{'homed': is_homed('${axis}'), 'axis-${axis}': true}`, + v-if=`enabled('${axis}')`) + th.name= axis td.position - unit-value(:value="get_position('#{axis}')", precision="4") - td.absolute: unit-value(:value="state.#{axis}p", precision="3") - td.offset: unit-value(:value="get_offset('#{axis}')", precision="3") + unit-value(:value=`get_position('${axis}')`, precision="4") + td.absolute: unit-value(:value="state." + axis + "p", precision="3") + td.offset: unit-value(:value=`get_offset('${axis}')`, precision="3") th.actions button.pure-button(:disabled="!is_ready", - title="Set {{'#{axis}' | upper}} axis position.", - @click="show_set_position('#{axis}')") + title=`Set {{'${axis}' | upper}} axis position.`, + @click=`show_set_position('${axis}')`) .fa.fa-cog button.pure-button(:disabled="!is_ready", - title="Zero {{'#{axis}' | upper}} axis offset.", - @click="zero('#{axis}')") ∅ + title=`Zero {{'${axis}' | upper}} axis offset.`, + @click=`zero('${axis}')`) ∅ button.pure-button(:disabled="!is_ready", - title="Home {{'#{axis}' | upper}} axis.", - @click="home('#{axis}')") + title=`Home {{'${axis}' | upper}} axis.`, + @click=`home('${axis}')`) .fa.fa-home - message(:show.sync="position_msg['#{axis}']") + message(:show.sync=`position_msg['${axis}']`) h3(slot="header") Set {{'#{axis}' | upper}} axis position div(slot="body") @@ -72,21 +72,21 @@ script#control-view-template(type="text/x-template") .pure-control-group label Position input(v-model="axis_position", - @keyup.enter="set_position('#{axis}', axis_position)") + @keyup.enter=`set_position('${axis}', axis_position)`) p div(slot="footer") - button.pure-button(@click="position_msg['#{axis}'] = false") + button.pure-button(@click=`position_msg['${axis}'] = false`) | Cancel - button.pure-button(v-if="is_homed('#{axis}')", - @click="unhome('#{axis}')") Unhome + button.pure-button(v-if="is_homed('" + axis + "')", + @click=`unhome('${axis}')`) Unhome button.pure-button.button-success( - @click="set_position('#{axis}', axis_position)") Set + @click=`set_position('${axis}', axis_position)`) Set - message(:show.sync="manual_home['#{axis}']") + message(:show.sync=`manual_home['${axis}']`) h3(slot="header") Manually home {{'#{axis}' | upper}} axis div(slot="body") @@ -96,17 +96,17 @@ script#control-view-template(type="text/x-template") .pure-control-group label Absolute input(v-model="axis_position", - @keyup.enter="set_home('#{axis}', axis_position)") + @keyup.enter=`set_home('${axis}', axis_position)`) p div(slot="footer") - button.pure-button(@click="manual_home['#{axis}'] = false") + button.pure-button(@click=`manual_home['${axis}'] = false`) | Cancel button.pure-button.button-success( - title="Home {{'#{axis}' | upper}} axis.", - @click="set_home('#{axis}', axis_position)") Set + title=`Home {{'${axis}' | upper}} axis.`, + @click=`set_home('${axis}', axis_position)`) Set table.info tr @@ -157,21 +157,22 @@ script#control-view-template(type="text/x-template") tr th Time td(title="Total run time (days:hours:mins:secs)") - | {{toolpath.time / 1000 | time}} + span(v-if="plan_time") {{plan_time | time}} of  + | {{toolpath.time | time}} tr th ETA - td + td {{eta}} tr th Line td - | {{0 <= state.line ? state.line : '0'}} + | {{0 <= state.line ? state.line : 0 | number}} span(v-if="toolpath.lines") |  of {{toolpath.lines | number}} tr th Progress td.progress - label {{(state.progress || 0) | percent}} - .bar(:style="'width:' + (state.progress || 0.01) * 100 + '%'") + label {{(progress || 0) | percent}} + .bar(:style="'width:' + (progress || 0) * 100 + '%'") .override(title="Feed rate override.") label Feed @@ -221,15 +222,16 @@ script#control-view-template(type="text/x-template") .fa.fa-step-forward button.pure-button(title="Upload a new GCode program.", @click="open", - :disabled="is_running || is_stopping") + :disabled="!is_ready") .fa.fa-folder-open input.gcode-file-input(type="file", @change="upload", - style="display:none", accept=".nc,.gcode,.gc,.ngc") + style="display:none", accept=".nc,.gcode,.gc,.ngc", + :disabled="!is_ready") button.pure-button(title="Delete current GCode program.", @click="deleteGCode = true", - :disabled="!state.selected || is_running || is_stopping") + :disabled="!state.selected || !is_ready") .fa.fa-trash message(:show.sync="deleteGCode") @@ -245,8 +247,7 @@ script#control-view-template(type="text/x-template") |  selected select(title="Select previously uploaded GCode programs.", - v-model="state.selected", @change="load", - :disabled="is_running || is_stopping") + v-model="state.selected", @change="load", :disabled="!is_ready") option(v-for="file in files", :value="file") {{file}} path-viewer(:toolpath="toolpath", :progress="progress", diff --git a/src/pug/templates/help-view.pug b/src/pug/templates/help-view.pug index 1c0187b..6982a71 100644 --- a/src/pug/templates/help-view.pug +++ b/src/pug/templates/help-view.pug @@ -29,25 +29,33 @@ script#help-view-template(type="text/x-template") #help h2 User Manual p - | You can find a detailed user manual at docs.buildbotics.com. + | You can find a detailed user manual at + | + a(href="http://docs.buildbotics.com", target="_blank") + | docs.buildbotics.com + |. h2 Discussion Forum p | If you're having trouble or just want to chat with other Buildbotics | CNC controller owners, head over to the Buildbotics forum at - | forum.buildbotics.com. Register on the site and post a message. - | We'll be happy to help. + | + a(href="http://forum.buildbotics.com", target="_blank") + | forum.buildbotics.com + |. Register on the site and post a message. We'll be happy to help. h2 CAD/CAM Software p - | CAM software can be used to create GCode + a(href="http://wikipedia.com/wiki/Computer-aided_manufacturing", + target="_blank") CAM + | + | software can be used to create GCode | automatically from - | CAD models. Here are a few CAD/CAM resources: + | + a(href="http://wikipedia.com/wiki/Computer-aided_design", + target="_blank") CAD + | + | models. Here are a few CAD/CAM resources: ul li: a(href="http://camotics.org/", target="_blank") | CAMotics - Open-Source CNC Simulator diff --git a/src/pug/templates/indicators.pug b/src/pug/templates/indicators.pug index f9650c4..9cec814 100644 --- a/src/pug/templates/indicators.pug +++ b/src/pug/templates/indicators.pug @@ -68,14 +68,14 @@ script#indicators-template(type="text/x-template") each motor in '0123' tr td - .fa.io(:class="get_input_class('#{motor}lw', '#{motor}ls')", - :title="get_input_tooltip('#{motor}lw', '#{motor}ls')") + .fa.io(:class=`get_input_class('${motor}lw', '${motor}ls')`, + :title=`get_input_tooltip('${motor}lw', '${motor}ls')`) td {{get_min_pin(#{motor})}} th Motor #{motor} Min th.separator td - .fa.io(:class="get_input_class('#{motor}xw', '#{motor}xs')", - :title="get_input_tooltip('#{motor}xw', '#{motor}xs')") + .fa.io(:class=`get_input_class('${motor}xw', '${motor}xs')`, + :title=`get_input_tooltip('${motor}xw', '${motor}xs')`) td {{get_max_pin(#{motor})}} th Motor #{motor} Max @@ -239,7 +239,7 @@ script#indicators-template(type="text/x-template") th Current h2 DB25 breakout box - img(width=700, src="/images/DB25_breakout_box.png") + img(width=700, src="images/DB25_breakout_box.png") h2 DB25-M2 breakout - img(width=400, src="/images/DB25-M2_breakout.png") + img(width=400, src="images/DB25-M2_breakout.png") diff --git a/src/pug/templates/path-viewer.pug b/src/pug/templates/path-viewer.pug index 044ac6b..33ce4b0 100644 --- a/src/pug/templates/path-viewer.pug +++ b/src/pug/templates/path-viewer.pug @@ -32,19 +32,21 @@ script#path-viewer-template(type="text/x-template") @click="small = !small", :class="{active: !small}") .fa.fa-arrows-alt - tool-button(name="tool", :active="showTool", - @click="showTool = !showTool", title="Show/hide tool.") - tool-button(name="bbox", :active="showBBox", - @click="showBBox = !showBBox", title="Show/hide bounding box.") - tool-button(name="axes", :active="showAxes", - @click="showAxes = !showAxes", title="Show/hide axes.") + .tool-button(@click="showTool = !showTool", :active="showTool", + title="Show/hide tool.") + img(src="images/tool.png") - tool-button(name="isometric", @click="snap('isometric')", - title="Snap to isometric view.") - tool-button(name="top", @click="snap('top')", - title="Snap to top view.") - tool-button(name="front", @click="snap('front')", - title="Snap to front view.") + .tool-button(@click="showBBox = !showBBox", :active="showBBox", + title="Show/hide bounding box.") + img(src="images/bbox.png") + + .tool-button(@click="showAxes = !showAxes", :active="showAxes", + title="Show/hide axes.") + img(src="images/axes.png") + + each view in "isometric top front".split(" ") + .tool-button(@click=`snap('${view}')`, title=`Snap to ${view} view.`) + img(src=`images/${view}.png`) .path-viewer-content(:class="{small: small}") .path-viewer-message(:class="{error: error}") @@ -63,8 +65,8 @@ script#path-viewer-template(type="text/x-template") th Message tr(v-for="msg in toolpath.messages", :class="'log-' + msg.level") - td {{msg.level}} - td + td.level {{msg.level}} + td.location | {{msg.line}} span(v-if="msg.column") :{{msg.column}} - td {{msg.msg}} + td.message {{msg.msg}} diff --git a/src/pug/templates/settings-view.pug b/src/pug/templates/settings-view.pug index cd3444b..dd56872 100644 --- a/src/pug/templates/settings-view.pug +++ b/src/pug/templates/settings-view.pug @@ -31,8 +31,8 @@ script#settings-view-template(type="text/x-template") :template="template.settings.units") p - | Note, units sets both the machine default units and the - | units used in motor configuration. GCode program-start, + | Note, #[tt units] sets both the machine default units and the + | units used in motor configuration. GCode #[tt program-start], | set below, may also change the default machine units. fieldset diff --git a/src/pug/templates/tool-button.pug b/src/pug/templates/tool-button.pug deleted file mode 100644 index 8306fba..0000000 --- a/src/pug/templates/tool-button.pug +++ /dev/null @@ -1,28 +0,0 @@ -//-///////////////////////////////////////////////////////////////////////////// -//- // -//- Copyright (c) 2018, Cauldron Development LLC // -//- All rights reserved. // -//- // -//- This file ("the software") is free software: you can redistribute it // -//- and/or modify it under the terms of the GNU General Public License, // -//- version 2 as published by the Free Software Foundation. You should // -//- have received a copy of the GNU General Public License, version 2 // -//- along with the software. If not, see . // -//- // -//- The software is distributed in the hope that it will be useful, but // -//- WITHOUT ANY WARRANTY; without even the implied warranty of // -//- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // -//- Lesser General Public License for more details. // -//- // -//- You should have received a copy of the GNU Lesser General Public // -//- License along with the software. If not, see // -//- . // -//- // -//- For information regarding this software email: // -//- "Joseph Coffland" // -//- // -//-///////////////////////////////////////////////////////////////////////////// - -script#tool-button-template(type="text/x-template") - .tool-button(:class="{'active': active}") - img(:src="'images/' + name + '.png'") diff --git a/src/pug/templates/tool-view.pug b/src/pug/templates/tool-view.pug index e889502..023ec95 100644 --- a/src/pug/templates/tool-view.pug +++ b/src/pug/templates/tool-view.pug @@ -54,8 +54,8 @@ script#tool-view-template(type="text/x-template") v-if="is_modbus && this.tool_type != 'HUANYANG VFD'") h2 Active Modbus Program p - | (Click Save to activate the selected - | tool-type.) + | (Click #[tt(class="save") Save] to activate the selected + | #[b tool-type].) table.modbus-regs.fixed-regs tr th Index @@ -121,22 +121,25 @@ script#tool-view-template(type="text/x-template") td.reg-addr PD163 td.reg-value 1 td Modbus ID - td Must match bus-id above. + td Must match #[tt bus-id] above. tr td.reg-addr PD164 td.reg-value 1 td 9600 baud - td Must match baud above. + td Must match #[tt baud] above. tr td.reg-addr PD166 td.reg-value 3 td 8 bit, no parity, RTU mode - td Must match parity above. + td Must match #[tt parity] above. p - | Other settings according to the Huanyang VFD manual and spindle type. + | Other settings according to the + | + a(href="https://buildbotics.com/upload/vfd/Huanyang-VFD-manual.pdf", + target="_blank") Huanyang VFD manual + | + | and spindle type. .notes(v-if="tool_type.startsWith('DELTA VFD015M21A')") h2 Notes @@ -161,17 +164,17 @@ script#tool-view-template(type="text/x-template") td.reg-addr Pr.88 td.reg-value 1 td Modbus ID - td Must match bus-id above + td Must match #[tt bus-id] above tr td.reg-addr Pr.89 td.reg-value 1 td 9600 baud - td Must match baud above + td Must match #[tt baud] above tr td.reg-addr Pr.92 td.reg-value 3 td 8 bit, no parity, RTU mode - td Must match parity above + td Must match #[tt parity] above tr td.reg-addr Pr.157 td.reg-value 1 @@ -179,6 +182,9 @@ script#tool-view-template(type="text/x-template") td Communication mode p - | Other settings according to the Delta VFD015M21A VFD manual and spindle type. + | Other settings according to the + | + a(href="https://buildbotics.com/upload/vfd/Delta_VFD015M21A.pdf", + target="_blank") Delta VFD015M21A VFD manual + | + | and spindle type. diff --git a/src/py/bbctrl/Ctrl.py b/src/py/bbctrl/Ctrl.py index 69028ca..47cfe85 100644 --- a/src/py/bbctrl/Ctrl.py +++ b/src/py/bbctrl/Ctrl.py @@ -48,6 +48,7 @@ class Ctrl(object): self.lcd = bbctrl.LCD(self) self.mach = bbctrl.Mach(self) self.preplanner = bbctrl.Preplanner(self) + self.planTimer = bbctrl.PlanTimer(self) self.jog = bbctrl.Jog(self) self.pwr = bbctrl.Pwr(self) diff --git a/src/py/bbctrl/PlanTimer.py b/src/py/bbctrl/PlanTimer.py new file mode 100644 index 0000000..997fb6d --- /dev/null +++ b/src/py/bbctrl/PlanTimer.py @@ -0,0 +1,106 @@ +################################################################################ +# # +# This file is part of the Buildbotics firmware. # +# # +# Copyright (c) 2015 - 2018, Buildbotics LLC # +# All rights reserved. # +# # +# This file ("the software") is free software: you can redistribute it # +# and/or modify it under the terms of the GNU General Public License, # +# version 2 as published by the Free Software Foundation. You should # +# have received a copy of the GNU General Public License, version 2 # +# along with the software. If not, see . # +# # +# The software is distributed in the hope that it will be useful, but # +# WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # +# Lesser General Public License for more details. # +# # +# You should have received a copy of the GNU Lesser General Public # +# License along with the software. If not, see # +# . # +# # +# For information regarding this software email: # +# "Joseph Coffland" # +# # +################################################################################ + +import logging +import time +import bbctrl + +log = logging.getLogger('PlanTimer') + + +class PlanTimer(object): + def __init__(self, ctrl): + self.ctrl = ctrl + + self.reset() + self._report() + + self.ctrl.state.set('plan_time', 0) + ctrl.state.add_listener(self._update) + + + def reset(self): + self.plan_time = 0 + self.move_start = None + self.hold_start = None + self.plan_times = None + self.plan_index = 0 + + + def _report(self): + if (self.plan_times is not None and + self.plan_index < len(self.plan_times) and + self.move_start is not None): + state = self.ctrl.state.get('xx', '') + + if state in ['STOPPING', 'RUNNING']: + t = self.plan_time + delta = time.time() - self.move_start + nextT = self.plan_times[self.plan_index][1] + if t + delta < nextT: t += delta + else: t = nextT + + self.ctrl.state.set('plan_time', round(t)) + + self.timer = self.ctrl.ioloop.call_later(1, self._report) + + + def _update(self, update): + # Check state + if 'xx' in update: + state = update['xx'] + + if state in ['READY', 'ESTOPPED']: + self.ctrl.state.set('plan_time', 0) + self.reset() + + elif state == 'HOLDING': self.hold_start = time.time() + elif state == 'RUNNING' and self.hold_start is not None: + self.move_start += time.time() - self.hold_start + self.hold_start = None + + # Get plan times + if self.plan_times is None or 'selected' in update: + active_plan = self.ctrl.state.get('selected', '') + + if active_plan: + plan = self.ctrl.preplanner.get_plan(active_plan) + + if plan is not None and plan.done(): + self.reset() + self.plan_times = plan.result()[1] + + # Get plan time for current id + if self.plan_times is not None and 'id' in update: + currentID = update['id'] + + while self.plan_index < len(self.plan_times): + id, t = self.plan_times[self.plan_index] + if id <= currentID: self.move_start = time.time() + if currentID <= id: break + self.plan_time = t + self.plan_index += 1 diff --git a/src/py/bbctrl/Planner.py b/src/py/bbctrl/Planner.py index b1db478..4d228bd 100644 --- a/src/py/bbctrl/Planner.py +++ b/src/py/bbctrl/Planner.py @@ -38,7 +38,11 @@ from bbctrl.CommandQueue import CommandQueue log = logging.getLogger('Planner') reLogLine = re.compile( - r'^(?P[A-Z])[0-9 ]:((?P[^:]+:\d+:\d+):)?(?P.*)$') + r'^(?P[A-Z])[0-9 ]:' + r'((?P[^:]+):)?' + r'((?P\d+):)?' + r'((?P\d+):)?' + r'(?P.*)$') class Planner(): @@ -47,7 +51,6 @@ class Planner(): self.cmdq = CommandQueue() self.logLock = threading.Lock() self.logIntercept = {} - self.time = 0 ctrl.state.add_listener(self._update) @@ -173,10 +176,14 @@ class Planner(): level = m.group('level') msg = m.group('msg') - where = m.group('where') + filename = m.group('file') + line = m.group('line') + column = m.group('column') - if where is not None: filename, line, column = where.split(':') - else: filename, line, column = None, None, None + where = ':'.join(filter(None.__ne__, [filename, line, column])) + + if line is not None: line = int(line) + if column is not None: column = int(column) # Per thread log intercept with self.logLock: @@ -185,7 +192,7 @@ class Planner(): self.logIntercept[tid](level, msg, filename, line, column) return - if where is not None: extra = dict(where = where) + if where: extra = dict(where = where) else: extra = None if level == 'I': log.info (msg, extra = extra) @@ -202,10 +209,10 @@ class Planner(): def __encode(self, block): - log.info('Cmd:' + json.dumps(block)) - type, id = block['type'], block['id'] + if type != 'set': log.info('Cmd:' + json.dumps(block)) + if type == 'line': return Cmd.line(block['target'], block['exit-vel'], block['max-accel'], block['max-jerk'], diff --git a/src/py/bbctrl/Preplanner.py b/src/py/bbctrl/Preplanner.py index 09290bb..92e62a2 100644 --- a/src/py/bbctrl/Preplanner.py +++ b/src/py/bbctrl/Preplanner.py @@ -103,7 +103,8 @@ class Preplanner(object): self.max_plan_time = max_plan_time self.max_loop_time = max_loop_time - if not os.path.exists('plans'): os.mkdir('plans') + for dir in ['plans', 'times']: + if not os.path.exists(dir): os.mkdir(dir) self.started = Future() @@ -168,7 +169,8 @@ class Preplanner(object): # Copy state for thread state = self.ctrl.state.snapshot() - config = self.ctrl.mach.planner.get_config(False, True) + config = self.ctrl.mach.planner.get_config(False, False) + del config['default-units'] # Start planner thread plan = yield self.pool.submit(self._exec_plan, filename, state, config) @@ -200,8 +202,16 @@ class Preplanner(object): # Check if this plan was already run hid = plan_hash(filename, config) plan_path = 'plans/' + filename + '.' + hid + '.gz' - if os.path.exists(plan_path): - with open(plan_path, 'rb') as f: return f.read() + times_path = 'times/' + filename + '.' + hid + '.gz' + + try: + if os.path.exists(plan_path) and os.path.exists(times_path): + with open(plan_path, 'rb') as f: data = f.read() + with open(times_path, 'rb') as f: times = f.read() + return (data, json.loads(gzip.decompress(times).decode('utf8'))) + + except Exception as e: log.error(e) + # Clean up old plans self._clean_plans(filename) @@ -227,6 +237,7 @@ class Preplanner(object): position = dict(x = 0, y = 0, z = 0) rapid = False moves = [] + times = [] messages = [] count = 0 @@ -247,12 +258,15 @@ class Preplanner(object): try: while planner.has_more(): cmd = planner.next() - planner.set_active(cmd['id']) + planner.set_active(cmd['id']) # Release plan + # Cannot synchronize with actual machine so fake it if planner.is_synchronizing(): planner.synchronize(0) if cmd['type'] == 'line': - totalTime += sum(cmd['times']) + if not 'first' in cmd: + totalTime += sum(cmd['times']) / 1000 + times.append((cmd['id'], totalTime)) target = cmd['target'] move = {} @@ -272,7 +286,9 @@ class Preplanner(object): maxLine = line maxLineTime = time.time() - elif cmd['type'] == 'dwell': totalTime += cmd['seconds'] + elif cmd['type'] == 'dwell': + totalTime += cmd['seconds'] + times.append((cmd['id'], totalTime)) if not self._progress(filename, maxLine / totalLines): raise Exception('Plan canceled.') @@ -298,7 +314,9 @@ class Preplanner(object): messages = messages) data = gzip.compress(dump_json(data).encode('utf8')) - # Save plan + # Save plan & times with open(plan_path, 'wb') as f: f.write(data) + with open(times_path, 'wb') as f: + f.write(gzip.compress(dump_json(times).encode('utf8'))) - return data + return (data, times) diff --git a/src/py/bbctrl/Web.py b/src/py/bbctrl/Web.py index ff68566..f63d4b3 100644 --- a/src/py/bbctrl/Web.py +++ b/src/py/bbctrl/Web.py @@ -249,6 +249,7 @@ class PathHandler(bbctrl.APIHandler): return if data is not None: + data = data[0] self.set_header('Content-Encoding', 'gzip') # Respond with chunks to avoid long delays diff --git a/src/py/bbctrl/__init__.py b/src/py/bbctrl/__init__.py index ff0d08d..098a80f 100644 --- a/src/py/bbctrl/__init__.py +++ b/src/py/bbctrl/__init__.py @@ -57,6 +57,7 @@ from bbctrl.CommandQueue import CommandQueue from bbctrl.MainLCDPage import MainLCDPage from bbctrl.IPLCDPage import IPLCDPage from bbctrl.Camera import Camera, VideoHandler +from bbctrl.PlanTimer import PlanTimer import bbctrl.Cmd as Cmd import bbctrl.v4l2 as v4l2 diff --git a/src/stylus/style.styl b/src/stylus/style.styl index 8fc0de6..56d5a65 100644 --- a/src/stylus/style.styl +++ b/src/stylus/style.styl @@ -495,6 +495,15 @@ span.unit background-color inherit color #ff3a3a + .path-viewer-messages + margin 0.125em 0 + + th, td + padding 0.125em + + &.level + text-transform capitalize + .path-viewer-content background-color #333 background linear-gradient(to bottom, #666 0%, #222 100%); -- 2.27.0