Files
cnc_wams/web-rtcp-5axis-sim-plan/tests/node/verify_gmoccapy_xyzac_trt_parity.mjs

189 lines
10 KiB
JavaScript

import assert from "node:assert/strict";
import { readFile } from "node:fs/promises";
import { createMemorySessionStorage } from "../../app/src/runtime/five-axis-session.js";
import { createLinuxCncInterpreterRuntime } from "../../app/src/runtime/linuxcnc-interpreter-runtime.js";
import { createLinuxCncKinematicsRuntime } from "../../app/src/runtime/linuxcnc-kinematics-runtime.js";
import { parseLinuxCncIni } from "../../app/src/runtime/linuxcnc-ini-runtime.js";
import {
selectMachineFileProgram,
stageProfileMachineFiles,
} from "../../app/src/runtime/linuxcnc-machine-file-staging.js";
import { buildRtcpFrame } from "../../app/src/runtime/rtcp-frame.js";
import { createProfileSourceReferenceSummary } from "../../app/src/profiles/source-reference-map.js";
import { getFiveAxisProfile } from "../../app/src/profiles/index.js";
import { createSimulationStore, validateRunPreconditions } from "../../app/src/state/store.js";
const GMOCAPY_TRT_EXAMPLE_SOURCE_PREFIX = "configs/sim/gmoccapy/non_trivial_kinematics/table-rotary-tilting/examples/";
const GMOCAPY_TRT_EXAMPLE_FILES = [
"boat-xyzac.ngc",
"boat-xyzbc.ngc",
"impeller-7bl-xyzac.ngc",
"test-xyzac.ngc",
"test-xyzbc.ngc",
];
const DIRECT_PROGRAM_EXAMPLES = [
"impeller-7bl-xyzac.ngc",
"boat-xyzac.ngc",
"boat-xyzbc.ngc",
];
const NGC_GUI_SUBROUTINE_EXAMPLES = [
{ filename: "test-xyzac.ngc", subroutine: "test-xyzac", rotaryAxis: "A" },
{ filename: "test-xyzbc.ngc", subroutine: "test-xyzbc", rotaryAxis: "B" },
];
const profile = getFiveAxisProfile("gmoccapy-xyzac-trt");
const iniText = await readFile(
new URL("../../../wasm-port/vendor/linuxcnc/configs/sim/gmoccapy/non_trivial_kinematics/table-rotary-tilting/xyzac-trt.ini", import.meta.url),
"utf8",
);
const postguiText = await readFile(
new URL("../../../wasm-port/vendor/linuxcnc/configs/sim/gmoccapy/non_trivial_kinematics/table-rotary-tilting/postgui.hal", import.meta.url),
"utf8",
);
assert.equal(profile.display.display, "gmoccapy");
assert.equal(profile.display.openFile, "./examples/impeller-7bl-xyzac.ngc");
assert.equal(profile.kinematics, "xyzac-trt-kins");
assert.equal(profile.kinematicsModuleId, "xyzac-trt");
assert.equal(profile.kinematicsParameters.fixedTrtDefault, true);
assert.equal(profile.kinematicsParameters.switchkinsTypes[0].webKinsType, "tcp-xyzac");
assert.equal(profile.rtcpProof, true);
assert.equal(profile.machineFileStaging.machineRel, "gmoccapy/non_trivial_kinematics/table-rotary-tilting");
assert.equal(profile.machineFileStaging.demoDirectory, "examples");
assert.equal(profile.hal.halcmd.offsetNets.some((net) => net.target === "gmoccapy.tooloffset-z"), true);
assert.equal(profile.hal.halcmd.toolChange.manualGmoccapyPinsConnected, true);
const sourceSummary = createProfileSourceReferenceSummary(profile.id);
assert.equal(sourceSummary.referenceCount >= 10, true);
assert.equal(sourceSummary.kinds.includes("ini"), true);
assert.equal(sourceSummary.kinds.includes("gcode_demo"), true);
assert.equal(sourceSummary.kinds.includes("gcode_ngcgui_subroutine"), true);
assert.equal(sourceSummary.kinds.includes("remap_subroutine"), true);
assert.equal(sourceSummary.sourceRequiredCount >= 2, true);
for (const filename of GMOCAPY_TRT_EXAMPLE_FILES) {
assert.equal(
sourceSummary.references.some((reference) => reference.path === `${GMOCAPY_TRT_EXAMPLE_SOURCE_PREFIX}${filename}`),
true,
`${filename} source reference`,
);
}
const iniConfig = parseLinuxCncIni(iniText, {
path: profile.iniPath,
profileId: profile.id,
});
assert.equal(iniConfig.validation.ready, true);
assert.equal(iniConfig.machineName, "sim-xyzac-trt");
assert.equal(iniConfig.display.display, "gmoccapy");
assert.equal(iniConfig.traj.coordinates, "XYZAC");
assert.equal(iniConfig.kinematics.name, "xyzac-trt-kins");
assert.equal(iniConfig.kinematicsParameters.sparm, null);
assert.deepEqual(iniConfig.rs274ngc.remaps.map((remap) => remap.code), ["M6", "M61"]);
assert.equal(iniConfig.rs274ngc.subroutinePath, "./examples:../../macros");
assert.equal(iniConfig.hal.postguiHalFiles.includes("postgui.hal"), true);
assert.equal(iniConfig.hal.halcmd.some((line) => line.includes("xyzac-trt-gui")), true);
assert.equal(iniConfig.hal.halcmd.some((line) => line.includes("xyzac-trt-kins.tool-offset")), true);
assert.equal(iniConfig.hal.halcmd.some((line) => line.includes("sets :y-offset 20")), true);
assert.equal(iniConfig.emcmot.servoPeriodNs, 1000000);
assert.equal(iniConfig.task.cycleTimeSeconds, 0.010);
assert.equal(postguiText.includes("gmoccapy.spindle_feedback_bar"), true);
assert.equal(postguiText.includes("gmoccapy.toolchange-change"), true);
assert.equal(postguiText.includes("gmoccapy.tooloffset-z"), true);
const staged = await stageProfileMachineFiles(profile, {
storage: createMemorySessionStorage(),
});
assert.equal(staged.plan.profileId, profile.id);
assert.equal(staged.plan.machineRel, "gmoccapy/non_trivial_kinematics/table-rotary-tilting");
assert.equal(staged.plan.demoDirectory, "examples");
assert.equal(staged.save.files.some((file) => file.sourceRel === profile.iniPath), true);
assert.equal(staged.save.files.some((file) => file.sourceRel === profile.toolTablePath), true);
assert.equal(staged.save.files.some((file) => file.sourceRel.endsWith("macros/change_g43.ngc")), true);
assert.equal(staged.save.files.some((file) => file.sourceRel.endsWith("macros/settool_g43.ngc")), true);
assert.deepEqual(staged.save.gcodeSources.map((source) => source.filename), GMOCAPY_TRT_EXAMPLE_FILES);
assert.equal(staged.save.gcodeSources.every((source) => source.sourceRel.startsWith(GMOCAPY_TRT_EXAMPLE_SOURCE_PREFIX)), true);
assert.equal(staged.save.gcodeSources.every((source) => source.semanticBoundary === "linuxcnc_vendored_5axis_gcode_source_file"), true);
assert.equal(staged.save.gcodeFiles.some((file) => file.filename === "test-xyzac.ngc"), true);
assert.equal(staged.save.gcodeFiles.some((file) => file.filename === "test-xyzbc.ngc"), true);
const selectedPlan = selectMachineFileProgram(
staged.plan,
staged.save,
"configs/sim/gmoccapy/non_trivial_kinematics/table-rotary-tilting/examples/impeller-7bl-xyzac.ngc",
);
assert.equal(selectedPlan.selectedProgramFilename, "impeller-7bl-xyzac.ngc");
assert.equal(selectedPlan.wasmProgramPath.endsWith("/examples/impeller-7bl-xyzac.ngc"), true);
const runtime = await createLinuxCncInterpreterRuntime();
for (const filename of DIRECT_PROGRAM_EXAMPLES) {
const source = staged.save.files.find((file) => file.sourceRel.endsWith(`/examples/${filename}`));
assert.ok(source, `${filename} staged`);
const execution = runtime.runProgram(source.text);
assert.equal(execution.sourceMode, "linuxcnc-interpreter-wasm", `${filename} source mode`);
assert.equal(execution.summary.ready, true, `${filename} ready`);
assert.equal(execution.summary.motionEventCount > 0, true, `${filename} motion`);
assert.equal(execution.plannerTiming.samples.length > 0, true, `${filename} planner samples`);
}
for (const { filename, subroutine, rotaryAxis } of NGC_GUI_SUBROUTINE_EXAMPLES) {
const source = staged.save.files.find((file) => file.sourceRel.endsWith(`/examples/${filename}`));
assert.ok(source, `${filename} staged`);
assert.equal(source.text.includes(`o<${subroutine}> sub`), true, `${filename} subroutine open`);
assert.equal(source.text.includes(`o<${subroutine}> endsub`), true, `${filename} subroutine close`);
assert.equal(source.text.includes("T#<tool1> M6"), true, `${filename} tool-change semantics`);
assert.equal(source.text.includes("G43 H#<tool2> Z0"), true, `${filename} tool-offset semantics`);
assert.equal(new RegExp(`G00 ${rotaryAxis}#<${rotaryAxis.toLowerCase()}_angle> C#<c_angle>`).test(source.text), true, `${filename} rotary-axis semantics`);
const execution = runtime.runProgram(source.text);
assert.equal(execution.sourceMode, "linuxcnc-interpreter-wasm", `${filename} source mode`);
assert.equal(execution.summary.ready, false, `${filename} ngcgui subroutine is not a standalone main program`);
assert.equal(execution.summary.motionEventCount, 0, `${filename} direct subroutine execution has no motion`);
}
const kinematics = await createLinuxCncKinematicsRuntime({ moduleId: "xyzac-trt", switchkinsType: 0 });
const frame = buildRtcpFrame({
axisPose: { x: 16.339, y: -25.409, z: 33.353, a: -71.841, c: -35.93 },
activeLine: 5,
kinsType: "tcp-xyzac",
rtcpEnabled: true,
profile,
linuxCncKinematicsResult: kinematics.frameForJoints([16.339, -25.409, 33.353, -71.841, -35.93]),
});
assert.equal(frame.sourceMode, "source-derived-kinematics-wasm");
assert.equal(frame.readiness.linuxCncKinematicsReady, true);
assert.equal(frame.rtcpState, "on");
assert.equal(frame.profileId, "gmoccapy-xyzac-trt");
const store = createSimulationStore();
store.dispatch({ type: "SET_PROFILE", profileId: profile.id });
store.dispatch({ type: "ATTACH_INI_CONFIG", profileId: profile.id, iniConfig });
store.dispatch({ type: "ATTACH_KINEMATICS_RUNTIME", runtime: kinematics });
await store.refreshKinematicsFrame();
store.dispatch({ type: "ATTACH_INTERPRETER_RUNTIME", runtime });
await store.stageMachineFiles({ storage: createMemorySessionStorage() });
store.dispatch({
type: "LOAD_LINUXCNC_GCODE_SOURCE",
sourceRel: "configs/sim/gmoccapy/non_trivial_kinematics/table-rotary-tilting/examples/impeller-7bl-xyzac.ngc",
});
await new Promise((resolve) => setTimeout(resolve, 0));
const loadedState = store.getState();
assert.equal(loadedState.machineProfile, profile.id);
assert.equal(loadedState.display?.display, undefined);
assert.equal(loadedState.kinsType, "tcp-xyzac");
assert.equal(loadedState.rtcpState, "on");
assert.equal(loadedState.machineProject.gcodeDirectory.endsWith("/configs/sim/gmoccapy/non_trivial_kinematics/table-rotary-tilting/examples"), true);
assert.equal(loadedState.machineProject.selectedProgram.filename, "impeller-7bl-xyzac.ngc");
assert.equal(loadedState.programValidation.sourceGuard, "linuxcnc_vendored_5axis_gcode_source_file");
assert.equal(loadedState.programExecution?.summary?.motionEventCount > 0, true);
assert.equal(loadedState.toolDbReadiness.toolCount, 10);
const preconditions = validateRunPreconditions(loadedState, {
requireTaskHalRuntime: false,
requireTaskHalSession: false,
});
assert.equal(preconditions.ok, true);
assert.equal(preconditions.profileId, "gmoccapy-xyzac-trt");
assert.equal(preconditions.selectedGcodeSourceRel.endsWith("/examples/impeller-7bl-xyzac.ngc"), true);
console.log("gmoccapy_xyzac_trt_parity_smoke=ok");