第 6 组:源码链接、构建和文档约束闭环完成
This commit is contained in:
@@ -7,7 +7,13 @@ const { pathToFileURL } = require("url");
|
||||
const wasmDir = path.join(__dirname, "web", "public");
|
||||
const cjsLoader = path.join(os.tmpdir(), `cnc_sim_node_loader_${process.pid}.cjs`);
|
||||
fs.copyFileSync(path.join(wasmDir, "cnc_sim.js"), cjsLoader);
|
||||
process.on("exit", () => {
|
||||
fs.rmSync(cjsLoader, { force: true });
|
||||
});
|
||||
const createCncSimModule = require(cjsLoader);
|
||||
if (typeof createCncSimModule !== "function") {
|
||||
throw new Error("cnc_sim.js did not export a Node-loadable createCncSimModule function");
|
||||
}
|
||||
|
||||
const EVENT_TYPE = {
|
||||
2: "comment",
|
||||
@@ -61,10 +67,87 @@ function expectKinematicsSwitch(events, line, kinstype, label) {
|
||||
}
|
||||
}
|
||||
|
||||
function expectEvent(events, predicate, message) {
|
||||
if (!events.some(predicate)) {
|
||||
throw new Error(message);
|
||||
}
|
||||
}
|
||||
|
||||
async function expectErrorContaining(action, expectedText, message) {
|
||||
try {
|
||||
await action();
|
||||
throw new Error(message);
|
||||
} catch (error) {
|
||||
if (!String(error?.message ?? error).includes(expectedText)) {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function expectRtcpPivot(events, expected, message) {
|
||||
expectEvent(
|
||||
events,
|
||||
(event) => event.type === "rtcp-pivot" &&
|
||||
event.line === expected.line &&
|
||||
event.reserved === expected.reserved &&
|
||||
near(event.dwellSeconds, expected.dwellSeconds) &&
|
||||
(expected.endX === undefined || near(event.endX, expected.endX)) &&
|
||||
(expected.endY === undefined || near(event.endY, expected.endY)) &&
|
||||
(expected.endZ === undefined || near(event.endZ, expected.endZ)) &&
|
||||
(expected.endA === undefined || near(event.endA, expected.endA)) &&
|
||||
(expected.endB === undefined || near(event.endB, expected.endB)) &&
|
||||
(expected.endC === undefined || near(event.endC, expected.endC)),
|
||||
message,
|
||||
);
|
||||
}
|
||||
|
||||
function near(actual, expected) {
|
||||
return Math.abs(actual - expected) < 1e-6;
|
||||
}
|
||||
|
||||
let completedSteps = 0;
|
||||
|
||||
function loadSwitchkinsCases() {
|
||||
const configCases = JSON.parse(
|
||||
fs.readFileSync(path.join(wasmDir, "linuxcnc_switchkins_remap_config_cases.json"), "utf8"),
|
||||
);
|
||||
if (!Array.isArray(configCases) || configCases.length === 0) {
|
||||
throw new Error("expected non-empty generated LinuxCNC switchkins config cases");
|
||||
}
|
||||
for (const [index, configCase] of configCases.entries()) {
|
||||
if (
|
||||
!configCase ||
|
||||
typeof configCase.field !== "string" ||
|
||||
typeof configCase.value !== "string" ||
|
||||
!Number.isInteger(configCase.m428) ||
|
||||
!Number.isInteger(configCase.m429) ||
|
||||
!Number.isInteger(configCase.m430)
|
||||
) {
|
||||
throw new Error(`invalid generated LinuxCNC switchkins config case at index ${index}`);
|
||||
}
|
||||
}
|
||||
return configCases.map((configCase) => ({
|
||||
label: `${configCase.field}=${configCase.value}`,
|
||||
config: { backend: "linuxcnc-rs274", [configCase.field]: configCase.value },
|
||||
program: configCase.m430 >= 0 ? "M428\nM429\nM430\n" : "M428\nM429\n",
|
||||
expected: [
|
||||
[1, configCase.m428],
|
||||
[2, configCase.m429],
|
||||
...(configCase.m430 >= 0 ? [[3, configCase.m430]] : []),
|
||||
],
|
||||
}));
|
||||
}
|
||||
|
||||
async function runStep(name, action) {
|
||||
try {
|
||||
await action();
|
||||
completedSteps += 1;
|
||||
} catch (error) {
|
||||
const detail = error && error.stack ? error.stack : error;
|
||||
throw new Error(`Node WASM smoke step "${name}" failed: ${detail}`);
|
||||
}
|
||||
}
|
||||
|
||||
(async () => {
|
||||
const module = await createCncSimModule({
|
||||
locateFile: (file) => path.join(wasmDir, file),
|
||||
@@ -80,7 +163,40 @@ function near(actual, expected) {
|
||||
const loadConfig = module.cwrap("cnc_sim_load_config_json", "number", ["number", "number", "number"]);
|
||||
const parseProgram = module.cwrap("cnc_sim_parse_program", "number", ["number", "number", "number"]);
|
||||
const lastError = module.cwrap("cnc_sim_last_error", "number", ["number"]);
|
||||
|
||||
const throwLastError = (targetHandle) => {
|
||||
throw new Error(module.UTF8ToString(lastError(targetHandle)));
|
||||
};
|
||||
const initializeHandle = (targetHandle) => {
|
||||
reset(targetHandle);
|
||||
if (setDialect(targetHandle, 0) !== 0) {
|
||||
throwLastError(targetHandle);
|
||||
}
|
||||
};
|
||||
const loadJsonConfig = (targetHandle, value) => {
|
||||
const config = writeString(module, JSON.stringify(value));
|
||||
try {
|
||||
if (loadConfig(targetHandle, config.ptr, config.len) !== 0) {
|
||||
throwLastError(targetHandle);
|
||||
}
|
||||
} finally {
|
||||
module._free(config.ptr);
|
||||
}
|
||||
};
|
||||
const parseText = (targetHandle, value) => {
|
||||
const program = writeString(module, value);
|
||||
try {
|
||||
if (parseProgram(targetHandle, program.ptr, program.len) !== 0) {
|
||||
throwLastError(targetHandle);
|
||||
}
|
||||
} finally {
|
||||
module._free(program.ptr);
|
||||
}
|
||||
};
|
||||
const attachCallback = (targetHandle, targetCallbackPtr) => {
|
||||
if (setCallback(targetHandle, targetCallbackPtr, 0) !== 0) {
|
||||
throwLastError(targetHandle);
|
||||
}
|
||||
};
|
||||
const handle = create();
|
||||
if (!handle) {
|
||||
throw new Error("cnc_sim_create returned null");
|
||||
@@ -88,258 +204,146 @@ function near(actual, expected) {
|
||||
|
||||
let callbackPtr = 0;
|
||||
try {
|
||||
reset(handle);
|
||||
if (setDialect(handle, 0) !== 0) {
|
||||
throw new Error(module.UTF8ToString(lastError(handle)));
|
||||
}
|
||||
|
||||
const config = writeString(module, JSON.stringify({ backend: "linuxcnc-rs274" }));
|
||||
try {
|
||||
if (loadConfig(handle, config.ptr, config.len) !== 0) {
|
||||
throw new Error(module.UTF8ToString(lastError(handle)));
|
||||
}
|
||||
} finally {
|
||||
module._free(config.ptr);
|
||||
}
|
||||
initializeHandle(handle);
|
||||
loadJsonConfig(handle, { backend: "linuxcnc-rs274" });
|
||||
|
||||
const events = [];
|
||||
callbackPtr = module.addFunction((eventPtr) => {
|
||||
events.push(readEvent(module, eventPtr));
|
||||
return 0;
|
||||
}, "iii");
|
||||
if (setCallback(handle, callbackPtr, 0) !== 0) {
|
||||
throw new Error(module.UTF8ToString(lastError(handle)));
|
||||
}
|
||||
|
||||
const program = writeString(module, "G21 G90\nG0 X0\nG1 X5 F100\nM30\n");
|
||||
try {
|
||||
if (parseProgram(handle, program.ptr, program.len) !== 0) {
|
||||
throw new Error(module.UTF8ToString(lastError(handle)));
|
||||
}
|
||||
} finally {
|
||||
module._free(program.ptr);
|
||||
}
|
||||
|
||||
if (!events.some((event) => event.type === "linear-feed" && event.endX === 5)) {
|
||||
throw new Error("expected LinuxCNC WASM linear-feed event ending at X5");
|
||||
}
|
||||
if (!events.some((event) => event.type === "program-end")) {
|
||||
throw new Error("expected LinuxCNC WASM program-end event");
|
||||
}
|
||||
|
||||
events.length = 0;
|
||||
const switchProgram = writeString(module, "M428\nM429\nM430\n");
|
||||
try {
|
||||
if (parseProgram(handle, switchProgram.ptr, switchProgram.len) !== 0) {
|
||||
throw new Error(module.UTF8ToString(lastError(handle)));
|
||||
}
|
||||
} finally {
|
||||
module._free(switchProgram.ptr);
|
||||
}
|
||||
|
||||
for (const kinstype of [1, 0, 2]) {
|
||||
if (!events.some((event) => event.type === "kinematics-switch" && event.reserved === kinstype)) {
|
||||
throw new Error(`expected LinuxCNC WASM kinematics switch ${kinstype}`);
|
||||
}
|
||||
if (!events.some((event) => event.type === "comment" &&
|
||||
event.reserved === 68 &&
|
||||
event.tool === 3 &&
|
||||
event.feed === kinstype)) {
|
||||
throw new Error(`expected LinuxCNC WASM M68 E3 Q${kinstype} remap side effect`);
|
||||
}
|
||||
}
|
||||
if (!events.some((event) => event.type === "comment" &&
|
||||
event.reserved === 66 &&
|
||||
event.tool === 0 &&
|
||||
event.feed === 0)) {
|
||||
throw new Error("expected LinuxCNC WASM M66 E0 L0 remap side effect");
|
||||
}
|
||||
|
||||
const switchkinsCases = [
|
||||
{
|
||||
label: "scara",
|
||||
config: { backend: "linuxcnc-rs274", switchkins: "scara" },
|
||||
program: "M428\nM429\nM430\n",
|
||||
expected: [
|
||||
[1, 0],
|
||||
[2, 1],
|
||||
[3, 2],
|
||||
],
|
||||
},
|
||||
{
|
||||
label: "table-dual-rotary",
|
||||
config: { backend: "linuxcnc-rs274", switchkins: "table-dual-rotary" },
|
||||
program: "M428\nM429\n",
|
||||
expected: [
|
||||
[1, 1],
|
||||
[2, 0],
|
||||
],
|
||||
},
|
||||
{
|
||||
label: "sim-xyzab-tdr-kins",
|
||||
config: { backend: "linuxcnc-rs274", switchkins: "sim-xyzab-tdr-kins" },
|
||||
program: "M428\nM429\n",
|
||||
expected: [
|
||||
[1, 1],
|
||||
[2, 0],
|
||||
],
|
||||
},
|
||||
{
|
||||
label: "puma",
|
||||
config: { backend: "linuxcnc-rs274", switchkins: "puma" },
|
||||
program: "M428\nM429\nM430\n",
|
||||
expected: [
|
||||
[1, 0],
|
||||
[2, 1],
|
||||
[3, 2],
|
||||
],
|
||||
},
|
||||
{
|
||||
label: "melfa-sim",
|
||||
config: { backend: "linuxcnc-rs274", switchkins: "melfa-sim" },
|
||||
program: "M428\nM429\nM430\n",
|
||||
expected: [
|
||||
[1, 0],
|
||||
[2, 1],
|
||||
[3, 2],
|
||||
],
|
||||
},
|
||||
{
|
||||
label: "hexapod-sim",
|
||||
config: { backend: "linuxcnc-rs274", remap: "hexapod-sim" },
|
||||
program: "M428\nM429\nM430\n",
|
||||
expected: [
|
||||
[1, 0],
|
||||
[2, 1],
|
||||
[3, 2],
|
||||
],
|
||||
},
|
||||
{
|
||||
label: "xyzbca-trsrn",
|
||||
config: { backend: "linuxcnc-rs274", switchkins: "xyzbca-trsrn" },
|
||||
program: "M428\nM429\nM430\n",
|
||||
expected: [
|
||||
[1, 0],
|
||||
[2, 1],
|
||||
[3, 2],
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
for (const testCase of switchkinsCases) {
|
||||
attachCallback(handle, callbackPtr);
|
||||
const parseCaseWithHandle = (testCase) => {
|
||||
reset(handle);
|
||||
events.length = 0;
|
||||
const switchkinsConfig = writeString(module, JSON.stringify(testCase.config));
|
||||
loadJsonConfig(handle, testCase.config);
|
||||
parseText(handle, testCase.program);
|
||||
};
|
||||
const withConfiguredHandle = async (label, config, program, action) => {
|
||||
events.length = 0;
|
||||
const targetHandle = create();
|
||||
if (!targetHandle) {
|
||||
throw new Error(`cnc_sim_create returned null for ${label} case`);
|
||||
}
|
||||
try {
|
||||
if (loadConfig(handle, switchkinsConfig.ptr, switchkinsConfig.len) !== 0) {
|
||||
throw new Error(module.UTF8ToString(lastError(handle)));
|
||||
}
|
||||
initializeHandle(targetHandle);
|
||||
attachCallback(targetHandle, callbackPtr);
|
||||
loadJsonConfig(targetHandle, config);
|
||||
parseText(targetHandle, program);
|
||||
await action();
|
||||
} finally {
|
||||
module._free(switchkinsConfig.ptr);
|
||||
destroy(targetHandle);
|
||||
}
|
||||
};
|
||||
|
||||
const switchkinsProgram = writeString(module, testCase.program);
|
||||
try {
|
||||
if (parseProgram(handle, switchkinsProgram.ptr, switchkinsProgram.len) !== 0) {
|
||||
throw new Error(module.UTF8ToString(lastError(handle)));
|
||||
await runStep("basic LinuxCNC RS274 parse", async () => {
|
||||
parseText(handle, "G21 G90\nG0 X0\nG1 X5 F100\nM30\n");
|
||||
});
|
||||
await runStep("basic LinuxCNC RS274 linear-feed event", async () => {
|
||||
expectEvent(events, (event) => event.type === "linear-feed" && event.endX === 5,
|
||||
"expected LinuxCNC WASM linear-feed event ending at X5");
|
||||
});
|
||||
await runStep("basic LinuxCNC RS274 program-end event", async () => {
|
||||
expectEvent(events, (event) => event.type === "program-end",
|
||||
"expected LinuxCNC WASM program-end event");
|
||||
});
|
||||
|
||||
await runStep("default switchkins remap parse", async () => {
|
||||
events.length = 0;
|
||||
parseText(handle, "M428\nM429\nM430\n");
|
||||
});
|
||||
for (const kinstype of [1, 0, 2]) {
|
||||
await runStep(`default switchkins kinematics switch ${kinstype}`, async () => {
|
||||
expectEvent(events, (event) => event.type === "kinematics-switch" && event.reserved === kinstype,
|
||||
`expected LinuxCNC WASM kinematics switch ${kinstype}`);
|
||||
});
|
||||
await runStep(`default switchkins M68 E3 Q${kinstype} side effect`, async () => {
|
||||
expectEvent(events, (event) => event.type === "comment" &&
|
||||
event.reserved === 68 &&
|
||||
event.tool === 3 &&
|
||||
event.feed === kinstype,
|
||||
`expected LinuxCNC WASM M68 E3 Q${kinstype} remap side effect`);
|
||||
});
|
||||
}
|
||||
await runStep("default switchkins M66 E0 L0 side effect", async () => {
|
||||
expectEvent(events, (event) => event.type === "comment" &&
|
||||
event.reserved === 66 &&
|
||||
event.tool === 0 &&
|
||||
event.feed === 0,
|
||||
"expected LinuxCNC WASM M66 E0 L0 remap side effect");
|
||||
});
|
||||
|
||||
const switchkinsCases = loadSwitchkinsCases();
|
||||
await runStep("generated switchkins config cases load", async () => {
|
||||
if (switchkinsCases.length === 0) {
|
||||
throw new Error("expected generated LinuxCNC WASM switchkins config cases");
|
||||
}
|
||||
});
|
||||
for (const testCase of switchkinsCases) {
|
||||
await runStep(`generated switchkins ${testCase.label}`, async () => {
|
||||
parseCaseWithHandle(testCase);
|
||||
for (const [line, kinstype] of testCase.expected) {
|
||||
expectKinematicsSwitch(events, line, kinstype, testCase.label);
|
||||
}
|
||||
} finally {
|
||||
module._free(switchkinsProgram.ptr);
|
||||
}
|
||||
|
||||
for (const [line, kinstype] of testCase.expected) {
|
||||
expectKinematicsSwitch(events, line, kinstype, testCase.label);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
await runStep("5axiskins RTCP parse", async () => {
|
||||
reset(handle);
|
||||
events.length = 0;
|
||||
const fiveaxisConfig = writeString(
|
||||
module,
|
||||
JSON.stringify({
|
||||
backend: "linuxcnc-rs274",
|
||||
rtcp: { enabled: true, toolLength: 250 },
|
||||
kinematics: "5axiskins",
|
||||
pivotLength: 250,
|
||||
}),
|
||||
);
|
||||
try {
|
||||
if (loadConfig(handle, fiveaxisConfig.ptr, fiveaxisConfig.len) !== 0) {
|
||||
throw new Error(module.UTF8ToString(lastError(handle)));
|
||||
}
|
||||
} finally {
|
||||
module._free(fiveaxisConfig.ptr);
|
||||
}
|
||||
|
||||
const fiveaxisProgram = writeString(module, "M428\nG0 X260 Y20 Z280 B90 C0\n");
|
||||
try {
|
||||
if (parseProgram(handle, fiveaxisProgram.ptr, fiveaxisProgram.len) !== 0) {
|
||||
throw new Error(module.UTF8ToString(lastError(handle)));
|
||||
}
|
||||
} finally {
|
||||
module._free(fiveaxisProgram.ptr);
|
||||
}
|
||||
|
||||
loadJsonConfig(handle, {
|
||||
backend: "linuxcnc-rs274",
|
||||
rtcp: { enabled: true, toolLength: 250 },
|
||||
kinematics: "5axiskins",
|
||||
pivotLength: 250,
|
||||
});
|
||||
parseText(handle, "M428\nG0 X260 Y20 Z280 B90 C0\n");
|
||||
});
|
||||
await runStep("5axiskins RTCP kinematics switch", async () => {
|
||||
expectKinematicsSwitch(events, 1, 0, "5axiskins");
|
||||
if (!events.some((event) => event.type === "rtcp-pivot" &&
|
||||
event.line === 2 &&
|
||||
event.reserved === 0 &&
|
||||
near(event.dwellSeconds, 250) &&
|
||||
near(event.endX, 10) &&
|
||||
near(event.endY, 20) &&
|
||||
near(event.endZ, 30) &&
|
||||
near(event.endB, 90) &&
|
||||
near(event.endC, 0))) {
|
||||
throw new Error("expected LinuxCNC WASM 5axiskins RTCP pivot from LinuxCNC 5axiskins inverse");
|
||||
}
|
||||
});
|
||||
await runStep("5axiskins RTCP pivot event", async () => {
|
||||
expectRtcpPivot(events, {
|
||||
line: 2,
|
||||
reserved: 0,
|
||||
dwellSeconds: 250,
|
||||
endX: 10,
|
||||
endY: 20,
|
||||
endZ: 30,
|
||||
endB: 90,
|
||||
endC: 0,
|
||||
}, "expected LinuxCNC WASM 5axiskins RTCP pivot from LinuxCNC 5axiskins inverse");
|
||||
});
|
||||
|
||||
await runStep("userk RTCP parse", async () => {
|
||||
reset(handle);
|
||||
events.length = 0;
|
||||
const userkConfig = writeString(
|
||||
module,
|
||||
JSON.stringify({
|
||||
backend: "linuxcnc-rs274",
|
||||
rtcp: { enabled: true, toolLength: 250 },
|
||||
}),
|
||||
);
|
||||
try {
|
||||
if (loadConfig(handle, userkConfig.ptr, userkConfig.len) !== 0) {
|
||||
throw new Error(module.UTF8ToString(lastError(handle)));
|
||||
}
|
||||
} finally {
|
||||
module._free(userkConfig.ptr);
|
||||
}
|
||||
|
||||
const userkProgram = writeString(module, "M430\nG0 X260 Y20 Z280 B90 C45\n");
|
||||
try {
|
||||
if (parseProgram(handle, userkProgram.ptr, userkProgram.len) !== 0) {
|
||||
throw new Error(module.UTF8ToString(lastError(handle)));
|
||||
}
|
||||
} finally {
|
||||
module._free(userkProgram.ptr);
|
||||
}
|
||||
|
||||
loadJsonConfig(handle, {
|
||||
backend: "linuxcnc-rs274",
|
||||
rtcp: { enabled: true, toolLength: 250 },
|
||||
});
|
||||
parseText(handle, "M430\nG0 X260 Y20 Z280 B90 C45\n");
|
||||
});
|
||||
await runStep("userk RTCP kinematics switch", async () => {
|
||||
expectKinematicsSwitch(events, 1, 2, "userk");
|
||||
if (!events.some((event) => event.type === "rtcp-pivot" &&
|
||||
event.line === 2 &&
|
||||
event.reserved === 2 &&
|
||||
near(event.dwellSeconds, 250) &&
|
||||
near(event.endX, 260) &&
|
||||
near(event.endY, 20) &&
|
||||
near(event.endZ, 280) &&
|
||||
near(event.endB, 90) &&
|
||||
near(event.endC, 45))) {
|
||||
throw new Error("expected LinuxCNC WASM userk RTCP pivot from LinuxCNC userk identity inverse");
|
||||
}
|
||||
});
|
||||
await runStep("userk RTCP pivot event", async () => {
|
||||
expectRtcpPivot(events, {
|
||||
line: 2,
|
||||
reserved: 2,
|
||||
dwellSeconds: 250,
|
||||
endX: 260,
|
||||
endY: 20,
|
||||
endZ: 280,
|
||||
endB: 90,
|
||||
endC: 45,
|
||||
}, "expected LinuxCNC WASM userk RTCP pivot from LinuxCNC userk identity inverse");
|
||||
});
|
||||
|
||||
events.length = 0;
|
||||
const configuredTrtHandle = create();
|
||||
if (!configuredTrtHandle) {
|
||||
throw new Error("cnc_sim_create returned null for configured xyzbc-trt case");
|
||||
}
|
||||
const configuredTrtConfig = writeString(
|
||||
module,
|
||||
JSON.stringify({
|
||||
await runStep("configured xyzbc-trt RTCP parse", async () => {
|
||||
await withConfiguredHandle(
|
||||
"configured xyzbc-trt",
|
||||
{
|
||||
backend: "linuxcnc-rs274",
|
||||
rtcp: { enabled: false, toolLength: 11 },
|
||||
xyzbcTrt: {
|
||||
@@ -350,54 +354,32 @@ function near(actual, expected) {
|
||||
zOffset: 7,
|
||||
conventionalDirections: true,
|
||||
},
|
||||
}),
|
||||
},
|
||||
"M428\nG43.4\nG0 X30 Y40 Z50 B20 C-30\n",
|
||||
async () => {
|
||||
},
|
||||
);
|
||||
try {
|
||||
reset(configuredTrtHandle);
|
||||
if (setDialect(configuredTrtHandle, 0) !== 0) {
|
||||
throw new Error(module.UTF8ToString(lastError(configuredTrtHandle)));
|
||||
}
|
||||
if (setCallback(configuredTrtHandle, callbackPtr, 0) !== 0) {
|
||||
throw new Error(module.UTF8ToString(lastError(configuredTrtHandle)));
|
||||
}
|
||||
if (loadConfig(configuredTrtHandle, configuredTrtConfig.ptr, configuredTrtConfig.len) !== 0) {
|
||||
throw new Error(module.UTF8ToString(lastError(configuredTrtHandle)));
|
||||
}
|
||||
} finally {
|
||||
module._free(configuredTrtConfig.ptr);
|
||||
}
|
||||
});
|
||||
await runStep("configured xyzbc-trt kinematics switch", async () => {
|
||||
expectKinematicsSwitch(events, 1, 1, "configured xyzbc-trt");
|
||||
});
|
||||
await runStep("configured xyzbc-trt RTCP pivot event", async () => {
|
||||
expectRtcpPivot(events, {
|
||||
line: 3,
|
||||
reserved: 1,
|
||||
dwellSeconds: 11,
|
||||
endX: -4.814629,
|
||||
endY: 47.605118,
|
||||
endZ: 48.160567,
|
||||
endB: 20,
|
||||
endC: -30,
|
||||
}, "expected LinuxCNC WASM configured xyzbc-trt RTCP pivot from LinuxCNC trtfuncs inverse");
|
||||
});
|
||||
|
||||
const configuredTrtProgram = writeString(module, "M428\nG43.4\nG0 X30 Y40 Z50 B20 C-30\n");
|
||||
try {
|
||||
if (parseProgram(configuredTrtHandle, configuredTrtProgram.ptr, configuredTrtProgram.len) !== 0) {
|
||||
throw new Error(module.UTF8ToString(lastError(configuredTrtHandle)));
|
||||
}
|
||||
} finally {
|
||||
module._free(configuredTrtProgram.ptr);
|
||||
destroy(configuredTrtHandle);
|
||||
}
|
||||
|
||||
expectKinematicsSwitch(events, 1, 1, "configured xyzbc-trt");
|
||||
if (!events.some((event) => event.type === "rtcp-pivot" &&
|
||||
event.line === 3 &&
|
||||
event.reserved === 1 &&
|
||||
near(event.dwellSeconds, 11) &&
|
||||
near(event.endX, -4.814629) &&
|
||||
near(event.endY, 47.605118) &&
|
||||
near(event.endZ, 48.160567) &&
|
||||
near(event.endB, 20) &&
|
||||
near(event.endC, -30))) {
|
||||
throw new Error("expected LinuxCNC WASM configured xyzbc-trt RTCP pivot from LinuxCNC trtfuncs inverse");
|
||||
}
|
||||
|
||||
events.length = 0;
|
||||
const configuredXyzacHandle = create();
|
||||
if (!configuredXyzacHandle) {
|
||||
throw new Error("cnc_sim_create returned null for configured xyzac-trt case");
|
||||
}
|
||||
const configuredXyzacConfig = writeString(
|
||||
module,
|
||||
JSON.stringify({
|
||||
await runStep("configured xyzac-trt RTCP parse", async () => {
|
||||
await withConfiguredHandle(
|
||||
"configured xyzac-trt",
|
||||
{
|
||||
backend: "linuxcnc-rs274",
|
||||
rtcp: { enabled: false, toolLength: 7 },
|
||||
switchkins: "xyzac-trt",
|
||||
@@ -405,47 +387,30 @@ function near(actual, expected) {
|
||||
yOffset: 20,
|
||||
zOffset: 10,
|
||||
},
|
||||
}),
|
||||
},
|
||||
"M428\nG43.4\nG0 X12 Y-8 Z42 A35 C-25\n",
|
||||
async () => {
|
||||
},
|
||||
);
|
||||
try {
|
||||
reset(configuredXyzacHandle);
|
||||
if (setDialect(configuredXyzacHandle, 0) !== 0) {
|
||||
throw new Error(module.UTF8ToString(lastError(configuredXyzacHandle)));
|
||||
}
|
||||
if (setCallback(configuredXyzacHandle, callbackPtr, 0) !== 0) {
|
||||
throw new Error(module.UTF8ToString(lastError(configuredXyzacHandle)));
|
||||
}
|
||||
if (loadConfig(configuredXyzacHandle, configuredXyzacConfig.ptr, configuredXyzacConfig.len) !== 0) {
|
||||
throw new Error(module.UTF8ToString(lastError(configuredXyzacHandle)));
|
||||
}
|
||||
} finally {
|
||||
module._free(configuredXyzacConfig.ptr);
|
||||
}
|
||||
|
||||
const configuredXyzacProgram = writeString(module, "M428\nG43.4\nG0 X12 Y-8 Z42 A35 C-25\n");
|
||||
try {
|
||||
if (parseProgram(configuredXyzacHandle, configuredXyzacProgram.ptr, configuredXyzacProgram.len) !== 0) {
|
||||
throw new Error(module.UTF8ToString(lastError(configuredXyzacHandle)));
|
||||
}
|
||||
} finally {
|
||||
module._free(configuredXyzacProgram.ptr);
|
||||
destroy(configuredXyzacHandle);
|
||||
}
|
||||
|
||||
expectKinematicsSwitch(events, 1, 1, "configured xyzac-trt");
|
||||
if (!events.some((event) => event.type === "rtcp-pivot" &&
|
||||
event.line === 3 &&
|
||||
event.reserved === 1 &&
|
||||
near(event.dwellSeconds, 7) &&
|
||||
near(event.endX, 7.494747) &&
|
||||
near(event.endY, -20.815946) &&
|
||||
near(event.endZ, 18.939732) &&
|
||||
near(event.endA, 35) &&
|
||||
near(event.endB, 0) &&
|
||||
near(event.endC, -25))) {
|
||||
throw new Error("expected LinuxCNC WASM configured xyzac-trt RTCP pivot from LinuxCNC xyzab_tdr inverse");
|
||||
}
|
||||
});
|
||||
await runStep("configured xyzac-trt kinematics switch", async () => {
|
||||
expectKinematicsSwitch(events, 1, 1, "configured xyzac-trt");
|
||||
});
|
||||
await runStep("configured xyzac-trt RTCP pivot event", async () => {
|
||||
expectRtcpPivot(events, {
|
||||
line: 3,
|
||||
reserved: 1,
|
||||
dwellSeconds: 7,
|
||||
endX: 7.494747,
|
||||
endY: -20.815946,
|
||||
endZ: 18.939732,
|
||||
endA: 35,
|
||||
endB: 0,
|
||||
endC: -25,
|
||||
}, "expected LinuxCNC WASM configured xyzac-trt RTCP pivot from LinuxCNC xyzab_tdr inverse");
|
||||
});
|
||||
|
||||
await runStep("web wasm-core wrapper defaults and options", async () => {
|
||||
globalThis.createCncSimModule = createCncSimModule;
|
||||
const wasmCoreUrl = pathToFileURL(path.join(__dirname, "web", "src", "wasm-core.js")).href;
|
||||
const { createWasmSimulator } = await import(wasmCoreUrl);
|
||||
@@ -461,6 +426,31 @@ function near(actual, expected) {
|
||||
near(event.end.x, 3))) {
|
||||
throw new Error("expected web wasm-core default backend to use LinuxCNC RS274");
|
||||
}
|
||||
if (webSimulator.fs.opfs !== null) {
|
||||
throw new Error("expected Node wasm-core wrapper to leave OPFS disabled");
|
||||
}
|
||||
await expectErrorContaining(
|
||||
() => webSimulator.parseFile("programs/node-smoke.ngc", "linuxcnc", { backend: "linuxcnc-rs274" }),
|
||||
"OPFS workspace is not available",
|
||||
"expected Node wasm-core parseFile to require OPFS",
|
||||
);
|
||||
await expectErrorContaining(
|
||||
() => webSimulator.parseWithParameterFile("G21 G90\nM30\n", "parameters/node.var", "linuxcnc", {
|
||||
backend: "linuxcnc-rs274",
|
||||
}),
|
||||
"OPFS workspace is not available",
|
||||
"expected Node wasm-core parseWithParameterFile to require OPFS",
|
||||
);
|
||||
await expectErrorContaining(
|
||||
() => webSimulator.parseFileWithParameterFile(
|
||||
"programs/node-smoke.ngc",
|
||||
"parameters/node.var",
|
||||
"linuxcnc",
|
||||
{ backend: "linuxcnc-rs274" },
|
||||
),
|
||||
"OPFS workspace is not available",
|
||||
"expected Node wasm-core parseFileWithParameterFile to require OPFS",
|
||||
);
|
||||
|
||||
const webEvents = webSimulator.parse(
|
||||
"M428\nG43.4\nG0 X12 Y-8 Z42 A35 C-25\n",
|
||||
@@ -475,22 +465,22 @@ function near(actual, expected) {
|
||||
},
|
||||
},
|
||||
);
|
||||
if (!webEvents.some((event) => event.type === "rtcp-pivot" &&
|
||||
event.line === 3 &&
|
||||
event.reserved === 1 &&
|
||||
near(event.dwellSeconds, 7) &&
|
||||
near(event.end.x, 7.494747) &&
|
||||
near(event.end.y, -20.815946) &&
|
||||
near(event.end.z, 18.939732) &&
|
||||
near(event.end.a, 35) &&
|
||||
near(event.end.b, 0) &&
|
||||
near(event.end.c, -25))) {
|
||||
throw new Error("expected web wasm-core options to pass LinuxCNC xyzac-trt RTCP config into WASM");
|
||||
}
|
||||
expectEvent(webEvents, (event) => event.type === "rtcp-pivot" &&
|
||||
event.line === 3 &&
|
||||
event.reserved === 1 &&
|
||||
near(event.dwellSeconds, 7) &&
|
||||
near(event.end.x, 7.494747) &&
|
||||
near(event.end.y, -20.815946) &&
|
||||
near(event.end.z, 18.939732) &&
|
||||
near(event.end.a, 35) &&
|
||||
near(event.end.b, 0) &&
|
||||
near(event.end.c, -25),
|
||||
"expected web wasm-core options to pass LinuxCNC xyzac-trt RTCP config into WASM");
|
||||
} finally {
|
||||
webSimulator.dispose();
|
||||
delete globalThis.createCncSimModule;
|
||||
}
|
||||
});
|
||||
} finally {
|
||||
if (callbackPtr) {
|
||||
module.removeFunction(callbackPtr);
|
||||
@@ -498,7 +488,7 @@ function near(actual, expected) {
|
||||
destroy(handle);
|
||||
}
|
||||
|
||||
console.log("web wasm node smoke passed");
|
||||
console.log(`web wasm node smoke passed (${completedSteps} steps)`);
|
||||
})().catch((error) => {
|
||||
console.error(error && error.stack ? error.stack : error);
|
||||
process.exit(1);
|
||||
|
||||
Reference in New Issue
Block a user