import { readFileSync } from "node:fs"; import { fileURLToPath } from "node:url"; import { dirname, resolve } from "node:path"; import assert from "node:assert/strict"; import createLinuxCncTpModule from "../../../build/wasm/tp/linuxcnc_tp.js"; function verifyExpectedOutput(fixtureName, output, expectedText) { const expectedLines = expectedText.split("\n").filter(Boolean); for (const expectedLine of expectedLines) { assert.equal( output.includes(expectedLine), true, `${fixtureName}: ${expectedLine}`, ); } } const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); const rootDir = resolve(__dirname, "../../.."); const wasmPath = resolve(rootDir, "build/wasm/tp/linuxcnc_tp.wasm"); const tp = await createLinuxCncTpModule({ wasmBinary: readFileSync(wasmPath), print() {}, printErr(message) { console.error(message); }, }); const resultPtr = tp._lctp_run_probe(); assert.notEqual(resultPtr, 0); try { const output = tp.UTF8ToString(resultPtr); verifyExpectedOutput( "tp_wasm_probe", output, [ "tp_default_queue_size=32", "tp_err_ok=0", "tc_linear=1", "tc_circular=2", "pose_xyz=1,2,3", "tp_create=0", "tp_set_cycle_time=0", "tp_set_pos=0", "tp_set_vmax=0", "tp_set_vlimit=0", "tp_set_amax=0", "tp_set_term_cond=0", "tp_add_line=0", "tp_cycle_rc=4", "tp_get_pos=0", "tp_done_after_line=1", "tp_queue_depth=0", "tp_final_pos=1,0,0", "tp_arc_create=0", "tp_add_circle=0", "tp_arc_cycle_rc=4", "tp_arc_get_pos=0", "tp_done_after_arc=1", "tp_arc_queue_depth=0", "tp_arc_final_pos_near_end=1", "tp_queue_create=0", "tp_queue_add_line1=0", "tp_queue_depth_after_line1=1", "tp_queue_add_line2=0", "tp_queue_depth_after_line2=2", "tp_queue_cycle_rc=4", "tp_queue_get_pos=0", "tp_done_after_queued_lines=1", "tp_queue_final_depth=0", "tp_queue_final_pos_near_end=1", "tp_queue_final_pos=1,1,0", "tp_pause_rc=0", "tp_resume_rc=0", "tp_paused_velocity_zero=1", "tp_paused_position_frozen=1", "tp_resume_done=1", "tp_pause_resume_final_depth=0", "tp_pause_resume_final_pos_near_end=1", ].join("\n"), ); } finally { tp._lctp_free_string(resultPtr); } function allocCString(mod, value) { const bytes = mod.lengthBytesUTF8(value) + 1; const ptr = mod._malloc(bytes); mod.stringToUTF8(value, ptr, bytes); return ptr; } const timingPayload = JSON.stringify({ cycleTime: 0.001, maxVelocity: 10, maxAcceleration: 50, maxJerk: 100, queueSize: 8, motion: [ { line: 2, type: "STRAIGHT_TRAVERSE", x: 0, y: 0, z: 0, a: 0, b: 0, c: 0, feedRate: 0 }, { line: 3, type: "STRAIGHT_FEED", x: 1, y: 0, z: 0, a: 0, b: 0, c: 0, feedRate: 60 }, { line: 4, type: "STRAIGHT_FEED", x: 1, y: 1, z: 0, a: 0, b: 0, c: 0, feedRate: 60 }, ], }); const timingInputPtr = allocCString(tp, timingPayload); const timingResultPtr = tp._lctp_run_canonical_motion_timing(timingInputPtr); assert.notEqual(timingResultPtr, 0); try { const timing = JSON.parse(tp.UTF8ToString(timingResultPtr)); assert.equal(timing.ok, true); assert.equal(timing.semanticBoundary, "linuxcnc_tp_queue_runtime_timing_from_canonical_motion"); assert.equal(timing.motionCount, 3); assert.equal(timing.addFailures, 0); assert.equal(timing.emittedMotionCount, 3); assert.equal(timing.segments[0].zeroLength, true); assert.equal(timing.segments[0].durationSeconds, 0); assert.equal(timing.totalSeconds > 0, true); assert.equal(timing.tpDone, 1); } finally { tp._lctp_free_string(timingResultPtr); tp._free(timingInputPtr); } const arcPayload = JSON.stringify({ cycleTime: 0.001, maxVelocity: 10, maxAcceleration: 50, maxJerk: 100, queueSize: 8, motion: [ { line: 2, type: "STRAIGHT_TRAVERSE", x: 1, y: 0, z: 0, a: 0, b: 0, c: 0, feedRate: 0 }, { line: 3, type: "ARC_FEED", x: 0, y: 1, z: 0, a: 0, b: 0, c: 0, feedRate: 60, plane: 170, centerFirst: 0, centerSecond: 0, rotation: -1, axisEndPoint: 0, }, ], }); const arcInputPtr = allocCString(tp, arcPayload); const arcResultPtr = tp._lctp_run_canonical_motion_timing(arcInputPtr); assert.notEqual(arcResultPtr, 0); try { const timing = JSON.parse(tp.UTF8ToString(arcResultPtr)); assert.equal(timing.ok, true); assert.equal(timing.addFailures, 0); assert.equal(timing.emittedMotionCount, 2); assert.equal(timing.segments[1].type, "ARC_FEED"); assert.equal(timing.segments[1].durationSeconds > 1.4, true); assert.equal(timing.tpDone, 1); } finally { tp._lctp_free_string(arcResultPtr); tp._free(arcInputPtr); } console.log("tp_wasm_node_smoke=ok"); console.log("tp_pause_resume_smoke=ok");