From bc161fcd3d6542bafd982348d2e1c04dc23a24b2 Mon Sep 17 00:00:00 2001 From: David Carley Date: Thu, 7 Jul 2022 12:48:20 -0700 Subject: [PATCH] checkpoint --- package-lock.json | 11 - package.json | 1 - src/js/app.js | 76 +-- src/js/axis-vars.js | 7 +- src/js/control-view.js | 547 ++++++------------ src/js/main.js | 114 ++-- src/js/motor-view.js | 98 ++-- src/js/settings-view.js | 41 +- src/js/templated-input.js | 80 +-- src/js/unit-value.js | 65 +-- src/pug/templates/control-view.pug | 145 +---- src/pug/templates/settings-view.pug | 35 +- src/pug/templates/templated-input.pug | 27 - src/py/bbctrl/Ctrl.py | 29 - src/py/bbctrl/State.py | 8 - src/stylus/style.styl | 8 +- .../src/components/AdminNetworkView.svelte | 7 +- .../src/components/DialogHost.svelte | 6 - .../src/dialogs/ChangeHostnameDialog.svelte | 4 +- .../src/dialogs/DialogHost.svelte | 38 ++ .../src/dialogs/DialogProps.ts | 13 + .../src/dialogs/ProbeDialog.svelte | 293 ++++++++++ .../src/dialogs/WifiConnectionDialog.svelte | 16 +- src/svelte-components/src/lib/ConfigStore.ts | 7 + src/svelte-components/src/lib/DialogProps.ts | 16 - src/svelte-components/src/lib/NetworkInfo.ts | 2 +- .../src/lib/RegisterControllerMethods.ts | 10 + src/svelte-components/src/lib/StoreHelpers.ts | 18 + src/svelte-components/src/main.ts | 28 +- src/svelte-components/tsconfig.json | 5 + src/svelte-components/vite.config.ts | 7 + 31 files changed, 834 insertions(+), 928 deletions(-) delete mode 100644 src/svelte-components/src/components/DialogHost.svelte create mode 100644 src/svelte-components/src/dialogs/DialogHost.svelte create mode 100644 src/svelte-components/src/dialogs/DialogProps.ts create mode 100644 src/svelte-components/src/dialogs/ProbeDialog.svelte create mode 100644 src/svelte-components/src/lib/ConfigStore.ts delete mode 100644 src/svelte-components/src/lib/DialogProps.ts create mode 100644 src/svelte-components/src/lib/RegisterControllerMethods.ts create mode 100644 src/svelte-components/src/lib/StoreHelpers.ts diff --git a/package-lock.json b/package-lock.json index 79d0427..20d79b6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,7 +15,6 @@ "jstransformer-scss": "^2.0.0", "jstransformer-stylus": "^1.5.0", "lodash.merge": "4.6.2", - "lodash.omit": "^4.5.0", "pug-cli": "^1.0.0-alpha6" } }, @@ -1915,11 +1914,6 @@ "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" }, - "node_modules/lodash.omit": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.omit/-/lodash.omit-4.5.0.tgz", - "integrity": "sha512-XeqSp49hNGmlkj2EJlfrQFIzQ6lXdNro9sddtQzcJY8QaoC2GO0DT7xaIokHeyM+mIT0mPMlPvkYzg2xCuHdZg==" - }, "node_modules/longest": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", @@ -4614,11 +4608,6 @@ "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" }, - "lodash.omit": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.omit/-/lodash.omit-4.5.0.tgz", - "integrity": "sha512-XeqSp49hNGmlkj2EJlfrQFIzQ6lXdNro9sddtQzcJY8QaoC2GO0DT7xaIokHeyM+mIT0mPMlPvkYzg2xCuHdZg==" - }, "longest": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", diff --git a/package.json b/package.json index f16e20b..9b82c1b 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,6 @@ "jstransformer-scss": "^2.0.0", "jstransformer-stylus": "^1.5.0", "lodash.merge": "4.6.2", - "lodash.omit": "^4.5.0", "pug-cli": "^1.0.0-alpha6" } } diff --git a/src/js/app.js b/src/js/app.js index 3871766..50cacfc 100644 --- a/src/js/app.js +++ b/src/js/app.js @@ -3,7 +3,6 @@ const api = require("./api"); const cookie = require("./cookie")("bbctrl-"); const Sock = require("./sock"); -const omit = require("lodash.omit"); SvelteComponents.initNetworkInfo(); SvelteComponents.createComponent("DialogHost", @@ -84,6 +83,7 @@ module.exports = new Vue({ return { status: "connecting", currentView: "loading", + display_units: localStorage.getItem("display_units") || "METRIC", index: -1, modified: false, template: require("../resources/config-template.json"), @@ -95,10 +95,6 @@ module.exports = new Vue({ }, state: { messages: [], - probing_active: false, - wait_for_probing_complete: false, - show_probe_complete_modal: false, - show_probe_failed_modal: false, }, video_size: cookie.get("video-size", "small"), crosshair: cookie.get("crosshair", "false") != "false", @@ -130,11 +126,19 @@ module.exports = new Vue({ "cheat-sheet-view": { template: "#cheat-sheet-view-template", data: function () { - return { showUnimplemented: false }; + return { + showUnimplemented: false + }; }, }, }, + watch: { + display_units: function (value) { + localStorage.setItem("display_units", value); + }, + }, + events: { "config-changed": function () { this.modified = true; @@ -142,7 +146,6 @@ module.exports = new Vue({ send: function (msg) { if (this.status == "connected") { - console.debug(">", msg); this.sock.send(msg); } }, @@ -214,10 +217,6 @@ module.exports = new Vue({ }, methods: { - metric: function () { - return this.config.settings.units != "IMPERIAL"; - }, - block_error_dialog: function () { this.errorTimeoutStart = Date.now(); this.errorShow = false; @@ -297,6 +296,7 @@ module.exports = new Vue({ if (typeof check == "undefined" || check) this.$emit("check"); } + SvelteComponents.handleConfigUpdate(this.config); }, shutdown: function () { @@ -318,13 +318,9 @@ module.exports = new Vue({ } if ("log" in e.data) { - if (e.data.log.msg === "Switch not found") { - this.$broadcast("probing_failed"); - } else { + if (e.data.log.msg !== "Switch not found") { this.$broadcast("log", e.data.log); } - - delete e.data.log; } // Check for session ID change on controller @@ -343,37 +339,11 @@ module.exports = new Vue({ } } - // Set this to true to get console output of changes to the state - const debugStateChanges = false; - if (debugStateChanges) { - const data = omit(e.data, [ - "vdd", - "vin", - "vout", - "motor", - "temp", - "heartbeat", - "load1", - "load2", - "rpi_temp", - ]); - if (Object.keys(data).length > 0) { - console.log(JSON.stringify(data, null, 4)); - } - } - update_object(this.state, e.data, false); - if (this.state.pw === 0) { - Vue.set(this.state, "saw_probe_connected", true); - } + SvelteComponents.handleControllerStateUpdate(this.state); - if (this.state.cycle === "idle") { - if (this.state.wait_for_probing_complete) { - Vue.set(this.state, "wait_for_probing_complete", false); - this.$broadcast("probing_complete"); - } - } + delete this.state.log; this.$broadcast("update"); }; @@ -406,7 +376,7 @@ module.exports = new Vue({ this.currentView = parts[0]; }, - save: function () { + save: async function () { const selected_tool = this.config.tool["selected-tool"]; const saveModbus = selected_tool !== "pwm" && @@ -423,16 +393,12 @@ module.exports = new Vue({ this.config["selected-tool-settings"][selected_tool] = settings; - api - .put("config/save", this.config) - .done( - function (data) { - this.modified = false; - }.bind(this) - ) - .fail(function (error) { - api.alert("Save failed", error); - }); + try { + await api.put("config/save", this.config); + this.modified = false; + } catch (error) { + api.alert("Save failed", error); + } }, close_messages: function (action) { diff --git a/src/js/axis-vars.js b/src/js/axis-vars.js index 18c54e1..0f10539 100644 --- a/src/js/axis-vars.js +++ b/src/js/axis-vars.js @@ -4,6 +4,7 @@ module.exports = { props: ['state', 'config'], computed: { + metric: function () { this.$root.display_units === "METRIC" }, x: function () { return this._compute_axis('x') }, y: function () { return this._compute_axis('y') }, z: function () { return this._compute_axis('z') }, @@ -15,12 +16,14 @@ module.exports = { methods: { _convert_length: function (value) { - return this.state.imperial ? value / 25.4 : value; + return this.metric + ? value + : value / 25.4; }, _length_str: function (value) { return this._convert_length(value).toLocaleString() + - (this.state.imperial ? ' in' : ' mm'); + (this.metric ? ' mm' : ' in'); }, _compute_axis: function (axis) { diff --git a/src/js/control-view.js b/src/js/control-view.js index 53d7aee..1c54a26 100644 --- a/src/js/control-view.js +++ b/src/js/control-view.js @@ -1,30 +1,3 @@ -/******************************************************************************\ - - 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" - -\******************************************************************************/ - 'use strict' var api = require('./api'); @@ -36,7 +9,7 @@ module.exports = { data: function () { return { - mach_units: 'METRIC', + mach_units: this.$root.state.metric ? "METRIC" : "IMPERIAL", mdi: '', last_file: undefined, last_file_time: undefined, @@ -62,16 +35,26 @@ module.exports = { b: false, c: false }, + jog_incr_amounts: { + "METRIC": { + fine: 0.1, + small: 1.0, + medium: 10, + large: 100, + }, + "IMPERIAL": { + fine: 0.005, + small: 0.05, + medium: 0.5, + large: 5, + } + }, axis_position: 0, + jog_incr: localStorage.getItem("jog_incr") || 'small', jog_step: cookie.get_bool('jog-step'), jog_adjust: parseInt(cookie.get('jog-adjust', 2)), deleteGCode: false, tab: 'auto', - jog_incr: 1.0, - tool_diameter: 6.35, - tool_diameter_for_prompt: 6.35, - show_probe_test_modal: false, - show_tool_diameter_modal: false, toolpath_msg: { x: false, y: false, @@ -93,33 +76,24 @@ module.exports = { 'gcode-viewer': require('./gcode-viewer') }, - watch: { - 'state.imperial': { - handler: function (imperial) { - this.mach_units = imperial ? 'IMPERIAL' : 'METRIC'; - }, - immediate: true + jog_incr: function (value) { + localStorage.setItem("jog_incr", value); }, - 'state.bitDiameter': { - handler: function (bitDiameter) { - this.tool_diameter = bitDiameter; + 'state.metric': { + handler: function (metric) { + this.mach_units = metric + ? 'METRIC' + : 'IMPERIAL'; }, immediate: true }, - - mach_units: function (units) { - if ((units == 'METRIC') != this.metric) - this.send(units == 'METRIC' ? 'G21' : 'G20'); - - this.units_changed(); - }, - 'state.line': function () { - if (this.mach_state != 'HOMING') + if (this.mach_state != 'HOMING') { this.$broadcast('gcode-line', this.state.line); + } }, 'state.selected_time': function () { @@ -135,37 +109,56 @@ module.exports = { } }, - computed: { - metric: function () { - return !this.state.imperial; + display_units: { + cache: false, + get: function () { + return this.$root.display_units; + }, + set: function (value) { + this.$root.display_units = value; + } }, + metric: function () { + return this.display_units === "METRIC"; + }, mach_state: function () { var cycle = this.state.cycle; var state = this.state.xx; if (typeof cycle != 'undefined' && state != 'ESTOPPED' && - (cycle == 'jogging' || cycle == 'homing')) + (cycle == 'jogging' || cycle == 'homing')) { return cycle.toUpperCase(); + } + return state || '' }, - - pause_reason: function () { return this.state.pr }, - + pause_reason: function () { + return this.state.pr + }, is_running: function () { return this.mach_state == 'RUNNING' || this.mach_state == 'HOMING'; }, + is_stopping: function () { + return this.mach_state == 'STOPPING' + }, - is_stopping: function () { return this.mach_state == 'STOPPING' }, - is_holding: function () { return this.mach_state == 'HOLDING' }, - is_ready: function () { return this.mach_state == 'READY' }, - is_idle: function () { return this.state.cycle == 'idle' }, + is_holding: function () { + return this.mach_state == 'HOLDING' + }, + is_ready: function () { + return this.mach_state == 'READY' + }, + + is_idle: function () { + return this.state.cycle == 'idle' + }, is_paused: function () { return this.is_holding && @@ -173,9 +166,9 @@ module.exports = { this.pause_reason == 'Program pause') }, - - can_mdi: function () { return this.is_idle || this.state.cycle == 'mdi' }, - + can_mdi: function () { + return this.is_idle || this.state.cycle == 'mdi' + }, can_set_axis: function () { return this.is_idle @@ -183,47 +176,59 @@ module.exports = { return this.is_idle || this.is_paused }, - message: function () { - if (this.mach_state == 'ESTOPPED') return this.state.er; - if (this.mach_state == 'HOLDING') return this.state.pr; - if (this.state.messages.length) + if (this.mach_state == 'ESTOPPED') { + return this.state.er; + } + + if (this.mach_state == 'HOLDING') { + return this.state.pr; + } + + if (this.state.messages.length) { return this.state.messages.slice(-1)[0].text; + } + return ''; }, - highlight_state: function () { return this.mach_state == 'ESTOPPED' || this.mach_state == 'HOLDING'; }, - - plan_time: function () { return this.state.plan_time }, - + plan_time: function () { + return this.state.plan_time + }, plan_time_remaining: function () { - if (!(this.is_stopping || this.is_running || this.is_holding)) return 0; + if (!(this.is_stopping || this.is_running || this.is_holding)) { + return 0; + } + return this.toolpath.time - this.plan_time }, - eta: function () { - if (this.mach_state != 'RUNNING') return ''; + if (this.mach_state != 'RUNNING') { + return ''; + } + var remaining = this.plan_time_remaining; var d = new Date(); d.setSeconds(d.getSeconds() + remaining); return d.toLocaleString(); }, - progress: function () { - if (!this.toolpath.time || this.is_ready) return 0; + if (!this.toolpath.time || this.is_ready) { + return 0; + } + var p = this.plan_time / this.toolpath.time; return p < 1 ? p : 1; } }, - events: { jog: function (axis, power) { var data = { ts: new Date().getTime() }; @@ -232,244 +237,34 @@ module.exports = { }, back2zero: function (axis0, axis1) { - this.send("G0" + axis0 + "0" + axis1 + "0"); + this.send(`G0 ${axis0}0 ${axis1}0`); }, step: function (axis, value) { - this.send('M70\nG91\nG0' + axis + value + '\nM72'); + this.send(` + M70 + G91 + G0 ${axis}${value} + M72 + `); }, - - probing_failed: function () { - Vue.set(this.state, "probing_active", false); - Vue.set(this.state, "wait_for_probing_complete", false); - Vue.set(this.state, "show_probe_complete_modal", false); - Vue.set(this.state, "goto_xy_zero_after_probe", false); - - Vue.set(this.state, "show_probe_failed_modal", true); - }, - - probing_complete: function () { - Vue.set(this.state, "probing_active", false); - - if (this.config.settings['probing-prompts']) { - Vue.set(this.state, "show_probe_complete_modal", true); - } else { - this.$emit("finalize_probe"); - } - }, - - finalize_probe: function () { - Vue.set(this.state, "show_probe_complete_modal", false); - - if (this.state.goto_xy_zero_after_probe) { - this.goto_zero(1, 1, 0, 0); - } - - Vue.set(this.state, "goto_xy_zero_after_probe", false); - } }, - ready: function () { - this.load() + this.load(); + + SvelteComponents.registerControllerMethods({ + send: (...args) => this.send(...args), + goto_zero: (...args) => this.goto_zero(...args) + }); }, - methods: { - units_changed: function () { - if (this.mach_units == 'METRIC') { - document.getElementById("jog_button_fine").innerHTML = "0.1"; - document.getElementById("jog_button_small").innerHTML = "1.0"; - document.getElementById("jog_button_medium").innerHTML = "10"; - document.getElementById("jog_button_large").innerHTML = "100"; - } else { - document.getElementById("jog_button_fine").innerHTML = "0.005"; - document.getElementById("jog_button_small").innerHTML = "0.05"; - document.getElementById("jog_button_medium").innerHTML = "0.5"; - document.getElementById("jog_button_large").innerHTML = "5"; - } - - this.set_jog_incr('small'); - }, - - start_probe_test: function (on_finish) { - if (!this.config.settings['probing-prompts']) { - on_finish(); - return; - } - - this.show_probe_test_modal = true; - Vue.set(this.state, "saw_probe_connected", false); - Vue.set(this.state, "on_probe_finish", on_finish); - }, - - finish_probe_test: function () { - this.show_probe_test_modal = false; - Vue.set(this.state, "saw_probe_connected", false); - - const on_finish = this.state.on_probe_finish; - Vue.set(this.state, "on_probe_finish", undefined); - - on_finish(); - }, - - hide_probe_failed_modal: function () { - Vue.set(this.state, "show_probe_failed_modal", false); - }, - - prep_and_show_tool_diameter_modal() { - this.tool_diameter_for_prompt = (this.mach_units == 'METRIC') - ? this.tool_diameter - : this.tool_diameter / 25.4; - - this.tool_diameter_for_prompt = this.tool_diameter_for_prompt.toFixed(3).replace(/0+$/, ""); - - this.show_tool_diameter_modal = true; - }, - - set_tool_diameter() { - this.tool_diameter = parseFloat(this.tool_diameter_for_prompt); - - if (!isFinite(this.tool_diameter)) { - return; - } - - this.show_tool_diameter_modal = false; - - if (this.mach_units !== "METRIC") { - this.tool_diameter *= 25.4; - } - - this.probe_xyz(); - }, - - probe(zOnly = false) { - const xdim = this.config.probe["probe-xdim"]; - const ydim = this.config.probe["probe-ydim"]; - const zdim = this.config.probe["probe-zdim"]; - const slowSeek = this.config.probe["probe-slow-seek"]; - const fastSeek = this.config.probe["probe-fast-seek"]; - - const zlift = 1; - const xoffset = xdim + (this.tool_diameter / 2.0); - const yoffset = ydim + (this.tool_diameter / 2.0); - const zoffset = zdim; - - const metric = this.mach_units == "METRIC"; - const mm = n => (metric ? n : n / 25.4).toFixed(5); - const speed = s => `F${mm(s)}`; - - // After probing Z, we want to drop the bit down: - // Ideally, 12.7mm/0.5in - // And we don't want to be more than 75% down on the probe block - // Also, add zlift to compensate for the fact that we lift after probing Z - const plunge = Math.min(12.7, zoffset * 0.75) + zlift; - - Vue.set(this.state, "probing_active", true); - Vue.set(this.state, "goto_xy_zero_after_probe", !zOnly); - - if (zOnly) { - this.send(` - ${metric ? "G21" : "G20"} - G92 Z0 - - G38.2 Z ${mm(-25.4)} ${speed(fastSeek)} - G91 G1 Z ${mm(1)} - G38.2 Z ${mm(-2)} ${speed(slowSeek)} - G92 Z ${mm(zoffset)} - - G91 G0 Z ${mm(3)} - - M2 - `); - } else { - this.send(` - ${metric ? "G21" : "G20"} - G92 X0 Y0 Z0 - - G38.2 Z ${mm(-25.4)} ${speed(fastSeek)} - G91 G1 Z ${mm(1)} - G38.2 Z ${mm(-2)} ${speed(slowSeek)} - G92 Z ${mm(zoffset)} - - G91 G0 Z ${mm(zlift)} - G91 G0 X ${mm(20)} - G91 G0 Z ${mm(-plunge)} - G38.2 X ${mm(-20)} ${speed(fastSeek)} - G91 G1 X ${mm(1)} - G38.2 X ${mm(-2)} ${speed(slowSeek)} - G92 X ${mm(xoffset)} - - G91 G0 X ${mm(1)} - G91 G0 Y ${mm(20)} - G91 G0 X ${mm(-20)} - G38.2 Y ${mm(-20)} ${speed(fastSeek)} - G91 G1 Y ${mm(1)} - G38.2 Y ${mm(-2)} ${speed(slowSeek)} - G92 Y ${mm(yoffset)} - - G91 G0 Y ${mm(3)} - G91 G0 Z ${mm(25.4)} - - M2 - `); - } - - // Wait 1 second to let the probing sequence begin, - // then wait for probing to be complete - setTimeout(() => Vue.set(this.state, "wait_for_probing_complete", true), 1000); - }, - - probe_xyz() { - this.probe(false); - }, - - probe_z() { - this.probe(true); - }, - - set_jog_incr: function (newValue) { - document.getElementById("jog_button_fine").style.fontWeight = 'normal'; - document.getElementById("jog_button_small").style.fontWeight = 'normal'; - document.getElementById("jog_button_medium").style.fontWeight = 'normal'; - document.getElementById("jog_button_large").style.fontWeight = 'normal'; - - if (newValue == 'fine') { - document.getElementById("jog_button_fine").style.fontWeight = 'bold'; - if (this.mach_units == 'METRIC') - this.jog_incr = 0.1; - else - this.jog_incr = 0.005; - } else if (newValue == 'small') { - document.getElementById("jog_button_small").style.fontWeight = 'bold'; - if (this.mach_units == 'METRIC') - this.jog_incr = 1.0; - else - this.jog_incr = 0.05; - } else if (newValue == 'medium') { - document.getElementById("jog_button_medium").style.fontWeight = 'bold'; - if (this.mach_units == 'METRIC') - this.jog_incr = 10; - else - this.jog_incr = 0.5; - } else if (newValue == 'large') { - document.getElementById("jog_button_large").style.fontWeight = 'bold'; - - this.jog_incr = (this.mach_units == 'METRIC') - ? 100 - : 5; - } - }, - goto_zero(zero_x, zero_y, zero_z, zero_a) { - var xcmd = ""; - var ycmd = ""; - var zcmd = ""; - var acmd = ""; - if (zero_x) xcmd = "X0"; - if (zero_y) ycmd = "Y0"; - if (zero_z) zcmd = "Z0"; - if (zero_a) acmd = "A0"; + const xcmd = zero_x ? "X0" : ""; + const ycmd = zero_y ? "Y0" : ""; + const zcmd = zero_z ? "Z0" : ""; + const acmd = zero_a ? "A0" : ""; this.ask_zero_xy_msg = false; this.ask_zero_z_msg = false; @@ -477,13 +272,25 @@ module.exports = { this.send('G90\nG0' + xcmd + ycmd + zcmd + acmd + '\n'); }, - jog_fn: function (x_jog, y_jog, z_jog, a_jog) { - var xcmd = "X" + x_jog * this.jog_incr; - var ycmd = "Y" + y_jog * this.jog_incr; - var zcmd = "Z" + z_jog * this.jog_incr; - var acmd = "A" + a_jog * this.jog_incr; + getJogIncrFontWeight(value) { + const weight = this.jog_incr === value ? 'bold' : 'normal'; - this.send('G91\nG0' + xcmd + ycmd + zcmd + acmd + '\n'); + return `font-weight:${weight}`; + }, + + jog_fn: function (x_jog, y_jog, z_jog, a_jog) { + const amount = this.jog_incr_amounts[this.display_units][this.jog_incr]; + + var xcmd = "X" + x_jog * amount; + var ycmd = "Y" + y_jog * amount; + var zcmd = "Z" + z_jog * amount; + var acmd = "A" + a_jog * amount; + + this.send(` + G91 + ${this.metric ? "G21" : "G20"} + G0 ${xcmd}${ycmd}${zcmd}${acmd} + `); }, send: function (msg) { @@ -493,7 +300,10 @@ module.exports = { load: function () { var file_time = this.state.selected_time; var file = this.state.selected; - if (this.last_file == file && this.last_file_time == file_time) return; + if (this.last_file == file && this.last_file_time == file_time) { + return; + } + this.last_file = file; this.last_file_time = file_time; @@ -503,12 +313,12 @@ module.exports = { this.load_toolpath(file, file_time); }, - load_toolpath: async function (file, file_time) { this.toolpath = {}; - if (!file) return; - if (this.last_file_time != file_time) return; + if (!file || this.last_file_time != file_time) { + return; + } this.showGcodeMessage = true; @@ -534,30 +344,30 @@ module.exports = { } }, - submit_mdi: function () { this.send(this.mdi); - if (!this.history.length || this.history[0] != this.mdi) + + if (!this.history.length || this.history[0] != this.mdi) { this.history.unshift(this.mdi); + } + this.mdi = ''; }, - mdi_start_pause: function () { - if (this.state.xx == 'RUNNING') this.pause(); - - else if (this.state.xx == 'STOPPING' || this.state.xx == 'HOLDING') + if (this.state.xx == 'RUNNING') { + this.pause(); + } else if (this.state.xx == 'STOPPING' || this.state.xx == 'HOLDING') { this.unpause(); - - else this.submit_mdi(); + } else { + this.submit_mdi(); + } }, - load_history: function (index) { this.mdi = this.history[index]; }, - open: function (e) { // If we don't reset the form the browser may cache file if name is same // even if contents have changed @@ -565,7 +375,6 @@ module.exports = { $('.gcode-file-input input').click(); }, - upload: async function (e) { const files = e.target.files || e.dataTransfer.files; if (!files.length) { @@ -601,7 +410,6 @@ module.exports = { } }, - delete_current: function () { if (this.state.selected) { api.delete('file/' + this.state.selected); @@ -610,41 +418,33 @@ module.exports = { this.deleteGCode = false; }, - delete_all: function () { api.delete('file'); this.deleteGCode = false; }, - home: function (axis) { this.ask_home = false; if (typeof axis == 'undefined') { api.put('home'); + } else if (this[axis].homingMode != 'manual') { + api.put('home/' + axis); } else { - if (this[axis].homingMode != 'manual') { - api.put('home/' + axis); - } - else { - this.manual_home[axis] = true; - } + this.manual_home[axis] = true; } }, - set_home: function (axis, position) { this.manual_home[axis] = false; api.put('home/' + axis + '/set', { position: parseFloat(position) }); }, - unhome: function (axis) { this.position_msg[axis] = false; api.put('home/' + axis + '/clear'); }, - show_set_position: function (axis) { this.axis_position = 0; this.position_msg[axis] = true; @@ -654,61 +454,84 @@ module.exports = { this.toolpath_msg[axis] = true; }, - set_position: function (axis, position) { this.position_msg[axis] = false; api.put('position/' + axis, { 'position': parseFloat(position) }); }, - zero_all: function () { - for (var axis of 'xyzabc') - if (this[axis].enabled) this.zero(axis); + for (var axis of 'xyzabc') { + if (this[axis].enabled) { + this.zero(axis); + } + } }, - zero: function (axis) { - if (typeof axis == 'undefined') this.zero_all(); - else this.set_position(axis, 0); + if (typeof axis == 'undefined') { + this.zero_all(); + } else { + this.set_position(axis, 0); + } }, - start_pause: function () { - if (this.state.xx == 'RUNNING') this.pause(); - - else if (this.state.xx == 'STOPPING' || this.state.xx == 'HOLDING') + if (this.state.xx == 'RUNNING') { + this.pause(); + } else if (this.state.xx == 'STOPPING' || this.state.xx == 'HOLDING') { this.unpause(); - - else this.start(); + } else { + this.start(); + } }, + start: function () { + api.put('start') + }, - start: function () { api.put('start') }, - pause: function () { api.put('pause') }, - unpause: function () { api.put('unpause') }, - optional_pause: function () { api.put('pause/optional') }, - stop: function () { api.put('stop') }, - step: function () { api.put('step') }, + pause: function () { + api.put('pause') + }, + unpause: function () { + api.put('unpause') + }, - override_feed: function () { api.put('override/feed/' + this.feed_override) }, + optional_pause: function () { + api.put('pause/optional') + }, + stop: function () { + api.put('stop') + }, + + step: function () { + api.put('step') + }, + + override_feed: function () { + api.put('override/feed/' + this.feed_override) + }, override_speed: function () { api.put('override/speed/' + this.speed_override) }, - current: function (axis, value) { var x = value / 32.0; - if (this.state[axis + 'pl'] == x) return; + if (this.state[axis + 'pl'] == x) { + return; + } var data = {}; data[axis + 'pl'] = x; this.send(JSON.stringify(data)); + }, + + showProbeDialog: function(probeType) { + SvelteComponents.showDialog("Probe", { probeType }); } }, - mixins: [require('./axis-vars')] } diff --git a/src/js/main.js b/src/js/main.js index d369409..9d93e45 100644 --- a/src/js/main.js +++ b/src/js/main.js @@ -1,33 +1,5 @@ -/******************************************************************************\ - - 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" - -\******************************************************************************/ - 'use strict'; - function cookie_get(name) { var decodedCookie = decodeURIComponent(document.cookie); var ca = decodedCookie.split(';'); @@ -35,12 +7,16 @@ function cookie_get(name) { for (var i = 0; i < ca.length; i++) { var c = ca[i]; - while (c.charAt(0) == ' ') c = c.substring(1); - if (!c.indexOf(name)) return c.substring(name.length, c.length); + while (c.charAt(0) == ' ') { + c = c.substring(1); + } + + if (!c.indexOf(name)) { + return c.substring(name.length, c.length); + } } } - function cookie_set(name, value, days) { var d = new Date(); d.setTime(d.getTime() + days * 24 * 60 * 60 * 1000); @@ -48,29 +24,26 @@ function cookie_set(name, value, days) { document.cookie = name + '=' + value + ';' + expires + ';path=/'; } - -var uuid_chars = - 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_+'; - +var uuid_chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_+'; function uuid(length) { - if (typeof length == 'undefined') length = 52; + if (typeof length == 'undefined') { + length = 52; + } var s = ''; - for (var i = 0; i < length; i++) + for (var i = 0; i < length; i++) { s += uuid_chars[Math.floor(Math.random() * uuid_chars.length)]; + } return s } -$(function() { - if (typeof cookie_get('client-id') == 'undefined') +$(function () { + if (typeof cookie_get('client-id') == 'undefined') { cookie_set('client-id', uuid(), 10000); - - // Vue debugging - Vue.config.debug = true; - //Vue.util.warn = function (msg) {console.debug('[Vue warn]: ' + msg)} + } // Register global components Vue.component('templated-input', require('./templated-input')); @@ -81,38 +54,64 @@ $(function() { Vue.component('unit-value', require('./unit-value')); Vue.filter('number', function (value) { - if (isNaN(value)) return 'NaN'; + if (isNaN(value)) { + return 'NaN'; + } + return value.toLocaleString(); }); Vue.filter('percent', function (value, precision) { - if (typeof value == 'undefined') return ''; - if (typeof precision == 'undefined') precision = 2; + if (typeof value == 'undefined') { + return ''; + } + + if (typeof precision == 'undefined') { + precision = 2; + } + return (value * 100.0).toFixed(precision) + '%'; }); Vue.filter('non_zero_percent', function (value, precision) { - if (!value) return ''; - if (typeof precision == 'undefined') precision = 2; + if (!value) { + return ''; + } + + if (typeof precision == 'undefined') { + precision = 2; + } + return (value * 100.0).toFixed(precision) + '%'; }); Vue.filter('fixed', function (value, precision) { - if (typeof value == 'undefined') return '0'; + if (typeof value == 'undefined') { + return '0'; + } + return parseFloat(value).toFixed(precision) }); Vue.filter('upper', function (value) { - if (typeof value == 'undefined') return ''; + if (typeof value == 'undefined') { + return ''; + } + return value.toUpperCase() }); Vue.filter('time', function (value, precision) { - if (isNaN(value)) return ''; - if (isNaN(precision)) precision = 0; + if (isNaN(value)) { + return ''; + } + + if (isNaN(precision)) { + precision = 0; + } var MIN = 60; - var HR = MIN * 60; + var HR = MIN * 60; var DAY = HR * 24; var parts = []; @@ -129,14 +128,17 @@ $(function() { if (MIN <= value) { parts.push(Math.floor(value / MIN)); value %= MIN; - - } else parts.push(0); + } else { + parts.push(0); + } parts.push(value); 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]; + if (i && parts[i] < 10) { + parts[i] = '0' + parts[i]; + } } return parts.join(':'); diff --git a/src/js/motor-view.js b/src/js/motor-view.js index 49bbf08..34d5ff8 100644 --- a/src/js/motor-view.js +++ b/src/js/motor-view.js @@ -1,124 +1,105 @@ -/******************************************************************************\ - - 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" - -\******************************************************************************/ - 'use strict' - module.exports = { template: '#motor-view-template', props: ['index', 'config', 'template', 'state'], - computed: { - metric: function () {return this.$root.metric()}, - + metric: function () { + return this.$root.display_units === "METRIC"; + }, is_slave: function () { - for (var i = 0; i < this.index; i++) - if (this.motor.axis == this.config.motors[i].axis) + for (var i = 0; i < this.index; i++) { + if (this.motor.axis == this.config.motors[i].axis) { return true; + } + } return false; }, - - motor: function () {return this.config.motors[this.index]}, - + motor: function () { + return this.config.motors[this.index] + }, invalidMaxVelocity: function () { return this.maxMaxVelocity < this.motor['max-velocity']; }, - maxMaxVelocity: function () { return 1 * (15 * this.umPerStep / this.motor['microsteps']).toFixed(3); }, - ustepPerSec: function () { return this.rpm * this.stepsPerRev * this.motor['microsteps'] / 60; }, - rpm: function () { return 1000 * this.motor['max-velocity'] / this.motor['travel-per-rev']; }, + gForce: function () { + return this.motor['max-accel'] * 0.0283254504 + }, - gForce: function () {return this.motor['max-accel'] * 0.0283254504}, - gForcePerMin: function () {return this.motor['max-jerk'] * 0.0283254504}, - stepsPerRev: function () {return 360 / this.motor['step-angle']}, + gForcePerMin: function () { + return this.motor['max-jerk'] * 0.0283254504 + }, + stepsPerRev: function () { + return 360 / this.motor['step-angle'] + }, umPerStep: function () { return this.motor['travel-per-rev'] * this.motor['step-angle'] / 0.36 }, + milPerStep: function () { + return this.umPerStep / 25.4 + }, - milPerStep: function () {return this.umPerStep / 25.4}, + invalidStallVelocity: function () { + if (!this.motor['homing-mode'].startsWith('stall-')) { + return false; + } - invalidStallVelocity: function() { - if(!this.motor['homing-mode'].startsWith('stall-')) return false; return this.maxStallVelocity < this.motor['search-velocity']; }, - stallRPM: function() { + stallRPM: function () { var v = this.motor['search-velocity']; return 1000 * v / this.motor['travel-per-rev']; }, - maxStallVelocity: function() { - var maxRate = 900000/this.motor['stall-sample-time']; + maxStallVelocity: function () { + var maxRate = 900000 / this.motor['stall-sample-time']; var ustep = this.motor['stall-microstep']; var angle = this.motor['step-angle']; var travel = this.motor['travel-per-rev']; - var maxStall = maxRate * 60/ 360 /1000 * angle/ ustep * travel; + var maxStall = maxRate * 60 / 360 / 1000 * angle / ustep * travel; return 1 * maxStall.toFixed(3); }, - stallUStepPerSec: function() { + stallUStepPerSec: function () { var ustep = this.motor['stall-microstep']; return this.stallRPM * this.stepsPerRev * ustep / 60; } - }, - events: { - 'input-changed': function() { + 'input-changed': function () { Vue.nextTick(function () { // Limit max-velocity - if (this.invalidMaxVelocity) + if (this.invalidMaxVelocity) { this.$set('motor["max-velocity"]', this.maxMaxVelocity); + } //Limit stall-velocity - if(this.invalidStallVelocity) + if (this.invalidStallVelocity) { this.$set('motor["search-velocity"]', this.maxStallVelocity); + } this.$dispatch('config-changed'); }.bind(this)) @@ -128,8 +109,11 @@ module.exports = { }, methods: { - show: function(name, templ) { - if(templ.hmodes == undefined) return true; + show: function (name, templ) { + if (templ.hmodes == undefined) { + return true; + } + return templ.hmodes.indexOf(this.motor['homing-mode']) != -1; } } diff --git a/src/js/settings-view.js b/src/js/settings-view.js index 599aea8..2df783c 100644 --- a/src/js/settings-view.js +++ b/src/js/settings-view.js @@ -1,40 +1,23 @@ -/******************************************************************************\ - - 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" - -\******************************************************************************/ - 'use strict' - module.exports = { template: '#settings-view-template', props: ['config', 'template'], + computed: { + display_units: { + cache: false, + get: function () { + return this.$root.display_units; + }, + set: function (value) { + this.$root.display_units = value; + } + }, + }, events: { - 'input-changed': function() { + 'input-changed': function () { this.$dispatch('config-changed'); return false; } diff --git a/src/js/templated-input.js b/src/js/templated-input.js index 32d80eb..0d5c2db 100644 --- a/src/js/templated-input.js +++ b/src/js/templated-input.js @@ -1,49 +1,24 @@ -/******************************************************************************\ - - 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" - -\******************************************************************************/ - 'use strict' - module.exports = { replace: true, template: '#templated-input-template', props: ['name', 'model', 'template'], - - data: function () {return {view: ''}}, - + data: function () { + return { view: '' } + }, computed: { - metric: function () {return this.$root.metric()}, - + metric: function () { + return this.$root.display_units === "METRIC"; + }, _view: function () { if (this.template.scale) { - if (this.metric) return 1 * this.model.toFixed(3); + if (this.metric) { + return 1 * this.model.toFixed(3); + } return 1 * (this.model / this.template.scale).toFixed(4); } @@ -51,39 +26,44 @@ module.exports = { return this.model; }, - units: function () { - return (this.metric || !this.template.iunit) ? - this.template.unit : this.template.iunit; + return (this.metric || !this.template.iunit) + ? this.template.unit + : this.template.iunit; }, - title: function () { - var s = 'Default ' + this.template.default + ' ' + - (this.template.unit || ''); - if (typeof this.template.help != 'undefined') + var s = `Default :${this.template.default} ${(this.template.unit || '')}`; + + if (typeof this.template.help != 'undefined') { s = this.template.help + '\n' + s; + } + return s; } }, - watch: { - _view: function () {this.view = this._view}, - + _view: function () { + this.view = this._view + }, view: function () { - if (this.template.scale && !this.metric) + if (this.template.scale && !this.metric) { this.model = this.view * this.template.scale; - else this.model = this.view; + } else { + this.model = this.view; + } } }, - - ready: function () {this.view = this._view}, - + ready: function () { + this.view = this._view + }, methods: { - change: function () {this.$dispatch('input-changed')} + change: function () { + this.$dispatch('input-changed') + } } } diff --git a/src/js/unit-value.js b/src/js/unit-value.js index d4d6ee0..de4f4be 100644 --- a/src/js/unit-value.js +++ b/src/js/unit-value.js @@ -1,58 +1,47 @@ -/******************************************************************************\ - - 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" - -\******************************************************************************/ - 'use strict' - module.exports = { replace: true, template: '{{text}}{{metric ? unit : iunit}}', props: ['value', 'precision', 'unit', 'iunit', 'scale'], - computed: { - metric: function () {return !this.$root.state.imperial}, - + metric: { + cache: false, + get: function () { + return this.$root.display_units === "METRIC"; + } + }, text: function () { var value = this.value; - if (typeof value == 'undefined') return ''; + if (typeof value == 'undefined') { + return ''; + } - if (!this.metric) value /= this.scale; + if (!this.metric) { + value /= this.scale; + } return (1 * value.toFixed(this.precision)).toLocaleString(); } }, - ready: function () { - if (typeof this.precision == 'undefined') this.precision = 0; - if (typeof this.unit == 'undefined') this.unit = 'mm'; - if (typeof this.iunit == 'undefined') this.iunit = 'in'; - if (typeof this.scale == 'undefined') this.scale = 25.4; + if (typeof this.precision == 'undefined') { + this.precision = 0; + } + + if (typeof this.unit == 'undefined') { + this.unit = 'mm'; + } + + if (typeof this.iunit == 'undefined') { + this.iunit = 'in'; + } + + if (typeof this.scale == 'undefined') { + this.scale = 25.4; + } } } diff --git a/src/pug/templates/control-view.pug b/src/pug/templates/control-view.pug index 83c8dc8..4184025 100644 --- a/src/pug/templates/control-view.pug +++ b/src/pug/templates/control-view.pug @@ -1,30 +1,3 @@ -//-///////////////////////////////////////////////////////////////////////////// -//- // -//- 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" // -//- // -//-///////////////////////////////////////////////////////////////////////////// - script#control-view-template(type="text/x-template") #control message(:show.sync="showGcodeMessage") @@ -63,70 +36,6 @@ script#control-view-template(type="text/x-template") button.pure-button(@click='ask_zero_z_msg = false') | Cancel - message(:show.sync=`show_probe_test_modal`) - - h3(slot="header") Test probe connection - - div(slot="body") - .pure-form - p Attach the probe magnet to the collet. - p Touch the probe block to the bit. - - div(slot="footer") - button.pure-button(@click=`show_probe_test_modal = false`) - | Cancel - - button.pure-button.button-success( - :disabled=`!state.saw_probe_connected` - @click=`finish_probe_test()`) Continue - - message(:show.sync=`show_tool_diameter_modal`) - h3(slot="header") Enter probe tool information - - div(slot="body") - .pure-form - .pure-control-group - label="{{metric ? 'Diameter (mm)' : 'Diameter (inches)'}}" - input(v-model="tool_diameter_for_prompt", size="8") - p - - div(slot="footer") - button.pure-button(@click=`show_tool_diameter_modal = false`) - | Cancel - - button.pure-button.button-success( - @click=`set_tool_diameter`) - | Set - - message(:show.sync=`state.show_probe_complete_modal`) - h3(slot="header") Probing complete! - - div(slot="body") - .pure-form - p Don't forget to put away the probe! - div(v-if="state.goto_xy_zero_after_probe") - p - | The machine will now move - br - | to the X-Y zero point. - p Watch your hands! - - div(slot="footer") - button.pure-button.button-success(@click=`$emit("finalize_probe")`) - | Done - - message(:show.sync=`state.show_probe_failed_modal`) - h3(slot="header") Probing failed! - - div(slot="body") - .pure-form - p Could not find the probe block during probing! - p Make sure the tip of the bit is about 1/4" (~6mm) above the probe block, and try again. - - div(slot="footer") - button.pure-button.button-success(@click=`hide_probe_failed_modal()`) - | OK - table(style="table-layout: fixed; width: 100%;") tr(style="height: fit-content;") td(style="white-space: nowrap; width: 410px;", rowspan="2") @@ -138,55 +47,60 @@ script#control-view-template(type="text/x-template") col(style="width:100px") tr td(style="height:100px",align="center") - button(style="height:100px;width:100px",@click="jog_fn(-1,1,0,0)") + button(@click="jog_fn(-1,1,0,0)") .fa.fa-arrow-right(style="transform: rotate(-135deg);") td(style="height:100px",align="center") - button(style="height:100px;width:100px",@click="jog_fn(0,1,0,0)") Y+ + button(@click="jog_fn(0,1,0,0)") Y+ td(style="height:100px",align="center") - button(style="height:100px;width:100px",@click="jog_fn(1,1,0,0)") + button(@click="jog_fn(1,1,0,0)") .fa.fa-arrow-right(style="transform: rotate(-45deg);") td(style="height:100px",align="center") - button(style="height:100px;width:100px",,@click="jog_fn(0,0,1,0)") Z+ + button(,@click="jog_fn(0,0,1,0)") Z+ tr td(style="height:100px",align="center") - button(style="height:100px;width:100px",@click="jog_fn(-1,0,0,0)") X- + button(@click="jog_fn(-1,0,0,0)") X- td(style="height:100px",align="center") - button(style="height:100px;width:100px",@click="ask_zero_xy_msg = true") + button(@click="ask_zero_xy_msg = true") .fa.fa-bullseye(style="font-size: 172%") td(style="height:100px",align="center") - button(style="height:100px;width:100px",@click="jog_fn(1,0,0,0)") X+ + button(@click="jog_fn(1,0,0,0)") X+ td(style="height:100px",align="center") - button(style="height:100px;width:100px",@click='ask_zero_z_msg = true') Z0 + button(@click='ask_zero_z_msg = true') Z0 tr td(style="height:100px",align="center") - button(style="height:100px;width:100px",@click="jog_fn(-1,-1,0,0)") + button(@click="jog_fn(-1,-1,0,0)") .fa.fa-arrow-right(style="transform: rotate(135deg);") td(style="height:100px",align="center") - button(style="height:100px;width:100px",@click="jog_fn(0,-1,0,0)") Y- + button(@click="jog_fn(0,-1,0,0)") Y- td(style="height:100px",align="center") - button(style="height:100px;width:100px",@click="jog_fn(1,-1,0,0)") + button(@click="jog_fn(1,-1,0,0)") .fa.fa-arrow-right(style="transform: rotate(45deg);") td(style="height:100px",align="center") - button(style="height:100px;width:100px",@click="jog_fn(0,0,-1,0)") Z- + button(@click="jog_fn(0,0,-1,0)") Z- tr td(style="height:100px",align="center") - button#jog_button_fine(style="height:100px;width:100px", @click=`set_jog_incr('fine')`) 0.1 + button(:style="getJogIncrFontWeight('fine')", @click="jog_incr = 'fine'") + span {{jog_incr_amounts[display_units].fine}}#[span.jog-units {{metric ? 'mm' : 'in'}}] td(style="height:100px",align="center") - button#jog_button_small(style="height:100px;width:100px", @click=`set_jog_incr('small')`) 1.0 + button(:style="getJogIncrFontWeight('small')", @click="jog_incr = 'small'") + span {{jog_incr_amounts[display_units].small}}#[span.jog-units {{metric ? 'mm' : 'in'}}] td(style="height:100px",align="center") - button#jog_button_medium(style="height:100px;width:100px", @click=`set_jog_incr('medium')`) 10 + button(:style="getJogIncrFontWeight('medium')", @click="jog_incr = 'medium'") + span {{jog_incr_amounts[display_units].medium}}#[span.jog-units {{metric ? 'mm' : 'in'}}] td(style="height:100px",align="center") - button#jog_button_large(style="height:100px;width:100px", @click=`set_jog_incr('large')`) 100 + button(:style="getJogIncrFontWeight('large')", @click="jog_incr = 'large'") + span {{jog_incr_amounts[display_units].large}}#[span.jog-units {{metric ? 'mm' : 'in'}}] tr td(style="height:100px", align="center", colspan="2") button(:class="state['pw'] ? '' : 'load-on'", style="height:100px;width:200px", - @click=`start_probe_test(prep_and_show_tool_diameter_modal)`) + @click="showProbeDialog('xyz')") | Probe XYZ + td(style="height:100px", align="center", colspan="2") button(:class="state['pw'] ? '' : 'load-on'", style="height:100px;width:200px", - @click=`start_probe_test(probe_z)`) + @click="showProbeDialog('z')") | Probe Z td(style="vertical-align: top;") @@ -198,8 +112,6 @@ script#control-view-template(type="text/x-template") th.offset Offset th.state State th.tstate Toolpath - //th.tstate Min - //th.tstate Max th.actions button.pure-button(disabled, style="height:60px;width:60px;display:none;") @@ -224,8 +136,6 @@ script#control-view-template(type="text/x-template") td.tstate(:class=`${axis}.tklass`, :title=`${axis}.toolmsg`, @click=`show_toolpath_msg('${axis}')`) .fa(:class=`'fa-' + ${axis}.ticon`) | {{#{axis}.tstate}} - //td.tstate: unit-value(:value=`${axis}.pathMin`, precision=4) - //td.tstate: unit-value(:value=`${axis}.pathMax`, precision=4) message(:show.sync=`toolpath_msg['${axis}']`) h3(slot="header") Tool path info {{'#{axis}' | upper}} axis @@ -310,10 +220,10 @@ script#control-view-template(type="text/x-template") td.message(:class="{attention: highlight_state}") | {{message.replace(/^#/, '')}} - tr(title="Active machine units") + tr th Units - td.mach_units - select(v-model="mach_units", :disabled="!is_idle") + td.units + select(v-model="display_units") option(value="METRIC") METRIC option(value="IMPERIAL") IMPERIAL @@ -471,6 +381,9 @@ script#control-view-template(type="text/x-template") input(v-model="mdi", :disabled="!can_mdi", @keyup.enter="submit_mdi") + div + em The machine is currently operating in #[strong {{mach_units}}] units. Use G20/G21 to switch units. + .history(:class="{placeholder: !history}") span(v-if="!history.length") MDI history displays here. ul diff --git a/src/pug/templates/settings-view.pug b/src/pug/templates/settings-view.pug index 058e043..7e0b0fa 100644 --- a/src/pug/templates/settings-view.pug +++ b/src/pug/templates/settings-view.pug @@ -1,25 +1,3 @@ -//- 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#settings-view-template(type="text/x-template") #settings h1 Settings @@ -27,13 +5,12 @@ script#settings-view-template(type="text/x-template") .pure-form.pure-form-aligned fieldset h2 Units - templated-input(name="units", :model.sync="config.settings.units", - :template="template.settings.units") - - p - | 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. + .pure-control-group + label(for="units") units + select(name="units", v-model="display_units") + option(value="METRIC") METRIC + option(value="IMPERIAL") IMPERIAL + fieldset h2 Probing safety prompts diff --git a/src/pug/templates/templated-input.pug b/src/pug/templates/templated-input.pug index c4c48ce..7e69979 100644 --- a/src/pug/templates/templated-input.pug +++ b/src/pug/templates/templated-input.pug @@ -1,30 +1,3 @@ -//-///////////////////////////////////////////////////////////////////////////// -//- // -//- 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" // -//- // -//-///////////////////////////////////////////////////////////////////////////// - script#templated-input-template(type="text/x-template") .pure-control-group(class="tmpl-input-{{name}}", :title="title") label(:for="name") {{name}} diff --git a/src/py/bbctrl/Ctrl.py b/src/py/bbctrl/Ctrl.py index 9a46323..a751aff 100644 --- a/src/py/bbctrl/Ctrl.py +++ b/src/py/bbctrl/Ctrl.py @@ -1,35 +1,6 @@ -################################################################################ -# # -# 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 os -import time import bbctrl - class Ctrl(object): def __init__(self, args, ioloop, id): self.args = args diff --git a/src/py/bbctrl/State.py b/src/py/bbctrl/State.py index e4c4212..d7c1e67 100644 --- a/src/py/bbctrl/State.py +++ b/src/py/bbctrl/State.py @@ -82,9 +82,6 @@ class State(object): self.set_callback(str(i) + 'latch_velocity', lambda name, i = i: self.motor_latch_velocity(i)) - #self.set_callback('metric', lambda name: 1 if self.is_metric() else 0) - #self.set_callback('imperial', lambda name: 0 if self.is_metric() else 1) - self.reset() self.load_files() @@ -99,11 +96,6 @@ class State(object): self.log.info('INIT Metric %d' % metric) if not 'metric' in self.vars: self.set('metric', metric) if not 'imperial' in self.vars: self.set('imperial', not metric) - - # Bit diameter for probing - diameter = self.ctrl.config.get('probe-diameter', 6.35) - self.log.info('INIT Diameter %f' % diameter) - self.set('bitDiameter',diameter) def reset(self): diff --git a/src/stylus/style.styl b/src/stylus/style.styl index 09a21e0..9e07231 100644 --- a/src/stylus/style.styl +++ b/src/stylus/style.styl @@ -282,6 +282,12 @@ span.unit // The jogging buttons, etc. .control-buttons button font-size 150% + width 100px + height 100px + + .jog-units + font-size initial + margin-left 5px &:first-child margin 0.5em 0 @@ -436,7 +442,7 @@ span.unit min-width 8em width 100% - .mach_units + .units padding 0 select diff --git a/src/svelte-components/src/components/AdminNetworkView.svelte b/src/svelte-components/src/components/AdminNetworkView.svelte index 0b7dad3..8efe39e 100644 --- a/src/svelte-components/src/components/AdminNetworkView.svelte +++ b/src/svelte-components/src/components/AdminNetworkView.svelte @@ -1,11 +1,10 @@ - - diff --git a/src/svelte-components/src/dialogs/ChangeHostnameDialog.svelte b/src/svelte-components/src/dialogs/ChangeHostnameDialog.svelte index 18627f4..de8930b 100644 --- a/src/svelte-components/src/dialogs/ChangeHostnameDialog.svelte +++ b/src/svelte-components/src/dialogs/ChangeHostnameDialog.svelte @@ -2,8 +2,8 @@ import Dialog, { Title, Content, Actions } from "@smui/dialog"; import Button, { Label } from "@smui/button"; import TextField from "@smui/textfield"; - import MessageDialog from "./MessageDialog.svelte"; - import * as api from "../lib/api"; + import MessageDialog from "$dialogs/MessageDialog.svelte"; + import * as api from "$lib/api"; // https://man7.org/linux/man-pages/man7/hostname.7.html // diff --git a/src/svelte-components/src/dialogs/DialogHost.svelte b/src/svelte-components/src/dialogs/DialogHost.svelte new file mode 100644 index 0000000..c6319dd --- /dev/null +++ b/src/svelte-components/src/dialogs/DialogHost.svelte @@ -0,0 +1,38 @@ + + + + diff --git a/src/svelte-components/src/dialogs/DialogProps.ts b/src/svelte-components/src/dialogs/DialogProps.ts new file mode 100644 index 0000000..338c722 --- /dev/null +++ b/src/svelte-components/src/dialogs/DialogProps.ts @@ -0,0 +1,13 @@ +import { writable } from "svelte/store"; + +export const HomeMachineProps = writable(); +export type HomeMachinePropsType = { + open: boolean, + home: () => void +} + +export const ProbeProps = writable(); +export type ProbePropsType = { + open: boolean, + probeType: "xyz" | "z" +}; diff --git a/src/svelte-components/src/dialogs/ProbeDialog.svelte b/src/svelte-components/src/dialogs/ProbeDialog.svelte new file mode 100644 index 0000000..36775fa --- /dev/null +++ b/src/svelte-components/src/dialogs/ProbeDialog.svelte @@ -0,0 +1,293 @@ + + + + + + Probe {probeType} + + + {#if stage === "TestingProbe" || stage === "TestingProbeComplete"} +

Attach the probe magnet to the collet.

+

Touch the probe block to the bit.

+ + {#if stage === "TestingProbe"} +

Waiting for probe contact...

+ {:else} +

Probe contact detected!

+ {/if} + {:else if stage === "GetToolDiameter"} + + + {:else if stage === "Probing"} +

Probing in progress...

+ {:else if stage === "ProbingFailed"} +

Could not find the probe block during probing!

+

+ Make sure the tip of the bit is about 1/4" (6mm) above the probe block, + and try again. +

+ {:else if stage === "ProbingComplete"} +

Don't forget to put away the probe!

+

The machine will now move to the XY origin.

+

Watch your hands!

+ {/if} +
+ + + + + +
diff --git a/src/svelte-components/src/dialogs/WifiConnectionDialog.svelte b/src/svelte-components/src/dialogs/WifiConnectionDialog.svelte index d6f333c..b213330 100644 --- a/src/svelte-components/src/dialogs/WifiConnectionDialog.svelte +++ b/src/svelte-components/src/dialogs/WifiConnectionDialog.svelte @@ -4,28 +4,22 @@ import TextField from "@smui/textfield"; import Icon from "@smui/textfield/icon"; import HelperText from "@smui/textfield/helper-text"; - import MessageDialog from "./MessageDialog.svelte"; - import type { WifiNetwork } from "../lib/NetworkInfo"; - import * as api from "../lib/api"; + import MessageDialog from "$dialogs/MessageDialog.svelte"; + import type { WifiNetwork } from "$lib/NetworkInfo"; + import * as api from "$lib/api"; export let open = false; export let network: WifiNetwork; let rebooting = false; - let needPassword = false; let password = ""; let showPassword = false; - let connectOrDisconnect: string; - let connectToOrDisconnectFrom: string; $: needPassword = !network?.active && network?.Encryption !== "Open"; - - $: { - connectOrDisconnect = network?.active ? "Disconnect" : "Connect"; - connectToOrDisconnectFrom = network?.active + $: connectOrDisconnect = network?.active ? "Disconnect" : "Connect"; + $: connectToOrDisconnectFrom = network?.active ? "Disconnect from" : "Connect to"; - } $: if (open) { password = ""; diff --git a/src/svelte-components/src/lib/ConfigStore.ts b/src/svelte-components/src/lib/ConfigStore.ts new file mode 100644 index 0000000..55a2f49 --- /dev/null +++ b/src/svelte-components/src/lib/ConfigStore.ts @@ -0,0 +1,7 @@ +import { writable } from "svelte/store"; + +export const Config = writable>({}); + +export function handleConfigUpdate(config: Record) { + Config.set(config); +} diff --git a/src/svelte-components/src/lib/DialogProps.ts b/src/svelte-components/src/lib/DialogProps.ts deleted file mode 100644 index 290f4df..0000000 --- a/src/svelte-components/src/lib/DialogProps.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { writable } from "svelte/store"; - -type HomeMachine = { - open: boolean, - home: () => any -} - -export type DialogPropsTypes = { - HomeMachine: HomeMachine -} - -export const HomeMachine = writable(); - -export default { - HomeMachine -}; diff --git a/src/svelte-components/src/lib/NetworkInfo.ts b/src/svelte-components/src/lib/NetworkInfo.ts index 1d84f3b..bad3a07 100644 --- a/src/svelte-components/src/lib/NetworkInfo.ts +++ b/src/svelte-components/src/lib/NetworkInfo.ts @@ -1,5 +1,5 @@ import { readable } from "svelte/store"; -import * as api from "./api"; +import * as api from "$lib/api"; export type WifiNetwork = { Quality: string; diff --git a/src/svelte-components/src/lib/RegisterControllerMethods.ts b/src/svelte-components/src/lib/RegisterControllerMethods.ts new file mode 100644 index 0000000..03917cd --- /dev/null +++ b/src/svelte-components/src/lib/RegisterControllerMethods.ts @@ -0,0 +1,10 @@ +type ControllerMethods = { + send: (gcode: string) => void; + goto_zero: (x: number, y: number, z: number, a: number) => void; +} + +export let ControllerMethods: ControllerMethods; + +export function registerControllerMethods(methods: ControllerMethods) { + ControllerMethods = methods; +} diff --git a/src/svelte-components/src/lib/StoreHelpers.ts b/src/svelte-components/src/lib/StoreHelpers.ts new file mode 100644 index 0000000..78604a5 --- /dev/null +++ b/src/svelte-components/src/lib/StoreHelpers.ts @@ -0,0 +1,18 @@ +import { get, type Writable } from "svelte/store"; + +export function listenForChange(writable: Writable, cb: (value: T) => void) { + const priorValue = get(writable); + + const unsubscribe = writable.subscribe((value) => { + if (value !== priorValue) { + unsubscribe(); + cb(value); + } + }); +} + +export function waitForChange(writable: Writable): Promise { + return new Promise((resolve) => { + listenForChange(writable, (value) => resolve(value)); + }); +} diff --git a/src/svelte-components/src/main.ts b/src/svelte-components/src/main.ts index 9d07eb0..c51d33d 100644 --- a/src/svelte-components/src/main.ts +++ b/src/svelte-components/src/main.ts @@ -1,10 +1,11 @@ import 'polyfill-object.fromentries'; -import AdminNetworkView from './components/AdminNetworkView.svelte'; -import { init as initNetworkInfo } from './lib/NetworkInfo'; -import DialogHost from "./components/DialogHost.svelte"; -import DialogProps from "./lib/DialogProps"; -import type { DialogPropsTypes } from "./lib/DialogProps"; +import AdminNetworkView from '$components/AdminNetworkView.svelte'; +import DialogHost, { showDialog } from "$dialogs/DialogHost.svelte"; +import { handleConfigUpdate } from '$lib/ConfigStore'; +import { init as initNetworkInfo } from '$lib/NetworkInfo'; +import { handleControllerStateUpdate } from "$dialogs/ProbeDialog.svelte"; +import { registerControllerMethods } from "$lib/RegisterControllerMethods"; export function createComponent(component: string, target: HTMLElement, props: Record) { switch (component) { @@ -19,17 +20,10 @@ export function createComponent(component: string, target: HTMLElement, props: R } } -export function showDialog(dialog: T, props: DialogPropsTypes[T]) { - switch (dialog) { - case "HomeMachine": - DialogProps.HomeMachine.set({ ...props, open: true }); - break; - - default: - throw new Error(`Unknown dialog '${dialog}`); - } -} - export { - initNetworkInfo + initNetworkInfo, + showDialog, + handleControllerStateUpdate, + handleConfigUpdate, + registerControllerMethods, }; diff --git a/src/svelte-components/tsconfig.json b/src/svelte-components/tsconfig.json index 4878d84..5bcd848 100644 --- a/src/svelte-components/tsconfig.json +++ b/src/svelte-components/tsconfig.json @@ -6,6 +6,11 @@ "module": "esnext", "resolveJsonModule": true, "baseUrl": ".", + "paths": { + "$lib/*": ["src/lib/*"], + "$components/*": ["src/components/*"], + "$dialogs/*": ["src/dialogs/*"] + }, /** * Typecheck JS in `.svelte` and `.js` files by default. * Disable checkJs if you'd like to use dynamic types in JS. diff --git a/src/svelte-components/vite.config.ts b/src/svelte-components/vite.config.ts index 33ccea6..eeb6a0e 100644 --- a/src/svelte-components/vite.config.ts +++ b/src/svelte-components/vite.config.ts @@ -7,6 +7,13 @@ export default defineConfig({ plugins: [ svelte() ], + resolve: { + alias: { + $lib: resolve('./src/lib'), + $dialogs: resolve('./src/dialogs'), + $components: resolve('./src/components') + } + }, build: { target: "chrome60", lib: {