79 lines
5.0 KiB
JavaScript
79 lines
5.0 KiB
JavaScript
import assert from "node:assert/strict";
|
|
import { readFile } from "node:fs/promises";
|
|
import createModule from "../../build-wasm/linuxcnc-sim-core.js";
|
|
import { compareEndpoints, createEndpoint, endpointHash } from "./endpoint-replay.mjs";
|
|
import { SimSession, CONTEXT_ID } from "./sim-session.mjs";
|
|
|
|
const wasmBinary = await readFile(new URL("../../build-wasm/linuxcnc-sim-core.wasm", import.meta.url));
|
|
const DELTA_SAMPLE = [300, 300, 300];
|
|
|
|
async function runDelta(id, fast) {
|
|
const core = await createModule({ wasmBinary });
|
|
const session = new SimSession(core, { sessionId: id });
|
|
const base = { schema_version: 1, context_id: CONTEXT_ID, session_id: id };
|
|
let seq = 0;
|
|
const send = (kind, operation_id, payload = {}) => {
|
|
seq += 1;
|
|
const response = session.accept({ ...base, kind, seq, operation_id, payload });
|
|
assert.notEqual(response.kind, "ERROR", `${id}:${kind}:${response.payload?.code ?? "error"}`);
|
|
return response;
|
|
};
|
|
send("HELLO", "hello"); send("SESSION_ATTACH", "attach");
|
|
send("LOAD_WORKSPACE", "workspace", { root_path: "/workspace", kinematics: "lineardeltakins" });
|
|
send("PROGRAM_LOAD", "program", { source: "G0 X0 Y0 Z64.636584194\nM2\n", path: "lineardelta.ngc" });
|
|
send("PROGRAM_RUN", "run");
|
|
if (fast) send("SIM_STEP", "fast", { cycles: 8 });
|
|
else for (let index = 0; index < 8; index += 1) send("SIM_STEP", `step-${index}`, { cycles: 1 });
|
|
const endpoint = createEndpoint({ session });
|
|
assert.equal(endpoint.authoritative.kinematics.type, "lineardelta");
|
|
endpoint.authoritative.kinematics.joints.forEach((value, index) => assert.ok(Math.abs(value - DELTA_SAMPLE[index]) < 1e-9));
|
|
const checkpoint = session.createCheckpoint();
|
|
send("SIM_STEP", "post-checkpoint", { cycles: 1 });
|
|
const continuous = createEndpoint({ session });
|
|
assert.equal(session.restoreCheckpoint(checkpoint, session.timeline.export(), (operation) => operation).status, "recovered");
|
|
const restored = createEndpoint({ session });
|
|
const recovery = compareEndpoints(continuous, restored);
|
|
assert.equal(recovery.equal, true, JSON.stringify(recovery));
|
|
return { endpoint, recovery, checkpoint };
|
|
}
|
|
|
|
const oneX = await runDelta("authoritative-lineardelta-1x", false);
|
|
const fast = await runDelta("authoritative-lineardelta-fast", true);
|
|
const mode = compareEndpoints(oneX.endpoint, fast.endpoint);
|
|
assert.equal(mode.equal, true, JSON.stringify(mode));
|
|
|
|
const unsupportedCore = await createModule({ wasmBinary });
|
|
const unsupported = new SimSession(unsupportedCore, { sessionId: "authoritative-lineardelta-unsupported" });
|
|
const base = { schema_version: 1, context_id: CONTEXT_ID, session_id: "authoritative-lineardelta-unsupported" };
|
|
unsupported.accept({ ...base, kind: "HELLO", seq: 1, operation_id: "hello" });
|
|
unsupported.accept({ ...base, kind: "SESSION_ATTACH", seq: 2, operation_id: "attach" });
|
|
const unsupportedResult = unsupported.accept({ ...base, kind: "LOAD_WORKSPACE", seq: 3, operation_id: "unsupported", payload: { root_path: "/workspace", kinematics: "xyzac-trt" } });
|
|
assert.equal(unsupportedResult.kind, "ERROR");
|
|
assert.equal(unsupportedResult.payload.code, "authoritative_kinematics_unsupported");
|
|
|
|
const rangeCore = await createModule({ wasmBinary });
|
|
const range = new SimSession(rangeCore, { sessionId: "authoritative-lineardelta-range" });
|
|
const rangeBase = { schema_version: 1, context_id: CONTEXT_ID, session_id: "authoritative-lineardelta-range" };
|
|
range.accept({ ...rangeBase, kind: "HELLO", seq: 1, operation_id: "hello" });
|
|
range.accept({ ...rangeBase, kind: "SESSION_ATTACH", seq: 2, operation_id: "attach" });
|
|
range.accept({ ...rangeBase, kind: "LOAD_WORKSPACE", seq: 3, operation_id: "load", payload: { root_path: "/workspace", kinematics: "lineardelta" } });
|
|
range.accept({ ...rangeBase, kind: "PROGRAM_LOAD", seq: 4, operation_id: "program", payload: { source: "G0 X1000 Y0 Z0\nM2\n", path: "range.ngc" } });
|
|
range.accept({ ...rangeBase, kind: "PROGRAM_RUN", seq: 5, operation_id: "run" });
|
|
const rangeStep = range.accept({ ...rangeBase, kind: "SIM_STEP", seq: 6, operation_id: "step", payload: { cycles: 8 } });
|
|
assert.equal(rangeStep.kind, "ERROR");
|
|
assert.equal(rangeStep.payload.code, "scheduler");
|
|
assert.equal(rangeStep.payload.message_key, "authoritative_kinematics_range");
|
|
|
|
console.log(JSON.stringify({
|
|
schema: "authoritative-kinematics-s7-03-sample.v1",
|
|
status: "verified",
|
|
context_id: CONTEXT_ID,
|
|
supported: { type: "lineardelta", source_family: "lineardeltakins", pose: [0, 0, 64.636584194], joints: oneX.endpoint.authoritative.kinematics.joints, endpoint_hash: endpointHash(oneX.endpoint) },
|
|
parity: { mode, recovery: oneX.recovery },
|
|
checkpoint_hash: oneX.checkpoint.checkpoint_hash,
|
|
unsupported: { type: "xyzac-trt", code: unsupportedResult.payload.code },
|
|
range: { code: rangeStep.payload.code, message_key: rangeStep.payload.message_key },
|
|
geometry: { radius: 130.25, rod_length: 269, tower_layout: "120-degree equilateral" },
|
|
boundaries: ["official kinematics oracle remains SOURCE_BLOCKED", "TRT/robot/Hexapod/Pentapod/switch/user remain queued", "missing ldelta HAL resources are retained as configuration gaps"],
|
|
}));
|