Align AXIS control flow and fix pause and program rendering
Document source UI gates, explicit native live-plot clearing, and remaining parity boundaries. Fix pause/resume transport continuity, repeated stepping, coordinate previews, and spindle override state. Optimize large program snapshots and rendering, and cover the control flows with native Tcl, WASM, and browser checks. Validation: 22 native tests and source/browser checks pass. Worker/App regression: 113 of 123 pass; 10 pre-existing failures remain documented with no new failures.
This commit is contained in:
81
web/worker/test_axis_source_execution.mjs
Normal file
81
web/worker/test_axis_source_execution.mjs
Normal file
@@ -0,0 +1,81 @@
|
||||
import assert from "node:assert/strict";
|
||||
import { readFile } from "node:fs/promises";
|
||||
import createModule from "../../build-wasm/linuxcnc-sim-core.js";
|
||||
import { loadSimulationCase, toWorkerConfiguration } from "../workspace/sim-case-loader.mjs";
|
||||
import { XyzacSession, CONTEXT_ID } from "./xyzac-session.mjs";
|
||||
|
||||
const bundle = await loadSimulationCase({ path: "linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzac-trt.ini", fetchImpl: async (url) => {
|
||||
try { const source = await readFile(new URL(`../../${String(url).replace(/^\//, "")}`, import.meta.url), "utf8"); return { ok: true, text: async () => source }; }
|
||||
catch { return { ok: false, text: async () => "" }; }
|
||||
} });
|
||||
const core = await createModule({ wasmBinary: await readFile(new URL("../../build-wasm/linuxcnc-sim-core.wasm", import.meta.url)) });
|
||||
const session = new XyzacSession(core, { sessionId: "axis-source-execution" });
|
||||
let seq = 0;
|
||||
const send = (kind, payload = {}) => session.accept({ schema_version: 1, context_id: CONTEXT_ID, session_id: session.sessionId, seq: ++seq, operation_id: `source-exec-${seq}`, kind, payload });
|
||||
const ok = (kind, payload = {}) => {
|
||||
const response = send(kind, payload);
|
||||
assert.notEqual(response.kind, "ERROR", `${kind}: ${response.payload?.gate_reason ?? response.payload?.message_key ?? response.payload?.code}`);
|
||||
return response.payload;
|
||||
};
|
||||
const panel = () => ok("SNAPSHOT_REQUEST").panel_snapshot;
|
||||
const drain = () => { for (let n = 0; n < 2000 && session.wasmMotion.queueDepth() > 0; n++) ok("SIM_STEP", { cycles: 1, response: "motion_delta" }); };
|
||||
ok("HELLO"); ok("SESSION_ATTACH"); ok("LOAD_WORKSPACE", { root_path: "/workspace", configuration: toWorkerConfiguration(bundle) });
|
||||
ok("PROGRAM_LOAD", { source: "G21 G90\nG1 X1 F600\nG1 X2\nM2\n", path: "source-step.ngc" });
|
||||
assert.equal(panel().axis_state.source_task_state, "STATE_ESTOP_RESET");
|
||||
ok("SET_OVERRIDE", { feed: 0.9 });
|
||||
assert.equal(panel().axis_state.source_task_state, "STATE_ESTOP_RESET");
|
||||
ok("POWER", { active: true });
|
||||
assert.equal(panel().ui_gates.run.enabled, true);
|
||||
assert.equal(panel().ui_gates.step.enabled, true);
|
||||
assert.equal(send("PROGRAM_RUN").payload.gate_reason, "xyzac_not_all_homed");
|
||||
ok("HOME", { all: true });
|
||||
assert.equal(send("HOME", { axis: "x" }).payload.message_key, "home_joint_requires_joint_mode");
|
||||
|
||||
ok("PROGRAM_STEP");
|
||||
assert.equal(panel().program.current_line, 0, "first native Step starts at line zero and pauses");
|
||||
ok("PROGRAM_STEP");
|
||||
assert.equal(panel().program.current_line, 1);
|
||||
ok("PROGRAM_STEP");
|
||||
assert.equal(panel().program.current_line, 2);
|
||||
assert.ok(session.wasmMotion.queueDepth() > 0);
|
||||
ok("PROGRAM_STEP");
|
||||
assert.equal(panel().motion.stepping, true);
|
||||
drain();
|
||||
assert.ok(Math.abs(panel().visual.pose.x - 1) < 1e-8);
|
||||
assert.equal(panel().program.current_line, 2);
|
||||
assert.equal(panel().axis_state.operation_state, "PAUSED");
|
||||
ok("PROGRAM_STEP"); ok("PROGRAM_STEP"); drain();
|
||||
assert.ok(Math.abs(panel().visual.pose.x - 2) < 1e-8);
|
||||
ok("PROGRAM_ABORT");
|
||||
|
||||
ok("PROGRAM_LOAD", { source: "G21 G90\nG1 X5 F600\nG1 X10\nM2\n", path: "source-waiting.ngc" });
|
||||
ok("PROGRAM_RUN");
|
||||
for (let n = 0; n < 20 && panel().program.program_status !== "completed"; n++) ok("SIM_STEP", { cycles: 1 });
|
||||
assert.equal(panel().axis_state.source_interp_state, "INTERP_WAITING");
|
||||
ok("PROGRAM_PAUSE");
|
||||
const paused = panel().visual.pose;
|
||||
ok("SIM_STEP", { cycles: 2 });
|
||||
assert.deepEqual(panel().visual.pose, paused);
|
||||
ok("PROGRAM_RESUME");
|
||||
assert.equal(panel().program.program_status, "completed", "Resume restores WAITING, not READING");
|
||||
drain(); ok("SIM_STEP", { cycles: 1 });
|
||||
assert.ok(Math.abs(panel().visual.pose.x - 10) < 1e-8);
|
||||
assert.equal(panel().axis_state.source_interp_state, "INTERP_IDLE");
|
||||
|
||||
ok("PROGRAM_LOAD", { source: "G21 G90\nM2\n", path: "source-mdi.ngc" });
|
||||
ok("MDI_EXECUTE", { block: "G1 X12 F600" });
|
||||
assert.equal(panel().axis_state.source_interp_state, "INTERP_WAITING");
|
||||
assert.equal(panel().ui_gates.mdi.enabled, true);
|
||||
assert.equal(panel().ui_gates.jog.enabled, false);
|
||||
assert.equal(send("MDI_EXECUTE", { block: "G0 X0" }).kind, "ERROR");
|
||||
ok("PROGRAM_PAUSE"); ok("PROGRAM_RESUME"); drain(); ok("SIM_STEP", { cycles: 1 });
|
||||
assert.equal(panel().axis_state.source_interp_state, "INTERP_IDLE");
|
||||
assert.ok(Math.abs(panel().visual.pose.x - 12) < 1e-8);
|
||||
ok("SPINDLE_COMMAND", { rpm: -600, enabled: true });
|
||||
ok("SET_SPINDLE_OVERRIDE", { scale: 0 });
|
||||
assert.equal(panel().devices.spindles[0].direction, -1);
|
||||
assert.equal(panel().devices.spindles[0].command_rpm, 0);
|
||||
ok("SET_SPINDLE_OVERRIDE", { scale: 1 });
|
||||
assert.equal(panel().devices.spindles[0].command_rpm, -600);
|
||||
ok("SPINDLE_COMMAND", { rpm: 0, enabled: false });
|
||||
console.log(JSON.stringify({ schema: "axis-source-execution.v1", status: "verified", checks: ["ui_vs_command_gate", "source_off_state", "switchkins_type", "repeated_step", "step_motion", "waiting_pause_resume", "mdi_motion_state", "spindle_zero_override"] }));
|
||||
Reference in New Issue
Block a user