import assert from "node:assert/strict"; import { readFileSync } from "node:fs"; import { dirname, resolve } from "node:path"; import { fileURLToPath } from "node:url"; import { createLinuxCncInterpSdk, createLinuxCncKinematicsSdk, planSimConfigStaging, } from "../../../wasm-port/runtime/sdk/src/index.js"; import { parseLinuxCncIni } from "../../app/src/runtime/linuxcnc-ini-runtime.js"; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); const workspaceRoot = resolve(__dirname, "../../.."); const wasmPortRoot = resolve(workspaceRoot, "wasm-port"); const vendorRoot = resolve(wasmPortRoot, "vendor/linuxcnc"); const trtConfigRel = "configs/sim/axis/vismach/5axis/table-rotary-tilting"; function near(actual, expected, tolerance = 1e-7) { return Math.abs(actual - expected) <= tolerance; } function assertPoseComponent(pose, key, expected, label) { assert.equal(near(Number(pose[key] ?? 0), expected), true, `${label}.${key}: ${pose[key]} != ${expected}`); } async function verifyTrtKinematics(moduleId, joints, expectedAxis) { const wasmFile = `linuxcnc_${moduleId.replaceAll("-", "_")}_kinematics.wasm`; const kins = await createLinuxCncKinematicsSdk({ moduleId, moduleOptions: { wasmBinary: readFileSync(resolve(wasmPortRoot, "build/wasm/kinematics", wasmFile)), print() {}, printErr() {}, }, }); assert.equal(kins.apiName, "linuxcnc-kinematics-wasm-sdk"); assert.equal(kins.switchable(), 1); assert.equal(kins.switchKinematics(0), 0); const forward = kins.forward(joints); assert.equal(forward.rc, 0, `${moduleId} forward`); const inverse = kins.inverse(forward.pose, 5, { seedJoints: joints }); assert.equal(inverse.rc, 0, `${moduleId} inverse`); inverse.joints.slice(0, 5).forEach((joint, index) => { assert.equal(near(joint, joints[index]), true, `${moduleId} inverse joint ${index}`); }); assert.equal(kins.switchKinematics(1), 0); const identity = kins.forward(joints); assert.equal(identity.rc, 0, `${moduleId} identity forward`); assertPoseComponent(identity.pose, "x", joints[0], `${moduleId} identity`); assertPoseComponent(identity.pose, "y", joints[1], `${moduleId} identity`); assertPoseComponent(identity.pose, "z", joints[2], `${moduleId} identity`); assertPoseComponent(identity.pose, expectedAxis, joints[3], `${moduleId} identity`); assertPoseComponent(identity.pose, "c", joints[4], `${moduleId} identity`); } await verifyTrtKinematics("xyzac-trt", [10, 20, 30, 25, 40], "a"); await verifyTrtKinematics("xyzbc-trt", [10, 20, 30, 35, 40], "b"); const manifestText = readFileSync(resolve(wasmPortRoot, "tools/source-manifest.txt"), "utf8"); for (const iniFile of ["xyzac-trt.ini", "xyzbc-trt.ini"]) { const iniText = readFileSync(resolve(vendorRoot, trtConfigRel, iniFile), "utf8"); const iniConfig = parseLinuxCncIni(iniText, { path: `${trtConfigRel}/${iniFile}`, profileId: iniFile.startsWith("xyzbc") ? "xyzbc-trt" : "xyzac-trt", }); assert.equal(iniConfig.validation.ready, true, `${iniFile} INI ready`); assert.equal(iniConfig.kinematics.name.endsWith("-trt-kins"), true, `${iniFile} kins`); assert.deepEqual(iniConfig.halui.mdiCommands, ["M429", "M428", "M430"], `${iniFile} HALUI MDI`); const plan = planSimConfigStaging({ manifestText, machineRel: `axis/vismach/5axis/table-rotary-tilting`, iniFile, iniText, }); const staged = plan.files.map((file) => file.sourceRel); assert.equal(staged.includes(`${trtConfigRel}/${iniFile}`), true, `${iniFile} staged`); assert.equal(staged.some((file) => file.endsWith("/remap_subs/428remap.ngc")), true, `${iniFile} M428 remap staged`); assert.equal(staged.some((file) => file.endsWith("/remap_subs/429remap.ngc")), true, `${iniFile} M429 remap staged`); assert.equal(staged.some((file) => file.endsWith("/remap_subs/430remap.ngc")), true, `${iniFile} M430 remap staged`); assert.equal(staged.some((file) => file.endsWith(".tbl")), true, `${iniFile} tool table staged`); } const interp = await createLinuxCncInterpSdk({ wasmBinary: readFileSync(resolve(wasmPortRoot, "build/wasm/core/linuxcnc_interp.wasm")), print() {}, printErr() {}, }); const directFiveAxisProgram = [ "G90 G17", "G0 X0 Y0 Z0 A0 C0", "G1 X10 Y2 Z-1 A15 C30 F120", "G1 X0 Y0 Z0 A0 C0 F120", "M2", "", ].join("\n"); const output = interp.runProgram(directFiveAxisProgram); assert.equal(output.includes("canon_event=STRAIGHT_TRAVERSE"), true); assert.equal(output.includes("canon_event=STRAIGHT_FEED"), true); assert.equal(output.includes("a=15"), true); assert.equal(output.includes("c=30"), true); console.log("full_linuxcnc_5axis_source_node_smoke=ok");