168 lines
6.5 KiB
JavaScript
168 lines
6.5 KiB
JavaScript
import { access, mkdir, readFile, writeFile } from "node:fs/promises";
|
|
import { dirname, resolve } from "node:path";
|
|
import { fileURLToPath } from "node:url";
|
|
|
|
import { createMemorySessionStorage } from "../app/src/runtime/five-axis-session.js";
|
|
import { parseLinuxCncIni } from "../app/src/runtime/linuxcnc-ini-runtime.js";
|
|
import {
|
|
selectMachineFileProgram,
|
|
stageProfileMachineFiles,
|
|
} from "../app/src/runtime/linuxcnc-machine-file-staging.js";
|
|
import { createSimulationStore } from "../app/src/state/store.js";
|
|
import { getFiveAxisProfile } from "../app/src/profiles/index.js";
|
|
|
|
const repoRoot = resolve(dirname(fileURLToPath(import.meta.url)), "../..");
|
|
const projectRoot = resolve(repoRoot, "web-rtcp-5axis-xyzbc-trt-sim-plan");
|
|
const outputPath = process.argv[2]
|
|
|| resolve(projectRoot, "working/evidence/web-xyzbc-trt-evidence.json");
|
|
const sourceRel = "configs/sim/axis/vismach/5axis/table-rotary-tilting/demos/xyzbc_switchkins.ngc";
|
|
|
|
const profile = getFiveAxisProfile("xyzbc-trt");
|
|
const wasmArtifacts = await inspectWasmArtifacts();
|
|
const iniText = await readFile(
|
|
resolve(repoRoot, "wasm-port/vendor/linuxcnc", profile.iniPath),
|
|
"utf8",
|
|
);
|
|
const ini = parseLinuxCncIni(iniText, {
|
|
path: profile.iniPath,
|
|
profileId: profile.id,
|
|
});
|
|
|
|
const storage = createMemorySessionStorage();
|
|
const staged = await stageProfileMachineFiles(profile, { storage });
|
|
const selectedPlan = selectMachineFileProgram(staged.plan, staged.save, sourceRel);
|
|
const store = createSimulationStore();
|
|
const storeStage = await store.stageMachineFiles({ storage: createMemorySessionStorage() });
|
|
store.dispatch({ type: "LOAD_LINUXCNC_GCODE_SOURCE", sourceRel });
|
|
const state = store.getState();
|
|
|
|
const evidence = {
|
|
apiName: "xyzbc-trt-web-opfs-wasm-evidence",
|
|
status: wasmArtifacts.ready ? "ready-for-wasm-runtime" : "blocked",
|
|
collectedAt: new Date().toISOString(),
|
|
profile: {
|
|
id: profile.id,
|
|
machineName: profile.machineName,
|
|
iniPath: profile.iniPath,
|
|
pyvcpXmlPath: profile.pyvcpXmlPath,
|
|
toolTablePath: profile.toolTablePath,
|
|
coordinates: profile.coordinates,
|
|
kinematics: profile.kinematics,
|
|
kinematicsModuleId: profile.kinematicsModuleId,
|
|
defaultProgramFilename: profile.machineFileStaging?.defaultProgramFilename,
|
|
switchkinsTypes: profile.kinematicsParameters?.switchkinsTypes,
|
|
halPins: profile.halPins,
|
|
},
|
|
ini: {
|
|
ready: ini.validation.ready,
|
|
machineName: ini.machineName,
|
|
coordinates: ini.traj.coordinates,
|
|
kinematicsName: ini.kinematics.name,
|
|
kinematicsModuleId: ini.kinematicsModuleId,
|
|
remaps: ini.rs274ngc.remaps,
|
|
haluiMdiCommands: ini.halui.mdiCommands,
|
|
toolTable: ini.emcio.toolTable,
|
|
parameterFile: ini.rs274ngc.parameterFile,
|
|
jointConfig: ini.jointConfig,
|
|
},
|
|
opfsStaging: {
|
|
storageMode: staged.save.storageMode,
|
|
opfsRoot: staged.save.opfsRoot,
|
|
fileCount: staged.save.fileCount,
|
|
summary: staged.save.summary,
|
|
files: staged.save.files.map((file) => ({
|
|
sourceRel: file.sourceRel,
|
|
opfsPath: file.opfsPath,
|
|
wasmPath: file.wasmPath,
|
|
kind: file.kind,
|
|
bytes: file.bytes,
|
|
executable: file.executable,
|
|
})),
|
|
gcodeSources: staged.save.gcodeSources,
|
|
selectedProgram: {
|
|
sourceRel: selectedPlan.selectedProgramSourceRel,
|
|
filename: selectedPlan.selectedProgramFilename,
|
|
wasmProgramPath: selectedPlan.wasmProgramPath,
|
|
},
|
|
},
|
|
store: {
|
|
machineProfile: state.machineProfile,
|
|
sessionName: state.sessionName,
|
|
machineProjectRoot: state.machineProject?.projectRoot || storeStage.save.opfsRoot,
|
|
activeProgram: state.activeProgram,
|
|
programSource: state.programSource,
|
|
programLineCount: state.programLines.length,
|
|
selectedGcodeSourceRel: state.machineFileStaging.selectedGcodeSourceRel,
|
|
},
|
|
wasm: wasmArtifacts,
|
|
coverage: {
|
|
profileDefaultXyzbc: profile.id === "xyzbc-trt",
|
|
iniReady: ini.validation.ready,
|
|
opfsStaged: staged.save.status === "saved" && staged.save.fileCount > 0,
|
|
pyvcpXmlStaged: staged.save.files.some((file) => file.sourceRel.endsWith("xyzbc-trt.xml")),
|
|
remapsStaged: ["428remap.ngc", "429remap.ngc", "430remap.ngc"].every((name) => (
|
|
staged.save.files.some((file) => file.sourceRel.endsWith(`/remap_subs/${name}`))
|
|
)),
|
|
toolTableStaged: staged.save.files.some((file) => file.sourceRel.endsWith("xyzbc-trt.tbl")),
|
|
parameterFileStaged: staged.save.files.some((file) => file.sourceRel.endsWith("xyzbc.var")),
|
|
defaultProgramStaged: staged.save.gcodeSources.some((source) => source.filename === "xyzbc_switchkins.ngc"),
|
|
wasmArtifactsReady: wasmArtifacts.ready,
|
|
},
|
|
blockers: [
|
|
...(wasmArtifacts.ready ? [] : [{
|
|
id: "missing-wasm-artifacts",
|
|
detail: "wasm-port/build/wasm does not contain all required kinematics/core/tp/task-hal artifacts.",
|
|
required: wasmArtifacts.required,
|
|
missing: wasmArtifacts.missing,
|
|
}]),
|
|
...(staged.save.files.some((file) => file.sourceRel.endsWith("xyzbc.var")) ? [] : [{
|
|
id: "missing-parameter-file-staging",
|
|
detail: "xyzbc.var is referenced by INI but absent from wasm-port/vendor manifest in this workspace.",
|
|
}]),
|
|
],
|
|
semanticBoundary: "web_opfs_wasm_runtime_readiness_for_linuxcnc_xyzbc_trt",
|
|
};
|
|
|
|
await mkdir(dirname(outputPath), { recursive: true });
|
|
await writeFile(outputPath, JSON.stringify(evidence, null, 2) + "\n", "utf8");
|
|
console.log(`web_xyzbc_trt_evidence=${outputPath}`);
|
|
|
|
async function inspectWasmArtifacts() {
|
|
const required = [
|
|
"wasm-port/build/wasm/kinematics/linuxcnc_xyzbc_trt_kinematics.js",
|
|
"wasm-port/build/wasm/kinematics/linuxcnc_xyzbc_trt_kinematics.wasm",
|
|
"wasm-port/build/wasm/core/linuxcnc_interp.js",
|
|
"wasm-port/build/wasm/core/linuxcnc_interp.wasm",
|
|
"wasm-port/build/wasm/tp/linuxcnc_tp.js",
|
|
"wasm-port/build/wasm/tp/linuxcnc_tp.wasm",
|
|
"wasm-port/build/wasm/task-hal/linuxcnc_task_hal.js",
|
|
"wasm-port/build/wasm/task-hal/linuxcnc_task_hal.wasm",
|
|
];
|
|
const files = [];
|
|
const missing = [];
|
|
for (const rel of required) {
|
|
const abs = resolve(repoRoot, rel);
|
|
try {
|
|
await access(abs);
|
|
files.push(rel);
|
|
} catch {
|
|
missing.push(rel);
|
|
}
|
|
}
|
|
return {
|
|
required,
|
|
files,
|
|
missing,
|
|
ready: missing.length === 0,
|
|
emscriptenAvailable: Boolean(await commandExists("emcc")),
|
|
};
|
|
}
|
|
|
|
async function commandExists(command) {
|
|
const { spawn } = await import("node:child_process");
|
|
return new Promise((resolveCommand) => {
|
|
const child = spawn("bash", ["-lc", `command -v ${command}`], { stdio: "ignore" });
|
|
child.on("exit", (code) => resolveCommand(code === 0));
|
|
});
|
|
}
|