UI: A axis surface (DRO row, jog, Home A, settings page)
Front-end side of the gplan-integrated A axis (B3).
- a-axis-view.{js,pug}: dedicated settings page that mounts the
AAxisSettings Svelte component and lives at #a-axis in the V09
settings rail.
- AAxisSettings.svelte: aux.json-backed form (axis letter, port,
homing direction, soft limits, ATC pin map, etc.) with master
Save integration via 'onefin:save-all'.
- main.ts + SettingsView.svelte: register AAxisSettings in the
Svelte component map; SettingsView no longer embeds the W axis
fieldset.
- settings-shell-view: 'A Axis' rail entry; route to a-axis-view.
- app.js: extend settings family to include 'a-axis'; broadcast
onefin:save-all from the master Save button.
- control-view: Home All button waits for the gantry cycle to
finish before firing Home A on a non-virtual setup; A jog
buttons; aux_jog/aux_home/aux_jog_incr methods.
- control-view.pug: A row in the DRO (with set-position + zero +
home actions), A- / A+ tiles in the jog grid (gated on
w.enabled || a.enabled), legacy W row kept for installs that
haven't migrated to the gplan integration.
- style.styl: dro-axis.axis-w color.
This commit is contained in:
20
src/js/a-axis-view.js
Normal file
20
src/js/a-axis-view.js
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
// V09 A-axis page — mounts the AAxisSettings Svelte component
|
||||||
|
// inside the settings shell so it gets a real top-level rail entry
|
||||||
|
// instead of being a soft-link anchor inside Display & Units.
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
template: "#a-axis-view-template",
|
||||||
|
|
||||||
|
attached: function () {
|
||||||
|
this.svelteComponent = SvelteComponents.createComponent(
|
||||||
|
"AAxisSettings",
|
||||||
|
document.getElementById("a-axis-mount")
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
detached: function () {
|
||||||
|
if (this.svelteComponent) this.svelteComponent.$destroy();
|
||||||
|
},
|
||||||
|
};
|
||||||
@@ -391,6 +391,7 @@ module.exports = new Vue({
|
|||||||
"admin-general", "admin-network",
|
"admin-general", "admin-network",
|
||||||
"motor", "tool", "io", "macros",
|
"motor", "tool", "io", "macros",
|
||||||
"help", "cheat-sheet",
|
"help", "cheat-sheet",
|
||||||
|
"a-axis",
|
||||||
];
|
];
|
||||||
const initialHead = (location.hash || "").replace(/^#/, "").split(":")[0];
|
const initialHead = (location.hash || "").replace(/^#/, "").split(":")[0];
|
||||||
if (settingsFamily.indexOf(initialHead) === -1) {
|
if (settingsFamily.indexOf(initialHead) === -1) {
|
||||||
@@ -626,6 +627,7 @@ module.exports = new Vue({
|
|||||||
"admin-general", "admin-network",
|
"admin-general", "admin-network",
|
||||||
"motor", "tool", "io", "macros",
|
"motor", "tool", "io", "macros",
|
||||||
"help", "cheat-sheet",
|
"help", "cheat-sheet",
|
||||||
|
"a-axis",
|
||||||
];
|
];
|
||||||
|
|
||||||
if (head == "control") {
|
if (head == "control") {
|
||||||
@@ -687,6 +689,13 @@ module.exports = new Vue({
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
await api.put("config/save", this.config);
|
await api.put("config/save", this.config);
|
||||||
|
// Notify any embedded Svelte subviews that own their
|
||||||
|
// own persistence (A axis -> aux.json, etc.) that
|
||||||
|
// the user just hit the master Save button. They
|
||||||
|
// listen for `onefin:save-all` and PUT their state.
|
||||||
|
try {
|
||||||
|
window.dispatchEvent(new CustomEvent("onefin:save-all"));
|
||||||
|
} catch (_e) {}
|
||||||
this.modified = false;
|
this.modified = false;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Save failed:", error);
|
console.error("Save failed:", error);
|
||||||
|
|||||||
@@ -249,13 +249,83 @@ module.exports = {
|
|||||||
api.put(`home/${axis}/clear`);
|
api.put(`home/${axis}/clear`);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
aux_home: function () {
|
||||||
|
api.put("aux/home").catch(function (err) {
|
||||||
|
console.error("Aux home failed:", err);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
// Home every enabled axis (legacy Onefinity "Home All"). Sequence:
|
||||||
|
// 1. Z, X, Y (and A/B/C if enabled) via /api/home on the AVR
|
||||||
|
// 2. Auxiliary axis via /api/aux/home on the ESP
|
||||||
|
// ONLY when the auxcnc axis is not integrated as a virtual
|
||||||
|
// machine axis. With the gplan A-axis integration (synthetic
|
||||||
|
// motor 4 enabled), Mach.home() already homes the external
|
||||||
|
// axis as part of the xyzabc pass - calling aux/home
|
||||||
|
// afterwards would home it a second time.
|
||||||
|
// /api/home returns as soon as the request is queued, not when
|
||||||
|
// homing completes, so we have to watch state.cycle:
|
||||||
|
// - first wait for it to *leave* 'idle' (cycle began),
|
||||||
|
// - then wait for it to come *back* to 'idle' (cycle ended).
|
||||||
|
// Only then do we fire the auxiliary home, so the gantry and the
|
||||||
|
// auxcnc ESP never move at the same time.
|
||||||
home_all: async function () {
|
home_all: async function () {
|
||||||
this.ask_home = false;
|
this.ask_home = false;
|
||||||
try {
|
try {
|
||||||
await api.put("home");
|
await api.put("home");
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("Home all failed:", e);
|
console.error("Home all (XYZ) failed:", e);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
if (!this.w || !this.w.enabled) return;
|
||||||
|
|
||||||
|
// When the synthetic external motor (index 4) is enabled,
|
||||||
|
// the auxcnc axis is mapped onto a real machine axis letter
|
||||||
|
// (e.g. A) and was already homed by /api/home above.
|
||||||
|
if (this.state && this.state["4me"]) return;
|
||||||
|
|
||||||
|
const wait = (ms) => new Promise(r => setTimeout(r, ms));
|
||||||
|
const cycleNow = () => (this.state && this.state.cycle) || "idle";
|
||||||
|
|
||||||
|
// Phase 1: wait up to 5s for the homing cycle to actually start.
|
||||||
|
// If the request was rejected upstream (e.g. estopped) cycle
|
||||||
|
// never leaves idle and we bail rather than home A in isolation.
|
||||||
|
const startedAt = Date.now();
|
||||||
|
while (Date.now() - startedAt < 5000) {
|
||||||
|
if (cycleNow() != "idle") break;
|
||||||
|
await wait(100);
|
||||||
|
}
|
||||||
|
if (cycleNow() == "idle") {
|
||||||
|
console.warn("home_all: main homing cycle never started; skipping aux");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Phase 2: wait up to 2 minutes for the gantry to finish.
|
||||||
|
const settledAt = Date.now();
|
||||||
|
while (Date.now() - settledAt < 120000) {
|
||||||
|
if (cycleNow() == "idle") break;
|
||||||
|
await wait(200);
|
||||||
|
}
|
||||||
|
if (cycleNow() != "idle") {
|
||||||
|
console.warn("home_all: gantry homing did not complete in time");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
api.put("aux/home").catch(function (err) {
|
||||||
|
console.error("Aux home failed:", err);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
aux_jog: function (delta_mm) {
|
||||||
|
api.put("aux/jog", { mm: delta_mm }).catch(function (err) {
|
||||||
|
console.error("Aux jog failed:", err);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
aux_jog_incr: function (sign) {
|
||||||
|
const amount = this.jog_incr_amounts[this.display_units][this.jog_incr];
|
||||||
|
const delta_mm = sign * (this.metric ? amount : amount * 25.4);
|
||||||
|
this.aux_jog(delta_mm);
|
||||||
},
|
},
|
||||||
|
|
||||||
show_set_position: function (axis) {
|
show_set_position: function (axis) {
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ module.exports = {
|
|||||||
"io-view": require("./io-view"),
|
"io-view": require("./io-view"),
|
||||||
"macros-view": require("./macros"),
|
"macros-view": require("./macros"),
|
||||||
"help-view": require("./help-view"),
|
"help-view": require("./help-view"),
|
||||||
|
"a-axis-view": require("./a-axis-view"),
|
||||||
"cheat-sheet-view": {
|
"cheat-sheet-view": {
|
||||||
template: "#cheat-sheet-view-template",
|
template: "#cheat-sheet-view-template",
|
||||||
data: function () {
|
data: function () {
|
||||||
@@ -56,6 +57,9 @@ module.exports = {
|
|||||||
{ sub: "motor", motor: 1, href: "#motor:1", icon: "fa-arrows-up-down-left-right", label: "Motor 1" },
|
{ sub: "motor", motor: 1, href: "#motor:1", icon: "fa-arrows-up-down-left-right", label: "Motor 1" },
|
||||||
{ sub: "motor", motor: 2, href: "#motor:2", icon: "fa-arrows-up-down-left-right", label: "Motor 2" },
|
{ sub: "motor", motor: 2, href: "#motor:2", icon: "fa-arrows-up-down-left-right", label: "Motor 2" },
|
||||||
{ sub: "motor", motor: 3, href: "#motor:3", icon: "fa-arrows-up-down-left-right", label: "Motor 3" },
|
{ sub: "motor", motor: 3, href: "#motor:3", icon: "fa-arrows-up-down-left-right", label: "Motor 3" },
|
||||||
|
// Auxiliary axis (auxcnc ESP32 - exposed to gplan as A).
|
||||||
|
// Mounts the AAxisSettings Svelte component on its own page.
|
||||||
|
{ sub: "a-axis", href: "#a-axis", icon: "fa-arrows-up-down", label: "A Axis" },
|
||||||
{ section: " " },
|
{ section: " " },
|
||||||
{ sub: "help", href: "#help", icon: "fa-circle-question", label: "Help" },
|
{ sub: "help", href: "#help", icon: "fa-circle-question", label: "Help" },
|
||||||
],
|
],
|
||||||
@@ -133,6 +137,7 @@ module.exports = {
|
|||||||
// layout, which under tablet mode pulls the fixed header out
|
// layout, which under tablet mode pulls the fixed header out
|
||||||
// of view.
|
// of view.
|
||||||
if (location.hash !== item.href) location.hash = item.href;
|
if (location.hash !== item.href) location.hash = item.href;
|
||||||
|
this._a_axis_focus = (item.sub === "a-axis");
|
||||||
const reset = () => {
|
const reset = () => {
|
||||||
// Force any inadvertent ancestor scroll back to 0 before
|
// Force any inadvertent ancestor scroll back to 0 before
|
||||||
// we move .settings-content explicitly.
|
// we move .settings-content explicitly.
|
||||||
@@ -155,6 +160,7 @@ module.exports = {
|
|||||||
requestAnimationFrame(reset);
|
requestAnimationFrame(reset);
|
||||||
}, 320);
|
}, 320);
|
||||||
} else {
|
} else {
|
||||||
|
this._a_axis_focus = false;
|
||||||
if (location.hash !== item.href) location.hash = item.href;
|
if (location.hash !== item.href) location.hash = item.href;
|
||||||
// Reset .app-body scroll so each route starts at the top.
|
// Reset .app-body scroll so each route starts at the top.
|
||||||
const body = document.querySelector(".app-body");
|
const body = document.querySelector(".app-body");
|
||||||
|
|||||||
4
src/pug/templates/a-axis-view.pug
Normal file
4
src/pug/templates/a-axis-view.pug
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
script#a-axis-view-template(type="text/x-template")
|
||||||
|
#a-axis-page
|
||||||
|
h1 A Axis (auxcnc)
|
||||||
|
#a-axis-mount
|
||||||
@@ -92,8 +92,33 @@ script#control-view-template(type="text/x-template")
|
|||||||
.fa.fa-arrow-down.ico(style="transform: rotate(-45deg)")
|
.fa.fa-arrow-down.ico(style="transform: rotate(-45deg)")
|
||||||
button.jbtn(@click="jog_fn(0, 0, -1, 0)") Z−
|
button.jbtn(@click="jog_fn(0, 0, -1, 0)") Z−
|
||||||
|
|
||||||
// Row 4 — A axis (rotary) when rotary is enabled.
|
// Row 4 — A axis (the auxcnc-driven external axis) when enabled.
|
||||||
template(v-if="state['2an'] == 3")
|
// A- | A+ | Probe XYZ | Probe Z
|
||||||
|
// "Home A" lives in the DRO table's actions column on the
|
||||||
|
// right, so it doesn't need a tile here. The legacy w.enabled
|
||||||
|
// gate is kept so older installs (where the auxcnc axis still
|
||||||
|
// appears as W via the side-channel) keep working.
|
||||||
|
template(v-if="w.enabled || a.enabled")
|
||||||
|
button.jbtn(@click="aux_jog_incr(-1)",
|
||||||
|
:disabled="!(w.enabled || a.enabled)")
|
||||||
|
.fa.fa-arrow-down.ico
|
||||||
|
span.lbl A−
|
||||||
|
button.jbtn(@click="aux_jog_incr(+1)",
|
||||||
|
:disabled="!(w.enabled || a.enabled)")
|
||||||
|
.fa.fa-arrow-up.ico
|
||||||
|
span.lbl A+
|
||||||
|
button.jbtn(@click="showProbeDialog('xyz')",
|
||||||
|
:class="{'load-on': !state['pw']}")
|
||||||
|
.fa.fa-bullseye.ico
|
||||||
|
span.lbl Probe XYZ
|
||||||
|
button.jbtn(@click="showProbeDialog('z')",
|
||||||
|
:class="{'load-on': !state['pw']}")
|
||||||
|
.fa.fa-bullseye.ico
|
||||||
|
span.lbl Probe Z
|
||||||
|
|
||||||
|
// Row 4 — A axis (rotary) when no W and rotary is enabled
|
||||||
|
// (Vue 1 has no v-else-if; we negate w.enabled explicitly.)
|
||||||
|
template(v-if="!w.enabled && state['2an'] == 3")
|
||||||
button.jbtn.dir(@click="jog_fn(0, 0, 0, -1)")
|
button.jbtn.dir(@click="jog_fn(0, 0, 0, -1)")
|
||||||
.fa.fa-rotate-left.ico
|
.fa.fa-rotate-left.ico
|
||||||
span.lbl A−
|
span.lbl A−
|
||||||
@@ -109,7 +134,7 @@ script#control-view-template(type="text/x-template")
|
|||||||
span.lbl Probe
|
span.lbl Probe
|
||||||
|
|
||||||
// Row 4 — fallback probe / zero / home shortcuts
|
// Row 4 — fallback probe / zero / home shortcuts
|
||||||
template(v-if="state['2an'] != 3")
|
template(v-if="!w.enabled && state['2an'] != 3")
|
||||||
button.jbtn(@click="showProbeDialog('xyz')",
|
button.jbtn(@click="showProbeDialog('xyz')",
|
||||||
:class="{'load-on': !state['pw']}")
|
:class="{'load-on': !state['pw']}")
|
||||||
.fa.fa-bullseye.ico
|
.fa.fa-bullseye.ico
|
||||||
@@ -193,7 +218,8 @@ script#control-view-template(type="text/x-template")
|
|||||||
.actions-cell
|
.actions-cell
|
||||||
// Master Home All. Each row's Actions cell has a per-axis
|
// Master Home All. Each row's Actions cell has a per-axis
|
||||||
// home button; this header-level button homes every
|
// home button; this header-level button homes every
|
||||||
// enabled axis (legacy Onefinity behavior).
|
// enabled axis (legacy Onefinity behavior). Auto-includes
|
||||||
|
// the auxiliary A axis when it is enabled.
|
||||||
button.icon-btn(:disabled="!is_idle",
|
button.icon-btn(:disabled="!is_idle",
|
||||||
title="Home all axes.", @click="home_all()")
|
title="Home all axes.", @click="home_all()")
|
||||||
.fa.fa-house-chimney
|
.fa.fa-house-chimney
|
||||||
@@ -223,6 +249,28 @@ script#control-view-template(type="text/x-template")
|
|||||||
@click=`home('${axis}')`)
|
@click=`home('${axis}')`)
|
||||||
.fa.fa-home
|
.fa.fa-home
|
||||||
|
|
||||||
|
// Legacy auxiliary-axis row - shown only when the auxcnc stepper is
|
||||||
|
// *not* exposed as a virtual A axis. After v2 the standard
|
||||||
|
// A row above renders this axis natively (with full offset
|
||||||
|
// + set-position support); this row only appears on legacy
|
||||||
|
// installs that haven't migrated yet.
|
||||||
|
.dro-row(:class="w.klass + ' ' + w.tklass",
|
||||||
|
v-if="w.enabled && !a.enabled",
|
||||||
|
:title="w.title")
|
||||||
|
.dro-axis.axis-w W
|
||||||
|
.dro-pos: unit-value(:value="w.pos", precision=4)
|
||||||
|
.dro-sec: unit-value(:value="w.abs", precision=3)
|
||||||
|
.dro-sec —
|
||||||
|
.actions-cell
|
||||||
|
button.icon-btn(disabled, style="visibility:hidden")
|
||||||
|
.fa.fa-gear
|
||||||
|
button.icon-btn(disabled, style="visibility:hidden")
|
||||||
|
.fa.fa-location-dot
|
||||||
|
button.icon-btn(:class="w.homed ? 'state-green' : 'state-amber'",
|
||||||
|
:disabled="!w.enabled",
|
||||||
|
title="Home auxiliary axis.", @click="aux_home()")
|
||||||
|
.fa.fa-home
|
||||||
|
|
||||||
// ----- Status strip -----
|
// ----- Status strip -----
|
||||||
.status-strip
|
.status-strip
|
||||||
.stat-card
|
.stat-card
|
||||||
|
|||||||
@@ -46,6 +46,8 @@ script#settings-shell-view-template(type="text/x-template")
|
|||||||
:index="index", :config="config", :template="template", :state="state")
|
:index="index", :config="config", :template="template", :state="state")
|
||||||
io-view(v-if="sub === 'io' && config_ready",
|
io-view(v-if="sub === 'io' && config_ready",
|
||||||
:index="index", :config="config", :template="template", :state="state")
|
:index="index", :config="config", :template="template", :state="state")
|
||||||
|
a-axis-view(v-if="sub === 'a-axis' && config_ready",
|
||||||
|
:index="index", :config="config", :template="template", :state="state")
|
||||||
macros-view(v-if="sub === 'macros' && config_ready",
|
macros-view(v-if="sub === 'macros' && config_ready",
|
||||||
:index="index", :config="config", :template="template", :state="state")
|
:index="index", :config="config", :template="template", :state="state")
|
||||||
help-view(v-if="sub === 'help' && config_ready",
|
help-view(v-if="sub === 'help' && config_ready",
|
||||||
|
|||||||
@@ -1457,6 +1457,9 @@ tt.save
|
|||||||
.dro-axis.axis-c
|
.dro-axis.axis-c
|
||||||
color #d946ef
|
color #d946ef
|
||||||
|
|
||||||
|
.dro-axis.axis-w
|
||||||
|
color #7c3aed
|
||||||
|
|
||||||
.dro-pos
|
.dro-pos
|
||||||
font-family 'JetBrains Mono', monospace
|
font-family 'JetBrains Mono', monospace
|
||||||
font-size 36px
|
font-size 36px
|
||||||
|
|||||||
304
src/svelte-components/src/components/AAxisSettings.svelte
Normal file
304
src/svelte-components/src/components/AAxisSettings.svelte
Normal file
@@ -0,0 +1,304 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { onMount } from "svelte";
|
||||||
|
import Button, { Label } from "@smui/button";
|
||||||
|
import * as api from "$lib/api";
|
||||||
|
|
||||||
|
// Mirrors the DEFAULTS in src/py/bbctrl/AuxAxis.py. The "enabled"
|
||||||
|
// flag is read-only here; toggling the auxiliary A axis on/off
|
||||||
|
// is done via aux.json on disk, so adding/removing the hardware
|
||||||
|
// doesn't have a surprise UI that bricks bring-up. Legacy aux.json
|
||||||
|
// files using min_w/max_w are migrated up to min_mm/max_mm by
|
||||||
|
// AuxAxis._migrate_legacy_fields on load.
|
||||||
|
type AuxConfig = {
|
||||||
|
enabled: boolean;
|
||||||
|
port: string;
|
||||||
|
baud: number;
|
||||||
|
steps_per_mm: number;
|
||||||
|
dir_sign: number;
|
||||||
|
axis_letter: string;
|
||||||
|
min_mm: number;
|
||||||
|
max_mm: number;
|
||||||
|
max_feed_mm_min: number;
|
||||||
|
max_velocity_m_per_min: number;
|
||||||
|
max_accel_km_per_min2: number;
|
||||||
|
max_jerk_km_per_min3: number;
|
||||||
|
home_dir: string;
|
||||||
|
home_position_mm: number;
|
||||||
|
home_fast_sps: number;
|
||||||
|
home_slow_sps: number;
|
||||||
|
home_backoff_steps: number;
|
||||||
|
home_maxtravel_steps: number;
|
||||||
|
step_max_sps: number;
|
||||||
|
step_accel_sps2: number;
|
||||||
|
step_start_sps: number;
|
||||||
|
limit_low: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
let cfg: AuxConfig | null = null;
|
||||||
|
let status: { enabled: boolean; present: boolean; homed: boolean; pos_mm: number } | null = null;
|
||||||
|
let busy = false;
|
||||||
|
|
||||||
|
// Listen for the global "save-all" event the Vue root dispatches
|
||||||
|
// when the user clicks the master Save button. We persist our
|
||||||
|
// current cfg the same way the in-form button used to. This way
|
||||||
|
// the user only ever needs one Save button.
|
||||||
|
function onGlobalSave() {
|
||||||
|
save().catch(e => console.error("aux save failed:", e));
|
||||||
|
}
|
||||||
|
|
||||||
|
onMount(async () => {
|
||||||
|
await refresh();
|
||||||
|
window.addEventListener("onefin:save-all", onGlobalSave);
|
||||||
|
return () => window.removeEventListener("onefin:save-all", onGlobalSave);
|
||||||
|
});
|
||||||
|
|
||||||
|
async function refresh() {
|
||||||
|
try {
|
||||||
|
cfg = await api.GET("aux/config");
|
||||||
|
status = await api.GET("aux/status");
|
||||||
|
} catch (e) {
|
||||||
|
console.error("Failed to load aux config/status:", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function save() {
|
||||||
|
if (!cfg) return;
|
||||||
|
busy = true;
|
||||||
|
try {
|
||||||
|
await api.PUT("aux/config/save", cfg);
|
||||||
|
await refresh();
|
||||||
|
} catch (e) {
|
||||||
|
console.error("Failed to save aux config:", e);
|
||||||
|
throw e;
|
||||||
|
} finally {
|
||||||
|
busy = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mark the root config as modified whenever an auxiliary axis
|
||||||
|
// field is edited, so the master Save button highlights and
|
||||||
|
// the user knows there are unsaved changes.
|
||||||
|
function markDirty() {
|
||||||
|
try {
|
||||||
|
const root = (window as any).$root || (window as any).Vue?.root;
|
||||||
|
if (root && "modified" in root) root.modified = true;
|
||||||
|
} catch (_e) {}
|
||||||
|
// Also dispatch a generic event the Vue root listens for.
|
||||||
|
window.dispatchEvent(new CustomEvent("onefin:dirty"));
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="a-axis-settings">
|
||||||
|
{#if !cfg}
|
||||||
|
<p class="tip">Loading A axis configuration...</p>
|
||||||
|
{:else}
|
||||||
|
<div class="status">
|
||||||
|
{#if status}
|
||||||
|
<span>
|
||||||
|
Status:
|
||||||
|
{#if !status.enabled}
|
||||||
|
disabled
|
||||||
|
{:else if !status.present}
|
||||||
|
offline
|
||||||
|
{:else if status.homed}
|
||||||
|
homed at {status.pos_mm.toFixed(3)} mm
|
||||||
|
{:else}
|
||||||
|
connected, unhomed
|
||||||
|
{/if}
|
||||||
|
</span>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="pure-form pure-form-aligned" on:input={markDirty} on:change={markDirty}>
|
||||||
|
<fieldset>
|
||||||
|
<div class="pure-control-group" title="Enable the auxiliary axis (auxcnc-driven A). Edit aux.json to toggle.">
|
||||||
|
<label for="enabled">enabled</label>
|
||||||
|
<input id="enabled" type="checkbox" checked={cfg.enabled} disabled />
|
||||||
|
<label for="" class="units">(edit aux.json)</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="pure-control-group" title="Serial port for the auxcnc ESP32.">
|
||||||
|
<label for="port">serial port</label>
|
||||||
|
<input id="port" type="text" bind:value={cfg.port} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="pure-control-group" title="Serial baud rate.">
|
||||||
|
<label for="baud">baud</label>
|
||||||
|
<input id="baud" type="number" bind:value={cfg.baud} min={1200} step={1} />
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
<h3>Mechanics</h3>
|
||||||
|
<fieldset>
|
||||||
|
<div class="pure-control-group" title="Logical steps per mm of axis travel.">
|
||||||
|
<label for="steps_per_mm">steps per mm</label>
|
||||||
|
<input id="steps_per_mm" type="number" bind:value={cfg.steps_per_mm} step="any" />
|
||||||
|
<label for="" class="units">steps/mm</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="pure-control-group" title="Direction sign: +1 or -1. Flip if A+ moves the wrong way.">
|
||||||
|
<label for="dir_sign">direction sign</label>
|
||||||
|
<select id="dir_sign" bind:value={cfg.dir_sign}>
|
||||||
|
<option value={1}>+1</option>
|
||||||
|
<option value={-1}>-1</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="pure-control-group" title="gcode axis letter exposed to the planner. Default 'a' (the standard 4th axis).">
|
||||||
|
<label for="axis_letter">axis letter</label>
|
||||||
|
<select id="axis_letter" bind:value={cfg.axis_letter}>
|
||||||
|
<option value="a">A</option>
|
||||||
|
<option value="b">B</option>
|
||||||
|
<option value="c">C</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="pure-control-group" title="Soft-limit minimum in mm.">
|
||||||
|
<label for="min_mm">soft min</label>
|
||||||
|
<input id="min_mm" type="number" bind:value={cfg.min_mm} step="any" />
|
||||||
|
<label for="" class="units">mm</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="pure-control-group" title="Soft-limit maximum in mm.">
|
||||||
|
<label for="max_mm">soft max</label>
|
||||||
|
<input id="max_mm" type="number" bind:value={cfg.max_mm} step="any" />
|
||||||
|
<label for="" class="units">mm</label>
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
<h3>Planner Limits</h3>
|
||||||
|
<fieldset>
|
||||||
|
<div class="pure-control-group" title="Maximum velocity used by gplan trajectory planning.">
|
||||||
|
<label for="max_velocity_m_per_min">max velocity</label>
|
||||||
|
<input id="max_velocity_m_per_min" type="number" bind:value={cfg.max_velocity_m_per_min} step="any" />
|
||||||
|
<label for="" class="units">m/min</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="pure-control-group" title="Maximum acceleration used by gplan trajectory planning.">
|
||||||
|
<label for="max_accel_km_per_min2">max acceleration</label>
|
||||||
|
<input id="max_accel_km_per_min2" type="number" bind:value={cfg.max_accel_km_per_min2} step="any" />
|
||||||
|
<label for="" class="units">km/min²</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="pure-control-group" title="Maximum jerk used by gplan trajectory planning.">
|
||||||
|
<label for="max_jerk_km_per_min3">max jerk</label>
|
||||||
|
<input id="max_jerk_km_per_min3" type="number" bind:value={cfg.max_jerk_km_per_min3} step="any" />
|
||||||
|
<label for="" class="units">km/min³</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="pure-control-group" title="Informational max feed; rate caps live on the ESP via step_max_sps.">
|
||||||
|
<label for="max_feed_mm_min">max feed</label>
|
||||||
|
<input id="max_feed_mm_min" type="number" bind:value={cfg.max_feed_mm_min} step="any" />
|
||||||
|
<label for="" class="units">mm/min</label>
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
<h3>Homing</h3>
|
||||||
|
<fieldset>
|
||||||
|
<div class="pure-control-group" title="Direction the axis moves when looking for the home limit switch.">
|
||||||
|
<label for="home_dir">home direction</label>
|
||||||
|
<select id="home_dir" bind:value={cfg.home_dir}>
|
||||||
|
<option value="-">- (toward A-)</option>
|
||||||
|
<option value="+">+ (toward A+)</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="pure-control-group" title="Axis position assigned when homing completes.">
|
||||||
|
<label for="home_position_mm">home position</label>
|
||||||
|
<input id="home_position_mm" type="number" bind:value={cfg.home_position_mm} step="any" />
|
||||||
|
<label for="" class="units">mm</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="pure-control-group" title="Fast seek rate during homing search.">
|
||||||
|
<label for="home_fast_sps">fast seek</label>
|
||||||
|
<input id="home_fast_sps" type="number" bind:value={cfg.home_fast_sps} step={1} min={1} />
|
||||||
|
<label for="" class="units">steps/s</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="pure-control-group" title="Slow seek rate during homing latch.">
|
||||||
|
<label for="home_slow_sps">slow seek</label>
|
||||||
|
<input id="home_slow_sps" type="number" bind:value={cfg.home_slow_sps} step={1} min={1} />
|
||||||
|
<label for="" class="units">steps/s</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="pure-control-group" title="Backoff after the limit triggers, before the slow seek.">
|
||||||
|
<label for="home_backoff_steps">backoff</label>
|
||||||
|
<input id="home_backoff_steps" type="number" bind:value={cfg.home_backoff_steps} step={1} min={0} />
|
||||||
|
<label for="" class="units">steps</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="pure-control-group" title="Maximum travel before homing aborts as a runaway.">
|
||||||
|
<label for="home_maxtravel_steps">max travel</label>
|
||||||
|
<input id="home_maxtravel_steps" type="number" bind:value={cfg.home_maxtravel_steps} step={1} min={1} />
|
||||||
|
<label for="" class="units">steps</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="pure-control-group" title="Limit switch active-low? Off = active-high.">
|
||||||
|
<label for="limit_low">limit active low</label>
|
||||||
|
<input id="limit_low" type="checkbox" bind:checked={cfg.limit_low} />
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
<h3>Step Profile</h3>
|
||||||
|
<fieldset>
|
||||||
|
<div class="pure-control-group" title="Maximum step rate during normal moves.">
|
||||||
|
<label for="step_max_sps">max rate</label>
|
||||||
|
<input id="step_max_sps" type="number" bind:value={cfg.step_max_sps} step={1} min={1} />
|
||||||
|
<label for="" class="units">steps/s</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="pure-control-group" title="Acceleration in steps per second squared.">
|
||||||
|
<label for="step_accel_sps2">acceleration</label>
|
||||||
|
<input id="step_accel_sps2" type="number" bind:value={cfg.step_accel_sps2} step={1} min={1} />
|
||||||
|
<label for="" class="units">steps/s²</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="pure-control-group" title="Initial step rate at the start of a move.">
|
||||||
|
<label for="step_start_sps">start rate</label>
|
||||||
|
<input id="step_start_sps" type="number" bind:value={cfg.step_start_sps} step={1} min={1} />
|
||||||
|
<label for="" class="units">steps/s</label>
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
<div class="tip">
|
||||||
|
Changes are written to aux.json when you click the
|
||||||
|
master <strong>Save</strong> button at the bottom of the
|
||||||
|
settings rail. Homing rates and the limit polarity are
|
||||||
|
pushed to the ESP immediately; any running motion is
|
||||||
|
unaffected. Re-home the auxiliary axis after changing direction,
|
||||||
|
sign, or step settings.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.a-axis-settings {
|
||||||
|
.status {
|
||||||
|
margin-bottom: 1em;
|
||||||
|
font-size: 90%;
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.actions {
|
||||||
|
margin-left: 210px;
|
||||||
|
margin-top: 1em;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.save-msg {
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tip {
|
||||||
|
margin-left: 210px;
|
||||||
|
margin-top: 1em;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
font-style: italic;
|
||||||
|
font-size: 90%;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -2,6 +2,10 @@
|
|||||||
import configTemplate from "../../../resources/config-template.json";
|
import configTemplate from "../../../resources/config-template.json";
|
||||||
import ScreenRotationDialog from "$dialogs/ScreenRotationDialog.svelte";
|
import ScreenRotationDialog from "$dialogs/ScreenRotationDialog.svelte";
|
||||||
import ConfigTemplatedInput from "./ConfigTemplatedInput.svelte";
|
import ConfigTemplatedInput from "./ConfigTemplatedInput.svelte";
|
||||||
|
// AAxisSettings is mounted directly by the V09 settings shell at
|
||||||
|
// #a-axis instead of being embedded here — see
|
||||||
|
// src/pug/templates/a-axis-view.pug.
|
||||||
|
// import AAxisSettings from "./AAxisSettings.svelte";
|
||||||
import SetTimeDialog from "$dialogs/SetTimeDialog.svelte";
|
import SetTimeDialog from "$dialogs/SetTimeDialog.svelte";
|
||||||
import Button, { Label } from "@smui/button";
|
import Button, { Label } from "@smui/button";
|
||||||
|
|
||||||
@@ -94,6 +98,10 @@
|
|||||||
{/each}
|
{/each}
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
||||||
|
<!-- W Axis (auxcnc) is now its own routed page in the V09
|
||||||
|
settings shell (#a-axis). Keep the SettingsView free of
|
||||||
|
that section so we don't render it twice. -->
|
||||||
|
|
||||||
<h2 id="sec-path-accuracy" data-sec="gcode">Path Accuracy</h2>
|
<h2 id="sec-path-accuracy" data-sec="gcode">Path Accuracy</h2>
|
||||||
<fieldset data-sec="gcode">
|
<fieldset data-sec="gcode">
|
||||||
<ConfigTemplatedInput key={`settings.max-deviation`} />
|
<ConfigTemplatedInput key={`settings.max-deviation`} />
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ matchAll.shim();
|
|||||||
import AdminNetworkView from "$components/AdminNetworkView.svelte";
|
import AdminNetworkView from "$components/AdminNetworkView.svelte";
|
||||||
import SettingsView from "$components/SettingsView.svelte";
|
import SettingsView from "$components/SettingsView.svelte";
|
||||||
import HelpView from "$components/HelpView.svelte";
|
import HelpView from "$components/HelpView.svelte";
|
||||||
|
import AAxisSettings from "$components/AAxisSettings.svelte";
|
||||||
import DialogHost, { showDialog } from "$dialogs/DialogHost.svelte";
|
import DialogHost, { showDialog } from "$dialogs/DialogHost.svelte";
|
||||||
import { handleConfigUpdate, setDisplayUnits } from "$lib/ConfigStore";
|
import { handleConfigUpdate, setDisplayUnits } from "$lib/ConfigStore";
|
||||||
import { handleControllerStateUpdate } from "$lib/ControllerState";
|
import { handleControllerStateUpdate } from "$lib/ControllerState";
|
||||||
@@ -22,6 +23,9 @@ export function createComponent(component: string, target: HTMLElement, props: R
|
|||||||
case "HelpView":
|
case "HelpView":
|
||||||
return new HelpView({ target, props });
|
return new HelpView({ target, props });
|
||||||
|
|
||||||
|
case "AAxisSettings":
|
||||||
|
return new AAxisSettings({ target, props });
|
||||||
|
|
||||||
case "DialogHost":
|
case "DialogHost":
|
||||||
return new DialogHost({ target, props });
|
return new DialogHost({ target, props });
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user