Expand WASM sim-config staging coverage

This commit is contained in:
2026-06-09 07:32:15 +08:00
parent 2658ee3b72
commit 5116b9894d
26 changed files with 5989 additions and 141 deletions

View File

@@ -446,6 +446,18 @@ for (const fixtureName of INTERP_FILE_FIXTURES) {
verifyExpectedOutput(fixtureName, interp.runFile(programPath), expectedEvents);
}
verifyExpectedOutput(
"minimal_linear_run_steps",
interp.runFile("/work/minimal_linear.ngc"),
[
"run_step phase=read step=1 rc=0 line=1",
"run_step phase=execute step=1 rc=0 line=1 x=1 y=2 z=0",
"statement_uri=G0%20X1.0%20Y2.0%20%28Comment%29",
"run_step phase=execute step=2 rc=0 line=2 x=3 y=4 z=0",
"statement_uri=G1%20X3.0%20Y4.0%20F120.0",
].join("\n"),
);
const namedParamFilePath = `/work/${INTERP_INI_FIXTURE}.ngc`;
interp.writeTextFile(namedParamFilePath, namedParamProgramText);
verifyExpectedOutput(

View File

@@ -47,6 +47,54 @@ function runVendorNcFile(filename) {
return interp.runFile(wasmPath);
}
function runVendorNcFileWithToolTable(filename) {
const wasmDir = "/work/nc-files-context";
const wasmPath = `${wasmDir}/${filename}`;
const iniPath = `${wasmDir}/nc_files_context.ini`;
interp.writeTextFile(wasmPath, readFileSync(resolve(ncFilesDir, filename), "utf8"));
interp.writeTextFile(
`${wasmDir}/tool.tbl`,
"T1 P1 D10.000000 Z+0.000000 ; nc_files representative context tool\n",
);
interp.writeTextFile(
iniPath,
[
"[RS274NGC]",
"SUBROUTINE_PATH = .",
"",
"[TRAJ]",
"COORDINATES = X Y Z A B C U V W",
"",
"[EMCIO]",
"TOOL_TABLE = tool.tbl",
"",
].join("\n"),
);
return interp.runFileWithIni(wasmPath, iniPath);
}
verifyExpectedOutput(
"nc_files_3d_chips_context_wasm",
runVendorNcFileWithToolTable("3D_Chips.ngc"),
[
"file_open=0",
"file_read_count=4706",
"file_execute_count=4706",
"file_saw_error=0",
"run_step phase=execute step=18 rc=2 line=18",
"statement_uri=N50T%23%3Ctoolno%3EM6",
"run_step phase=execute step=19 rc=0 line=19",
"statement_uri=N60M8",
"canon_event=CHANGE_TOOL",
"canon_event=START_SPINDLE_CLOCKWISE spindle=0",
"canon_event=STRAIGHT_TRAVERSE line=21 x=0 y=0 z=10",
"canon_event=STRAIGHT_FEED line=23 x=53 y=-56.128 z=-25.372",
"canon_event=PROGRAM_END",
"absent=file_error_text=",
"absent=Requested tool 1 not found",
].join("\n"),
);
verifyExpectedOutput(
"nc_files_arcspiral_wasm",
runVendorNcFile("arcspiral.ngc"),

View File

@@ -3,7 +3,10 @@ import { fileURLToPath } from "node:url";
import { dirname, resolve } from "node:path";
import assert from "node:assert/strict";
import { createLinuxCncInterpSdk } from "../../../runtime/sdk/src/index.js";
import {
createLinuxCncInterpSdk,
planSimConfigStaging,
} from "../../../runtime/sdk/src/index.js";
function verifyExpectedOutput(fixtureName, output, expectedText) {
const expectedLines = expectedText.split("\n").filter(Boolean);
@@ -32,6 +35,7 @@ const __dirname = dirname(__filename);
const rootDir = resolve(__dirname, "../../..");
const wasmPath = resolve(rootDir, "build/wasm/core/linuxcnc_interp.wasm");
const vendorRoot = resolve(rootDir, "vendor/linuxcnc");
const manifestText = readFileSync(resolve(rootDir, "tools/source-manifest.txt"), "utf8");
const interp = await createLinuxCncInterpSdk({
wasmBinary: readFileSync(wasmPath),
@@ -41,35 +45,72 @@ const interp = await createLinuxCncInterpSdk({
},
});
function vendorFile(sourceRel, wasmPath) {
const sourcePath = resolve(vendorRoot, sourceRel);
const syntheticPlan = planSimConfigStaging({
manifestText: [
"configs/sim/example/test.ini",
"configs/sim/example/test.ngc",
"configs/sim/example/tool.tbl",
"configs/sim/example/linuxcnc.var",
"configs/sim/example/subs/helper.ngc",
"configs/sim/example/M123",
].join("\n"),
machineRel: "example",
iniFile: "test.ini",
iniText: [
"[DISPLAY]",
"OPEN_FILE = test.ngc",
"[RS274NGC]",
"PARAMETER_FILE = linuxcnc.var",
"SUBROUTINE_PATH = subs",
"USER_M_PATH = .",
"[EMCIO]",
"TOOL_TABLE = tool.tbl",
].join("\n"),
});
assert.deepEqual(
syntheticPlan.files.map((file) => [file.sourceRel, file.executable]).sort(),
[
["configs/sim/example/M123", true],
["configs/sim/example/linuxcnc.var", false],
["configs/sim/example/subs/helper.ngc", false],
["configs/sim/example/test.ini", false],
["configs/sim/example/test.ngc", false],
["configs/sim/example/tool.tbl", false],
],
"synthetic sim-config staging plan",
);
function simMachine(machineRel, iniFile, programFile = null) {
const iniText = readFileSync(
resolve(vendorRoot, `configs/sim/${machineRel}/${iniFile}`),
"utf8",
);
const plan = planSimConfigStaging({
manifestText,
machineRel,
iniFile,
iniText,
programFile,
wasmDir: `/work/sim/${machineRel}`,
});
return {
path: wasmPath,
text: readFileSync(sourcePath, "utf8"),
executable: (statSync(sourcePath).mode & 0o111) !== 0,
...plan,
files: plan.files.map((file) => ({
path: file.path,
text: readFileSync(resolve(vendorRoot, file.sourceRel), "utf8"),
executable:
file.executable || (statSync(resolve(vendorRoot, file.sourceRel)).mode & 0o111) !== 0,
})),
};
}
function simMachine(machineRel, files) {
const wasmDir = `/work/sim/${machineRel}`;
return {
wasmDir,
files: files.map((file) =>
vendorFile(`configs/sim/${machineRel}/${file}`, `${wasmDir}/${file}`),
),
};
}
const foam = simMachine("axis/foam", [
"axis_foam.ini",
"foam.ngc",
]);
const foam = simMachine("axis/foam", "axis_foam.ini", "foam.ngc");
verifyExpectedOutput(
"sim_axis_foam_uv_wasm",
interp.runSimConfigProgram({
files: foam.files,
programPath: `${foam.wasmDir}/foam.ngc`,
iniPath: `${foam.wasmDir}/axis_foam.ini`,
programPath: foam.programPath,
iniPath: foam.iniPath,
}),
[
"file_open=0",
@@ -80,20 +121,17 @@ verifyExpectedOutput(
].join("\n"),
);
const bridgeMill = simMachine("axis/vismach/5axis/bridgemill", [
const bridgeMill = simMachine(
"axis/vismach/5axis/bridgemill",
"5axis.ini",
"5axis.tbl",
"5axisgui.ngc",
"remap_subs/428remap.ngc",
"remap_subs/429remap.ngc",
"remap_subs/430remap.ngc",
]);
);
verifyExpectedOutput(
"sim_axis_bridgemill_w_wasm",
interp.runSimConfigProgram({
files: bridgeMill.files,
programPath: `${bridgeMill.wasmDir}/5axisgui.ngc`,
iniPath: `${bridgeMill.wasmDir}/5axis.ini`,
programPath: bridgeMill.programPath,
iniPath: bridgeMill.iniPath,
executionMode: "fiveAxisRemap",
}),
[
@@ -115,17 +153,13 @@ verifyExpectedOutput(
].join("\n"),
);
const geometry = simMachine("axis/geometry", [
"M110",
"xyzc.ini",
"xyzc.ngc",
]);
const geometry = simMachine("axis/geometry", "xyzc.ini", "xyzc.ngc");
verifyExpectedOutput(
"sim_axis_geometry_xyzc_user_m110_wasm",
interp.runSimConfigProgram({
files: geometry.files,
programPath: `${geometry.wasmDir}/xyzc.ngc`,
iniPath: `${geometry.wasmDir}/xyzc.ini`,
programPath: geometry.programPath,
iniPath: geometry.iniPath,
}),
[
"file_open=0",
@@ -137,25 +171,66 @@ verifyExpectedOutput(
].join("\n"),
);
const externalOffsets = simMachine("axis/external_offsets", [
"M111",
"dyn_demo.ngc",
"dynamic_offsets.ini",
]);
verifyExpectedOutput(
"sim_axis_external_offsets_user_m111_wasm",
interp.runSimConfigProgram({
files: externalOffsets.files,
programPath: `${externalOffsets.wasmDir}/dyn_demo.ngc`,
iniPath: `${externalOffsets.wasmDir}/dynamic_offsets.ini`,
}),
[
"file_open=0",
"file_saw_error=0",
"canon_event=USER_M_COMMAND code=M111",
"canon_event=PROGRAM_END",
"absent=Unknown m code used: M111",
].join("\n"),
);
for (const externalOffsetCase of [
{
name: "dyn_demo",
program: "dyn_demo.ngc",
ini: "dynamic_offsets.ini",
readCount: 833,
firstTraverse: "canon_event=STRAIGHT_TRAVERSE line=21 x=0 y=0 z=0",
firstFeed: "canon_event=STRAIGHT_FEED line=26 x=9 y=0 z=1.5",
},
{
name: "eoffsets",
program: "eoffsets.ngc",
ini: "eoffsets.ini",
readCount: 35,
firstTraverse: "canon_event=STRAIGHT_TRAVERSE line=24 x=0 y=0 z=0",
firstFeed: "canon_event=STRAIGHT_FEED line=27 x=2.25 y=2.64 z=0",
},
{
name: "jwp_z",
program: "jwp_z.ngc",
ini: "jwp_z.ini",
readCount: 35,
firstTraverse: "canon_event=STRAIGHT_TRAVERSE line=17 x=0 y=0 z=0.5",
firstFeed: "canon_event=STRAIGHT_FEED line=24 x=2.5 y=3.3 z=0",
},
{
name: "opa_demo",
program: "opa_demo.ngc",
ini: "opa.ini",
readCount: 58,
firstTraverse: "canon_event=STRAIGHT_TRAVERSE line=13 x=1 y=0 z=0",
firstFeed: "canon_event=STRAIGHT_FEED line=35 x=1 y=0 z=0",
},
]) {
const externalOffsets = simMachine(
"axis/external_offsets",
externalOffsetCase.ini,
externalOffsetCase.program,
);
verifyExpectedOutput(
`sim_axis_external_offsets_${externalOffsetCase.name}_user_m111_wasm`,
interp.runSimConfigProgram({
files: externalOffsets.files,
programPath: externalOffsets.programPath,
iniPath: externalOffsets.iniPath,
}),
[
"file_open=0",
`file_read_count=${externalOffsetCase.readCount}`,
`file_execute_count=${externalOffsetCase.readCount}`,
"file_saw_error=0",
"canon_event=USER_M_COMMAND code=M111",
externalOffsetCase.firstTraverse,
externalOffsetCase.firstFeed,
"canon_event=PROGRAM_END",
"absent=Unknown m code used: M111",
"absent=Bad character",
"absent=Cannot use axis values",
].join("\n"),
);
}
console.log("sim_configs_wasm_node_smoke=ok");