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 { SimSession, CONTEXT_ID } from "./sim-session.mjs"; const CASE = "linuxcnc/configs/sim/axis/vismach/3axis-tutorial/3axis-tutorial.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)) }); const session = new SimSession(core, { sessionId: "axis3-tutorial-tool-io" }); const base = { schema_version: 1, context_id: CONTEXT_ID, session_id: session.sessionId }; let seq = 0; const send = (kind, operationId, payload = {}) => session.accept({ ...base, kind, seq: ++seq, operation_id: operationId, payload }); send("HELLO", "hello"); send("SESSION_ATTACH", "attach"); const loaded = send("LOAD_WORKSPACE", "load", { root_path: "/workspace", configuration: toWorkerConfiguration(bundle) }); assert.equal(loaded.payload.configuration.state, "TASK_READY"); const spindleOn = send("SPINDLE_COMMAND", "spindle-on", { spindle: 0, rpm: 600, enabled: true }); assert.equal(spindleOn.payload.status, "verified"); const spindleStep = send("IO_STEP", "spindle-step", { ticks: 10 }); assert.equal(spindleStep.payload.status, "verified"); assert.equal(spindleStep.payload.state.spindles[0].at_speed, true); assert.equal(send("SPINDLE_COMMAND", "spindle-off", { spindle: 0, rpm: 0, enabled: false }).payload.status, "verified"); assert.equal(send("IO_STEP", "spindle-stop", { ticks: 10 }).payload.status, "verified"); assert.equal(send("TOOL_PREPARE", "prepare", { tool: 1, pocket: 1 }).payload.status, "verified"); assert.equal(send("TOOL_PREPARED", "prepared", { prepared: true }).payload.status, "verified"); assert.equal(send("TOOL_CHANGE", "change").payload.status, "verified"); const changed = send("TOOL_CHANGED", "changed", { changed: true }); assert.equal(changed.payload.status, "verified"); assert.equal(changed.payload.state.tool.current, 1); const busyChange = send("TOOL_CHANGE", "busy-change"); assert.equal(busyChange.kind, "ERROR"); const coolant = send("COOLANT_COMMAND", "coolant-on", { mist: true, flood: true, lube: false }); assert.equal(coolant.payload.status, "verified"); assert.equal(coolant.payload.device_io.coolant.mist, true); assert.equal(coolant.payload.device_io.coolant.flood, true); assert.equal(send("COOLANT_FAULT", "coolant-fault", { fault: true }).kind, "ERROR"); assert.equal(send("COOLANT_FAULT", "coolant-clear", { fault: false }).payload.status, "verified"); assert.equal(send("COOLANT_COMMAND", "coolant-off", { mist: false, flood: false, lube: false }).payload.status, "verified"); const armed = send("PROBE_CONFIG", "probe-arm", { action: "arm", probe_type: 0 }); assert.equal(armed.payload.status, "verified"); const tripped = send("PROBE_CONFIG", "probe-trip", { action: "update", input: true, position: { x: 1, y: 2, z: -3 } }); assert.equal(tripped.payload.state.probe.state, "tripped"); assert.deepEqual(tripped.payload.state.probe.position, { x: 1, y: 2, z: -3 }); assert.equal(send("PROBE_CONFIG", "probe-disarm", { action: "disarm" }).payload.status, "verified"); const estop = send("ESTOP", "estop", { active: true }); assert.equal(estop.kind, "ERROR"); assert.equal(estop.payload.code, "sim_io_estop"); assert.equal(send("ESTOP", "estop-clear", { active: false }).payload.status, "verified"); assert.equal(send("IO_RECOVER", "recover").payload.status, "verified"); console.log(JSON.stringify({ schema: "axis3-tutorial-tool-io.v1", status: "verified", case: CASE, tool: { current: changed.payload.state.tool.current, changed: true, busy_change_code: busyChange.payload.code }, spindle: { command_rpm: spindleStep.payload.state.spindles[0].command_rpm, speed_rpm: spindleStep.payload.state.spindles[0].speed_rpm, at_speed: spindleStep.payload.state.spindles[0].at_speed }, coolant: { mist: true, flood: true, fault_blocked: true }, probe: { state: tripped.payload.state.probe.state, position: tripped.payload.state.probe.position }, estop: { blocked_code: estop.payload.code, recovered: true }, final_hash: session.workspacePackageState().state_hash }));