165 lines
6.8 KiB
JavaScript
165 lines
6.8 KiB
JavaScript
import assert from "node:assert/strict";
|
|
import { readFile } from "node:fs/promises";
|
|
|
|
import { createMemorySessionStorage } from "../../app/src/runtime/five-axis-session.js";
|
|
import { createLinuxCncInterpreterRuntime } from "../../app/src/runtime/linuxcnc-interpreter-runtime.js";
|
|
import { parseLinuxCncIni } from "../../app/src/runtime/linuxcnc-ini-runtime.js";
|
|
import { getFiveAxisProfile } from "../../app/src/profiles/index.js";
|
|
import { createSimulationStore } from "../../app/src/state/store.js";
|
|
|
|
function sidebarEntry(state, id) {
|
|
const entry = state.rightSidebarEntrances.find((candidate) => candidate.id === id);
|
|
assert.ok(entry, `missing right sidebar entry ${id}`);
|
|
return entry;
|
|
}
|
|
|
|
async function waitForValidatedProgram(store) {
|
|
for (let attempt = 0; attempt < 30; attempt += 1) {
|
|
const state = store.getState();
|
|
if (!state.interpreterExecutionPending && state.programValidation?.ready) {
|
|
return state;
|
|
}
|
|
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
}
|
|
return store.getState();
|
|
}
|
|
|
|
async function loadIniConfigFromVendoredSource(profile) {
|
|
const text = await readFile(
|
|
new URL(`../../../wasm-port/vendor/linuxcnc/${profile.iniPath}`, import.meta.url),
|
|
"utf8",
|
|
);
|
|
return parseLinuxCncIni(text, {
|
|
path: profile.iniPath,
|
|
profileId: profile.id,
|
|
});
|
|
}
|
|
|
|
const store = createSimulationStore();
|
|
let state = store.getState();
|
|
assert.equal(state.rightSidebarEntrances.length, 9);
|
|
assert.deepEqual(
|
|
state.rightSidebarEntrances.map((entry) => entry.label),
|
|
["E-STOP", "POWER", "RESET", "AUTO", "MANUAL", "JOG", "MDI", "IDENTITY", "TCP"],
|
|
);
|
|
assert.equal(sidebarEntry(state, "power").allowed, true);
|
|
assert.equal(sidebarEntry(state, "auto").allowed, false);
|
|
assert.equal(sidebarEntry(state, "manual").allowed, false);
|
|
assert.equal(sidebarEntry(state, "jog").allowed, false);
|
|
assert.equal(sidebarEntry(state, "mdi").allowed, false);
|
|
assert.equal(sidebarEntry(state, "identity").active, true);
|
|
assert.equal(sidebarEntry(state, "identity").status, "active-blocked");
|
|
assert.equal(sidebarEntry(state, "tcp").allowed, false);
|
|
|
|
store.dispatch({ type: "ESTOP" });
|
|
state = store.getState();
|
|
assert.equal(sidebarEntry(state, "estop").status, "emergency");
|
|
assert.equal(sidebarEntry(state, "power").allowed, false);
|
|
assert.equal(sidebarEntry(state, "power").operatorMessage, "power on blocked: reset estop first");
|
|
|
|
store.dispatch({ type: "RESET" });
|
|
store.dispatch({ type: "TOGGLE_POWER" });
|
|
state = store.getState();
|
|
assert.equal(state.machine.taskState, "on");
|
|
assert.equal(sidebarEntry(state, "power").active, true);
|
|
assert.equal(sidebarEntry(state, "manual").active, true);
|
|
assert.equal(sidebarEntry(state, "jog").active, false);
|
|
assert.equal(sidebarEntry(state, "auto").allowed, false);
|
|
assert.equal(sidebarEntry(state, "auto").operatorMessage, "mode blocked: home machine before AUTO");
|
|
|
|
store.dispatch({ type: "SET_MODE", mode: "jog" });
|
|
state = store.getState();
|
|
assert.equal(state.machine.mode, "manual");
|
|
assert.equal(state.machine.manualPanel, "jog");
|
|
assert.equal(sidebarEntry(state, "manual").active, false);
|
|
assert.equal(sidebarEntry(state, "jog").active, true);
|
|
|
|
store.dispatch({ type: "HOME" });
|
|
store.dispatch({ type: "SET_MODE", mode: "auto" });
|
|
state = store.getState();
|
|
assert.equal(sidebarEntry(state, "auto").active, true);
|
|
assert.equal(sidebarEntry(state, "mdi").allowed, true);
|
|
assert.equal(sidebarEntry(state, "tcp").allowed, true);
|
|
|
|
store.dispatch({ type: "SET_KINS_TYPE", kinsType: "tcp-xyzac" });
|
|
state = store.getState();
|
|
assert.equal(state.kinsType, "tcp-xyzac");
|
|
assert.equal(state.rtcpState, "on");
|
|
assert.equal(sidebarEntry(state, "tcp").active, true);
|
|
store.dispatch({ type: "SET_KINS_TYPE", kinsType: "identity" });
|
|
assert.equal(store.getState().kinsType, "identity");
|
|
|
|
store.dispatch({
|
|
type: "LOAD_PROGRAM",
|
|
filename: "sidebar-running-gate.ngc",
|
|
content: [
|
|
"G0 X0 Y0 Z0",
|
|
"G1 X1 F100",
|
|
"G1 X2",
|
|
"G1 X3",
|
|
"G1 X4",
|
|
"G1 X5",
|
|
"G1 X6",
|
|
"G1 X7",
|
|
"G1 X8",
|
|
"G1 X9",
|
|
"M2",
|
|
].join("\n"),
|
|
});
|
|
store.dispatch({ type: "RUN" });
|
|
state = store.getState();
|
|
assert.equal(state.runState, "running");
|
|
assert.equal(sidebarEntry(state, "manual").allowed, false);
|
|
assert.equal(sidebarEntry(state, "tcp").allowed, false);
|
|
assert.equal(sidebarEntry(state, "tcp").operatorMessage, "kinematics blocked: interpreter must be idle");
|
|
|
|
store.dispatch({ type: "STOP" });
|
|
store.dispatch({ type: "SET_MODE", mode: "manual" });
|
|
|
|
const profile = getFiveAxisProfile("xyzac-trt");
|
|
const iniConfig = await loadIniConfigFromVendoredSource(profile);
|
|
store.dispatch({ type: "ATTACH_INI_CONFIG", profileId: profile.id, iniConfig });
|
|
store.dispatch({
|
|
type: "ATTACH_INTERPRETER_RUNTIME",
|
|
runtime: await createLinuxCncInterpreterRuntime(),
|
|
});
|
|
await store.stageMachineFiles({ storage: createMemorySessionStorage() });
|
|
state = store.getState();
|
|
assert.equal(state.machineProject.profileId, "xyzac-trt");
|
|
assert.equal(state.machineProject.projectRoot, "web-rtcp-5axis-sim-plan/machines/xyzac-trt");
|
|
assert.equal(state.machineProject.ini.filename, "xyzac-trt.ini");
|
|
assert.equal(state.machineProject.ini.sourceMatchesProfile, true);
|
|
assert.equal(state.machineProject.ini.textMatchesLoadedIni, true);
|
|
assert.equal(state.machineProject.configFileCount > 0, true);
|
|
assert.equal(state.machineProject.gcodeFileCount, 16);
|
|
assert.equal(state.machineProject.gcodeFiles.some((file) => file.filename === "impeller-7bl-xyzac.ngc"), true);
|
|
|
|
store.dispatch({
|
|
type: "LOAD_LINUXCNC_GCODE_SOURCE",
|
|
sourceRel: "configs/sim/axis/vismach/5axis/table-rotary-tilting/demos/impeller-7bl-xyzac.ngc",
|
|
});
|
|
state = await waitForValidatedProgram(store);
|
|
assert.equal(state.programValidation.ready, true);
|
|
assert.equal(state.programValidation.sourceGuard, "linuxcnc_vendored_5axis_gcode_source_file");
|
|
assert.equal(state.programValidation.previewSource, "linuxcnc_interpreter_canonical_motion");
|
|
assert.equal(state.programValidation.motionEventCount > 0, true);
|
|
assert.equal(state.programValidation.plannerSampleCount > 0, true);
|
|
assert.equal(state.programValidation.realtimeAxisValues.x, state.axisPose.x);
|
|
assert.equal(state.machineProject.selectedProgram.filename, "impeller-7bl-xyzac.ngc");
|
|
|
|
const xyzbcStore = createSimulationStore();
|
|
xyzbcStore.dispatch({ type: "SET_PROFILE", profileId: "xyzbc-trt" });
|
|
const xyzbcProfile = getFiveAxisProfile("xyzbc-trt");
|
|
xyzbcStore.dispatch({
|
|
type: "ATTACH_INI_CONFIG",
|
|
profileId: xyzbcProfile.id,
|
|
iniConfig: await loadIniConfigFromVendoredSource(xyzbcProfile),
|
|
});
|
|
await xyzbcStore.stageMachineFiles({ storage: createMemorySessionStorage() });
|
|
const xyzbcState = xyzbcStore.getState();
|
|
assert.equal(xyzbcState.machineProject.profileId, "xyzbc-trt");
|
|
assert.equal(xyzbcState.machineProject.ini.filename, "xyzbc-trt.ini");
|
|
assert.equal(xyzbcState.machineProject.gcodeFiles.some((file) => file.filename === "boat-xyzbc.ngc"), true);
|
|
|
|
console.log("gmoccapy_trt_project_sidebar_smoke=ok");
|