Files
linuxcncWebWASM/web/worker/test_xyzac_manual_control.mjs

79 lines
5.3 KiB
JavaScript

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 CASE = "linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzac-trt.ini";
const fetchImpl = async (url) => { try { const body = await readFile(new URL(`../../${String(url).replace(/^\//, "")}`, import.meta.url)); return { ok: true, text: async () => body.toString("utf8") }; } catch { return { ok: false, text: async () => "" }; } };
const bundle = await loadSimulationCase({ path: CASE, fetchImpl });
const core = await createModule({ wasmBinary: await readFile(new URL("../../build-wasm/linuxcnc-sim-core.wasm", import.meta.url)) });
function setup(id) {
const session = new XyzacSession(core, { sessionId: id });
const base = { schema_version: 1, context_id: CONTEXT_ID, session_id: id };
let seq = 0;
const send = (kind, operation_id, payload = {}) => session.accept({ ...base, kind, seq: ++seq, operation_id, payload });
send("HELLO", "hello"); send("SESSION_ATTACH", "attach");
assert.equal(send("LOAD_WORKSPACE", "workspace", { root_path: "/workspace", configuration: toWorkerConfiguration(bundle) }).payload.status, "verified");
assert.equal(send("POWER", "power-on", { active: true }).payload.status, "verified");
assert.equal(send("HOME", "home-all", { all: true }).payload.wasm_home_limit.state.homed, true);
return { session, send };
}
const jogCase = setup("xyzac-manual-jog");
const home = jogCase.send("HOME", "home-all");
assert.equal(home.payload.motion_authority, "wasm");
assert.equal(home.payload.wasm_home_limit.state.homed, true);
assert.equal(home.payload.wasm_home_limit.state.joint_count, 5);
const axes = ["x", "y", "z", "a", "c"];
const jogRows = [];
for (const axis of axes) {
const axisCase = axis === "x" ? jogCase : setup(`xyzac-manual-jog-${axis}`);
if (axis !== "x") assert.equal(axisCase.send("HOME", `home-${axis}`).payload.wasm_home_limit.state.homed, true);
const start = axisCase.session.wasmMotion.read().state.position[axis] ?? 0;
const started = axisCase.send("JOG_START", `jog-${axis}`, { axis, direction: 1, speed: 1, increment: axis === "a" || axis === "c" ? 2 : 1 });
assert.equal(started.kind, "COMMAND_RESULT", axis);
assert.equal(started.payload.motion_authority, "wasm");
const stepped = axisCase.send("SIM_STEP", `jog-step-${axis}`, { cycles: 1 });
assert.equal(stepped.payload.motion_authority, "wasm");
const end = axisCase.session.wasmMotion.read().state.position[axis] ?? axisCase.session.wasmMotion.read().state.position.x;
assert.notEqual(end, start, axis);
assert.equal(axisCase.send("JOG_STOP", `jog-stop-${axis}`).payload.motion_authority, "wasm");
jogRows.push({ axis, start, end });
}
const outOfRange = jogCase.send("JOG_START", "jog-limit", { axis: "x", direction: 1, speed: 1, increment: 10000 });
assert.equal(outOfRange.kind, "ERROR");
assert.equal(outOfRange.payload.message_key, "motion_limit_range");
const nonFinite = jogCase.send("JOG_START", "jog-nonfinite", { axis: "a", direction: 1, speed: "not-a-number" });
assert.equal(nonFinite.kind, "ERROR");
assert.equal(nonFinite.payload.message_key, "motion_jog_nonfinite");
const ferror = jogCase.send("FOLLOWING_ERROR", "ferror", { value: 1 });
assert.equal(ferror.kind, "ERROR");
assert.equal(ferror.payload.code, "motion_following_error");
const mdiCase = setup("xyzac-manual-mdi");
const mdi = mdiCase.send("MDI_EXECUTE", "mdi-xyzac", { block: "G21 G90 G1 X10 Y5 Z180 A30 C45 F100" });
assert.equal(mdi.kind, "COMMAND_RESULT");
assert.equal(mdi.payload.motion_authority, "wasm");
assert.equal(mdi.payload.program.source, "linuxcnc-wasm-sim_program");
assert.equal(mdi.payload.panel_snapshot.kinematics.active_type, 0);
const invalidMdi = mdiCase.send("MDI_EXECUTE", "mdi-invalid", { block: "G999" });
assert.equal(invalidMdi.kind, "ERROR");
const loaded = mdiCase.send("PROGRAM_LOAD", "mdi-program", { source: "G21 G90\nG1 X20 A10 C20 F100\nM2\n", path: "mdi-run.ngc" });
assert.equal(loaded.kind, "COMMAND_RESULT");
mdiCase.send("PROGRAM_RUN", "mdi-run");
const mdiWhileRunning = mdiCase.send("MDI_EXECUTE", "mdi-running", { block: "G0 X1" });
assert.equal(mdiWhileRunning.kind, "ERROR");
assert.equal(mdiWhileRunning.payload.message_key, "mdi_while_program_active");
mdiCase.send("PROGRAM_ABORT", "mdi-abort");
const estop = mdiCase.send("ESTOP", "mdi-estop", { active: true });
assert.equal(estop.kind, "COMMAND_RESULT");
assert.equal(estop.payload.task.state, "ESTOP");
assert.equal(estop.payload.device_io.source, "wasm_io");
mdiCase.send("ESTOP", "mdi-estop-reset", { active: false });
const recovered = mdiCase.send("POWER", "mdi-power-after-estop", { active: true });
assert.equal(recovered.payload.motion_authority, "wasm");
console.log(JSON.stringify({ schema: "xyzac-manual-control-rtcp-06.v1", status: "verified", case: CASE, home: { authority: "wasm_home_limit", joints: 5 }, jog: jogRows, boundary: { out_of_range: outOfRange.payload.code, nonfinite_speed: nonFinite.payload.code, following_error: ferror.payload.code }, mdi: "verified", mdi_running_gate: mdiWhileRunning.payload.message_key, estop_recovery: "verified", state_hash: recovered.payload.panel_snapshot.state_hash }));