完善五轴 RTCP 仿真与验证资料
This commit is contained in:
@@ -8,6 +8,8 @@ assert.equal(blocked.phase, "blocked");
|
||||
assert.equal(blocked.promotionAllowed, false);
|
||||
assert.equal(blocked.fullLinuxCncProgramExecutionReady, false);
|
||||
assert.equal(blocked.missing.includes("linuxcnc kinematics WASM frame"), true);
|
||||
assert.equal(blocked.missing.includes("tool DB Web/WASM simulation process"), true);
|
||||
assert.equal(blocked.missing.includes("controlled user-M Web/WASM simulation process"), true);
|
||||
assert.equal(blocked.blockers.some((blocker) => blocker.includes("LinuxCNC task runtime")), true);
|
||||
|
||||
const canonicalState = {
|
||||
@@ -105,6 +107,45 @@ assert.equal(remap.semanticBoundary, "linuxcnc_machine_file_remap_ready_planner_
|
||||
assert.equal(remap.satisfied.includes("fiveaxis-remap-machine-file-run"), true);
|
||||
assert.equal(remap.evidence.machineFileFlags.length, 3);
|
||||
|
||||
const gmoccapyMachineFile = createFullLinuxCncExecutionBoundary({
|
||||
...canonicalState,
|
||||
programExecution: {
|
||||
...canonicalState.programExecution,
|
||||
plannerTiming: {
|
||||
plannerRuntimeReady: true,
|
||||
semanticBoundary: "linuxcnc_tp_queue_runtime_timing_from_canonical_motion",
|
||||
},
|
||||
summary: {
|
||||
...canonicalState.programExecution.summary,
|
||||
plannerRuntimeReady: true,
|
||||
},
|
||||
},
|
||||
machineFileStaging: {
|
||||
status: "staged",
|
||||
fileCount: 18,
|
||||
},
|
||||
machineFileExecution: {
|
||||
sourceMode: "linuxcnc-machine-file-remap-wasm",
|
||||
summary: {
|
||||
machineFileExecutionReady: true,
|
||||
remapRuntimeReady: false,
|
||||
},
|
||||
resultText: [
|
||||
"fiveaxis_parse_remap_1=5",
|
||||
"fiveaxis_parse_remap_2=5",
|
||||
"fiveaxis_remaps_ready=0",
|
||||
"fiveaxis_file_reached_exit=1",
|
||||
"fiveaxis_linuxcnc_remap_file_execute=0",
|
||||
].join("\n"),
|
||||
},
|
||||
});
|
||||
|
||||
assert.equal(gmoccapyMachineFile.machineFileBackedRemapReady, true);
|
||||
assert.equal(gmoccapyMachineFile.remapRuntimeReady, false);
|
||||
assert.equal(gmoccapyMachineFile.semanticBoundary, "linuxcnc_machine_file_remap_ready_planner_task_hal_blocked");
|
||||
assert.equal(gmoccapyMachineFile.satisfied.includes("fiveaxis-remap-machine-file-run"), true);
|
||||
assert.equal(gmoccapyMachineFile.evidence.machineFileFlags.length, 1);
|
||||
|
||||
const taskHalPromoted = createFullLinuxCncExecutionBoundary({
|
||||
...canonicalState,
|
||||
programExecution: remap.programExecution || {
|
||||
@@ -153,6 +194,18 @@ const taskHalPromoted = createFullLinuxCncExecutionBoundary({
|
||||
halChangedPinCount: 4,
|
||||
},
|
||||
},
|
||||
toolDbReadiness: {
|
||||
toolDbProcessReady: true,
|
||||
toolDbProcessScope: "web_simulation_only",
|
||||
hostToolDbProcessReady: false,
|
||||
toolCount: 10,
|
||||
},
|
||||
controlledUserMReadiness: {
|
||||
externalUserMProcessReady: true,
|
||||
externalUserMProcessScope: "web_simulation_only",
|
||||
hostExternalUserMProcessReady: false,
|
||||
arbitraryUserMExecution: false,
|
||||
},
|
||||
});
|
||||
|
||||
assert.equal(taskHalPromoted.semanticBoundary, "linuxcnc_task_motion_hal_wasm_simulation_runtime");
|
||||
@@ -162,8 +215,15 @@ assert.equal(taskHalPromoted.fullLinuxCncProgramExecutionReady, true);
|
||||
assert.equal(taskHalPromoted.promotionAllowed, true);
|
||||
assert.equal(taskHalPromoted.hardwareDrive, false);
|
||||
assert.equal(taskHalPromoted.hostRealtimeKernel, false);
|
||||
assert.equal(taskHalPromoted.externalUserMProcessReady, false);
|
||||
assert.equal(taskHalPromoted.toolDbProcessReady, false);
|
||||
assert.equal(taskHalPromoted.externalUserMProcessReady, true);
|
||||
assert.equal(taskHalPromoted.externalUserMProcessScope, "web_simulation_only");
|
||||
assert.equal(taskHalPromoted.toolDbProcessReady, true);
|
||||
assert.equal(taskHalPromoted.toolDbProcessScope, "web_simulation_only");
|
||||
assert.equal(taskHalPromoted.hostExternalUserMProcessReady, false);
|
||||
assert.equal(taskHalPromoted.hostToolDbProcessReady, false);
|
||||
assert.equal(taskHalPromoted.arbitraryUserMExecution, false);
|
||||
assert.equal(taskHalPromoted.satisfied.includes("tool-db-web-simulation"), true);
|
||||
assert.equal(taskHalPromoted.satisfied.includes("controlled-user-m-web-simulation"), true);
|
||||
assert.equal(taskHalPromoted.evidence.taskCycle, 2);
|
||||
|
||||
console.log("full_execution_boundary_smoke=ok");
|
||||
|
||||
@@ -107,7 +107,12 @@ assert.deepEqual(taskModeControls.map((control) => [control.id, control.halpin])
|
||||
["rbt-auto", "gmoccapy.v-button.button-4"],
|
||||
]);
|
||||
|
||||
assert.deepEqual(fiveAxisProfiles.map(({ id }) => id), ["xyzac-trt", "xyzbc-trt", "gmoccapy-xyzab"]);
|
||||
assert.deepEqual(fiveAxisProfiles.map(({ id }) => id), [
|
||||
"xyzac-trt",
|
||||
"xyzbc-trt",
|
||||
"gmoccapy-xyzac-trt",
|
||||
"gmoccapy-xyzab",
|
||||
]);
|
||||
|
||||
const sourceSummary = createProfileSourceReferenceSummary("gmoccapy-xyzab");
|
||||
assert.equal(sourceSummary.profileId, "gmoccapy-xyzab");
|
||||
|
||||
@@ -125,6 +125,29 @@ for (const filename of DIRECT_PROGRAM_EXAMPLES) {
|
||||
assert.equal(execution.summary.motionEventCount > 0, true, `${filename} motion`);
|
||||
assert.equal(execution.plannerTiming.samples.length > 0, true, `${filename} planner samples`);
|
||||
}
|
||||
|
||||
const boatMachineFilePlan = selectMachineFileProgram(
|
||||
staged.plan,
|
||||
staged.save,
|
||||
`${GMOCAPY_TRT_EXAMPLE_SOURCE_PREFIX}boat-xyzac.ngc`,
|
||||
);
|
||||
const boatMachineFileExecution = runtime.runMachineFileProgram({
|
||||
plan: boatMachineFilePlan,
|
||||
files: staged.save.files,
|
||||
executionMode: "fiveAxisRemap",
|
||||
});
|
||||
const boatRapidAfterToolChange = boatMachineFileExecution.motion.find((event) => (
|
||||
event.type === "STRAIGHT_TRAVERSE" && event.line === 12
|
||||
));
|
||||
assert.equal(boatMachineFileExecution.sourceMode, "linuxcnc-machine-file-remap-wasm");
|
||||
assert.equal(boatMachineFileExecution.summary.machineFileExecutionReady, true);
|
||||
assert.equal(boatMachineFileExecution.summary.motionEventCount, 1833);
|
||||
assert.equal(boatMachineFileExecution.plannerTiming.samples.length > 0, true);
|
||||
assert.ok(boatRapidAfterToolChange, "boat-xyzac line 12 rapid move");
|
||||
assert.equal(boatRapidAfterToolChange.axes.x, -49.65);
|
||||
assert.equal(boatRapidAfterToolChange.axes.y, -23.015);
|
||||
assert.equal(boatRapidAfterToolChange.axes.z, 5);
|
||||
|
||||
for (const { filename, subroutine, rotaryAxis } of NGC_GUI_SUBROUTINE_EXAMPLES) {
|
||||
const source = staged.save.files.find((file) => file.sourceRel.endsWith(`/examples/${filename}`));
|
||||
assert.ok(source, `${filename} staged`);
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import assert from "node:assert/strict";
|
||||
import { readFileSync } from "node:fs";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
import { createLinuxCncInterpreterRuntime } from "../../app/src/runtime/linuxcnc-interpreter-runtime.js";
|
||||
|
||||
@@ -103,4 +105,17 @@ assert.equal(switchkinsExecution.summary.plannerRuntimeReady, true);
|
||||
assert.equal(switchkinsExecution.plannerTiming.totalSeconds > 0, true);
|
||||
assert.equal(switchkinsExecution.summary.fullLinuxCncProgramExecutionReady, false);
|
||||
|
||||
const gmoccapyImpellerProgram = readFileSync(fileURLToPath(new URL(
|
||||
"../../../linuxcnc/configs/sim/gmoccapy/non_trivial_kinematics/table-rotary-tilting/examples/impeller-7bl-xyzac.ngc",
|
||||
import.meta.url,
|
||||
)), "utf8");
|
||||
const gmoccapyImpellerExecution = runtime.runProgram(gmoccapyImpellerProgram);
|
||||
const firstG93FeedMotion = gmoccapyImpellerExecution.motion.find((event) => event.type === "STRAIGHT_FEED");
|
||||
|
||||
assert.equal(gmoccapyImpellerExecution.summary.ready, true);
|
||||
assert.equal(gmoccapyImpellerExecution.motion[0].feedMode, "inverse-time");
|
||||
assert.equal(firstG93FeedMotion.line, 9);
|
||||
assert.equal(Math.abs(firstG93FeedMotion.feedRate - 635.745) < 0.001, true);
|
||||
assert.notEqual(firstG93FeedMotion.feedRate, 318);
|
||||
|
||||
console.log("linuxcnc_interpreter_runtime_smoke=ok");
|
||||
|
||||
@@ -1,52 +1,126 @@
|
||||
import assert from "node:assert/strict";
|
||||
|
||||
import { getFiveAxisProfile } from "../../app/src/profiles/index.js";
|
||||
import { createLinuxCncKinematicsRuntime } from "../../app/src/runtime/linuxcnc-kinematics-runtime.js";
|
||||
import { buildRtcpFrame } from "../../app/src/runtime/rtcp-frame.js";
|
||||
|
||||
const runtime = await createLinuxCncKinematicsRuntime({ moduleId: "xyzac-trt" });
|
||||
const readiness = runtime.readiness();
|
||||
const DEG_TO_RAD = Math.PI / 180;
|
||||
|
||||
assert.equal(runtime.apiName, "web-rtcp-5axis-linuxcnc-kinematics-runtime");
|
||||
assert.equal(runtime.moduleId, "xyzac-trt");
|
||||
assert.equal(runtime.loaded, true);
|
||||
assert.equal(runtime.sourceMode, "source-derived-kinematics-wasm");
|
||||
assert.equal(runtime.semanticBoundary, "linuxcnc_kinematics_wasm_c_abi");
|
||||
assert.equal(runtime.executionContext, "direct");
|
||||
assert.equal(runtime.wasmFile, "linuxcnc_xyzac_trt_kinematics.wasm");
|
||||
assert.equal(readiness.loaded, true);
|
||||
assert.equal(readiness.executionContext, "direct");
|
||||
assert.equal(readiness.supportedModules.includes("xyzac-trt"), true);
|
||||
assert.equal(runtime.switchRc, 0);
|
||||
const cases = [
|
||||
{
|
||||
moduleId: "xyzac-trt",
|
||||
wasmFile: "linuxcnc_xyzac_trt_kinematics.wasm",
|
||||
joints: [10, 20, 30, 25, 40],
|
||||
fourthAxis: "A",
|
||||
fourthKey: "a",
|
||||
axisPose: { x: 10, y: 20, z: 30, a: 25, b: 0, c: 40 },
|
||||
kinsType: "tcp-xyzac",
|
||||
expectedToolAxis: xyzacToolAxis(25, 40),
|
||||
},
|
||||
{
|
||||
moduleId: "xyzbc-trt",
|
||||
wasmFile: "linuxcnc_xyzbc_trt_kinematics.wasm",
|
||||
joints: [10, 20, 30, 35, 40],
|
||||
fourthAxis: "B",
|
||||
fourthKey: "b",
|
||||
axisPose: { x: 10, y: 20, z: 30, a: 0, b: 35, c: 40 },
|
||||
kinsType: "tcp-xyzbc",
|
||||
expectedToolAxis: xyzbcToolAxis(35, 40),
|
||||
},
|
||||
];
|
||||
|
||||
const linuxCncKinematicsResult = runtime.frameForJoints([10, 20, 30, 25, 40]);
|
||||
assert.equal(linuxCncKinematicsResult.moduleId, "xyzac-trt");
|
||||
assert.equal(linuxCncKinematicsResult.forward.rc, 0);
|
||||
assert.equal(linuxCncKinematicsResult.inverse.rc, 0);
|
||||
assert.deepEqual(
|
||||
linuxCncKinematicsResult.inverse.joints.map((value) => Math.round(value * 1e6) / 1e6),
|
||||
[10, 20, 30, 25, 40],
|
||||
);
|
||||
for (const testCase of cases) {
|
||||
const runtime = await createLinuxCncKinematicsRuntime({
|
||||
moduleId: testCase.moduleId,
|
||||
switchkinsType: 1,
|
||||
});
|
||||
const readiness = runtime.readiness();
|
||||
|
||||
const frame = buildRtcpFrame({
|
||||
axisPose: { x: 10, y: 20, z: 30, a: 25, b: 0, c: 40 },
|
||||
activeLine: 777,
|
||||
kinsType: "tcp-xyzac",
|
||||
rtcpEnabled: true,
|
||||
linuxCncKinematicsResult,
|
||||
});
|
||||
assert.equal(runtime.apiName, "web-rtcp-5axis-linuxcnc-kinematics-runtime");
|
||||
assert.equal(runtime.moduleId, testCase.moduleId);
|
||||
assert.equal(runtime.loaded, true);
|
||||
assert.equal(runtime.sourceMode, "source-derived-kinematics-wasm");
|
||||
assert.equal(runtime.semanticBoundary, "linuxcnc_kinematics_wasm_c_abi");
|
||||
assert.equal(runtime.executionContext, "direct");
|
||||
assert.equal(runtime.wasmFile, testCase.wasmFile);
|
||||
assert.equal(runtime.switchkinsType, 1);
|
||||
assert.equal(readiness.loaded, true);
|
||||
assert.equal(readiness.executionContext, "direct");
|
||||
assert.equal(readiness.supportedModules.includes("xyzac-trt"), true);
|
||||
assert.equal(readiness.supportedModules.includes("xyzbc-trt"), true);
|
||||
assert.equal(runtime.switchRc, 0);
|
||||
|
||||
assert.equal(frame.sourceMode, "source-derived-kinematics-wasm");
|
||||
assert.equal(frame.semanticBoundary, "linuxcnc_kinematics_wasm_c_abi");
|
||||
assert.equal(frame.readiness.linuxCncKinematicsReady, true);
|
||||
assert.equal(frame.readiness.promotionAllowed, true);
|
||||
assert.equal(frame.readiness.fullLinuxCncProgramExecutionReady, false);
|
||||
assert.equal(frame.kinematicsModuleId, "xyzac-trt");
|
||||
assert.equal(frame.kinematicsForwardRc, 0);
|
||||
assert.equal(frame.kinematicsInverseRc, 0);
|
||||
assert.equal(frame.jointPose[3].value, 25);
|
||||
assert.equal(frame.jointPose[4].value, 40);
|
||||
assert.equal(frame.tcpPose.x, linuxCncKinematicsResult.forward.pose.x);
|
||||
assert.equal(frame.tcpPose.y, linuxCncKinematicsResult.forward.pose.y);
|
||||
assert.equal(frame.tcpPose.z, linuxCncKinematicsResult.forward.pose.z);
|
||||
const linuxCncKinematicsResult = runtime.frameForJoints(testCase.joints);
|
||||
assert.equal(linuxCncKinematicsResult.moduleId, testCase.moduleId);
|
||||
assert.equal(linuxCncKinematicsResult.switchkinsType, 1);
|
||||
assert.equal(linuxCncKinematicsResult.forward.rc, 0);
|
||||
assert.equal(linuxCncKinematicsResult.inverse.rc, 0);
|
||||
assert.deepEqual(roundJoints(linuxCncKinematicsResult.inverse.joints), testCase.joints);
|
||||
|
||||
const frame = buildRtcpFrame({
|
||||
axisPose: testCase.axisPose,
|
||||
activeLine: 777,
|
||||
kinsType: testCase.kinsType,
|
||||
rtcpEnabled: true,
|
||||
profile: getFiveAxisProfile(testCase.moduleId),
|
||||
linuxCncKinematicsResult,
|
||||
});
|
||||
|
||||
assert.equal(frame.sourceMode, "source-derived-kinematics-wasm");
|
||||
assert.equal(frame.semanticBoundary, "linuxcnc_kinematics_wasm_c_abi");
|
||||
assert.equal(frame.readiness.linuxCncKinematicsReady, true);
|
||||
assert.equal(frame.readiness.promotionAllowed, true);
|
||||
assert.equal(frame.readiness.fullLinuxCncProgramExecutionReady, false);
|
||||
assert.equal(frame.profileId, testCase.moduleId);
|
||||
assert.equal(frame.kinematicsModuleId, testCase.moduleId);
|
||||
assert.equal(frame.kinematicsSwitchkinsType, 1);
|
||||
assert.equal(frame.kinematicsForwardRc, 0);
|
||||
assert.equal(frame.kinematicsInverseRc, 0);
|
||||
assert.equal(frame.jointPose[3].axis, testCase.fourthAxis);
|
||||
assert.equal(frame.jointPose[3].value, testCase.joints[3]);
|
||||
assert.equal(frame.jointPose[4].axis, "C");
|
||||
assert.equal(frame.jointPose[4].value, testCase.joints[4]);
|
||||
assert.equal(frame.tcpPose.x, linuxCncKinematicsResult.forward.pose.x);
|
||||
assert.equal(frame.tcpPose.y, linuxCncKinematicsResult.forward.pose.y);
|
||||
assert.equal(frame.tcpPose.z, linuxCncKinematicsResult.forward.pose.z);
|
||||
assert.equal(frame.tcpPose.a, linuxCncKinematicsResult.forward.pose.a);
|
||||
assert.equal(frame.tcpPose.b, linuxCncKinematicsResult.forward.pose.b);
|
||||
assert.equal(frame.tcpPose.c, linuxCncKinematicsResult.forward.pose.c);
|
||||
assert.equal(frame.tcpPose[testCase.fourthKey], testCase.axisPose[testCase.fourthKey]);
|
||||
assertVectorNear(frame.toolAxisVector, testCase.expectedToolAxis);
|
||||
|
||||
console.log(`${testCase.moduleId.replace(/-/g, "_")}_kinematics_runtime=ok`);
|
||||
}
|
||||
|
||||
console.log("linuxcnc_kinematics_runtime_smoke=ok");
|
||||
console.log("xyzbc_b_axis_tcp_pose_preserved=1");
|
||||
|
||||
function roundJoints(joints) {
|
||||
return joints.map((value) => Math.round(value * 1e6) / 1e6);
|
||||
}
|
||||
|
||||
function xyzacToolAxis(aDegrees, cDegrees) {
|
||||
const tilt = aDegrees * DEG_TO_RAD;
|
||||
const c = cDegrees * DEG_TO_RAD;
|
||||
return {
|
||||
x: Math.sin(tilt) * Math.sin(c),
|
||||
y: -Math.sin(tilt) * Math.cos(c),
|
||||
z: Math.cos(tilt),
|
||||
};
|
||||
}
|
||||
|
||||
function xyzbcToolAxis(bDegrees, cDegrees) {
|
||||
const tilt = bDegrees * DEG_TO_RAD;
|
||||
const c = cDegrees * DEG_TO_RAD;
|
||||
return {
|
||||
x: Math.sin(tilt) * Math.cos(c),
|
||||
y: Math.sin(tilt) * Math.sin(c),
|
||||
z: Math.cos(tilt),
|
||||
};
|
||||
}
|
||||
|
||||
function assertVectorNear(actual, expected, tolerance = 1e-12) {
|
||||
assert.ok(Math.abs(actual.x - expected.x) < tolerance);
|
||||
assert.ok(Math.abs(actual.y - expected.y) < tolerance);
|
||||
assert.ok(Math.abs(actual.z - expected.z) < tolerance);
|
||||
}
|
||||
|
||||
@@ -75,6 +75,14 @@ assert.equal(state.machineFileStaging.save.summary.gcodeFileCount, 16);
|
||||
assert.equal(state.machineFileStaging.save.summary.kinds.remap >= 3, true);
|
||||
assert.equal(state.machineFileStaging.gcodeSources.length >= 4, true);
|
||||
assert.equal(state.machineFileStaging.selectedGcodeSourceRel, null);
|
||||
assert.equal(state.toolDbReadiness.toolDbProcessReady, true);
|
||||
assert.equal(state.toolDbReadiness.toolDbProcessScope, "web_simulation_only");
|
||||
assert.equal(state.toolDbReadiness.hostToolDbProcessReady, false);
|
||||
assert.equal(state.toolDbReadiness.toolCount, 10);
|
||||
assert.equal(state.toolDbSimulation.toolTable.entries[1].toolNumber, 2);
|
||||
assert.equal(state.toolDbSimulation.toolTable.entries[1].offset.z, 15);
|
||||
assert.equal(state.controlledUserMReadiness.externalUserMProcessReady, true);
|
||||
assert.equal(state.controlledUserMReadiness.externalUserMProcessScope, "web_simulation_only");
|
||||
|
||||
store.dispatch({ type: "RUN_MACHINE_FILE_PROGRAM" });
|
||||
assert.equal(
|
||||
@@ -102,6 +110,8 @@ assert.equal(sourceState.activeProgram.endsWith("impeller-7bl-xyzac.ngc"), true)
|
||||
assert.equal(sourceState.programLines[0].includes("Impeller 5-axis"), true);
|
||||
assert.equal(sourceState.machineFileStaging.selectedGcodeSourceRel.endsWith("impeller-7bl-xyzac.ngc"), true);
|
||||
assert.equal(sourceState.machineFileStaging.plan.wasmProgramPath.endsWith("/demos/impeller-7bl-xyzac.ngc"), true);
|
||||
assert.equal(sourceState.toolDbReadiness.toolDbProcessReady, true);
|
||||
assert.equal(sourceState.controlledUserMReadiness.externalUserMProcessReady, true);
|
||||
|
||||
store.dispatch({ type: "RUN_MACHINE_FILE_PROGRAM" });
|
||||
const runState = await waitForMachineFileExecution(store);
|
||||
@@ -109,8 +119,9 @@ assert.equal(runState.machineFileExecution.sourceMode, "linuxcnc-machine-file-re
|
||||
assert.equal(runState.machineFileExecution.semanticBoundary, "linuxcnc_fiveaxis_remap_wasm_machine_file_execution");
|
||||
assert.equal(runState.machineFileExecution.summary.machineFileExecutionReady, true);
|
||||
assert.equal(runState.machineFileExecution.summary.remapRuntimeReady, true);
|
||||
assert.equal(runState.machineFileExecution.summary.plannerRuntimeReady, false);
|
||||
assert.equal(runState.machineFileExecution.summary.plannerRuntimeReady, true);
|
||||
assert.equal(runState.machineFileExecution.summary.fullLinuxCncProgramExecutionReady, false);
|
||||
assert.equal(runState.machineFileExecution.plannerTiming.samples.length > 0, true);
|
||||
assert.equal(runState.machineFileExecution.resultText.includes("fiveaxis_ini_open=1"), true);
|
||||
assert.equal(runState.machineFileExecution.resultText.includes("fiveaxis_remaps_ready=1"), true);
|
||||
assert.equal(runState.machineFileExecution.resultText.includes("fiveaxis_file_reached_exit=1"), true);
|
||||
@@ -120,7 +131,7 @@ assert.equal(runState.fullExecutionBoundary.apiName, "web-rtcp-5axis-full-linuxc
|
||||
assert.equal(runState.fullExecutionBoundary.machineFileBackedRemapReady, true);
|
||||
assert.equal(runState.fullExecutionBoundary.remapRuntimeReady, true);
|
||||
assert.equal(runState.fullExecutionBoundary.halSwitchkinsEvidenceReady, true);
|
||||
assert.equal(runState.fullExecutionBoundary.plannerRuntimeReady, false);
|
||||
assert.equal(runState.fullExecutionBoundary.plannerRuntimeReady, true);
|
||||
assert.equal(runState.fullExecutionBoundary.nativeTaskReady, false);
|
||||
assert.equal(runState.fullExecutionBoundary.nativeHalSyncReady, false);
|
||||
assert.equal(runState.fullExecutionBoundary.fullLinuxCncProgramExecutionReady, false);
|
||||
@@ -131,7 +142,7 @@ assert.equal(
|
||||
);
|
||||
assert.equal(runState.fullExecutionBoundary.satisfied.includes("fiveaxis-remap-machine-file-run"), true);
|
||||
assert.equal(runState.fullExecutionBoundary.satisfied.includes("switchkins-hal-bridge-evidence"), true);
|
||||
assert.equal(runState.fullExecutionBoundary.blockers.some((blocker) => blocker.includes("trajectory planner")), true);
|
||||
assert.equal(runState.fullExecutionBoundary.satisfied.includes("linuxcnc-tp-queue-runtime-timing"), true);
|
||||
|
||||
globalThis.__WEB_RTCP_FORCE_OPFS_UNAVAILABLE__ = true;
|
||||
const fallbackStore = createSimulationStore();
|
||||
@@ -142,6 +153,7 @@ assert.equal(fallbackStage.save.storageCapability.opfsUnavailable, true);
|
||||
assert.equal(fallbackStage.save.storageCapability.reason, "forced_unavailable");
|
||||
assert.equal(fallbackState.machineFileStaging.status, "staged");
|
||||
assert.equal(fallbackState.machineFileStaging.storageMode, "memory-fallback");
|
||||
assert.equal(fallbackState.toolDbReadiness.toolDbProcessReady, true);
|
||||
assert.equal(fallbackState.operatorMessage.includes("staged"), true);
|
||||
delete globalThis.__WEB_RTCP_FORCE_OPFS_UNAVAILABLE__;
|
||||
|
||||
|
||||
@@ -64,6 +64,14 @@ assert.equal(audit.nativeHostAndHardware.hardwareDrive, false);
|
||||
assert.equal(audit.nativeHostAndHardware.hostRealtimeKernel, false);
|
||||
assert.equal(audit.nativeHostAndHardware.externalUserMProcessReady, false);
|
||||
assert.equal(audit.nativeHostAndHardware.toolDbProcessReady, false);
|
||||
assert.equal(audit.nativeHostAndHardware.hostExternalUserMProcessReady, false);
|
||||
assert.equal(audit.nativeHostAndHardware.hostToolDbProcessReady, false);
|
||||
assert.equal(audit.nativeHostAndHardware.arbitraryUserMExecution, false);
|
||||
assert.equal(audit.toolUserWebSimulation.externalUserMProcessReady, true);
|
||||
assert.equal(audit.toolUserWebSimulation.externalUserMProcessScope, "web_simulation_only");
|
||||
assert.equal(audit.toolUserWebSimulation.toolDbProcessReady, true);
|
||||
assert.equal(audit.toolUserWebSimulation.toolDbProcessScope, "web_simulation_only");
|
||||
assert.equal(audit.toolUserWebSimulation.ready, true);
|
||||
assert.equal(audit.sourceManifest.ready, true);
|
||||
assert.equal(audit.sourceManifest.taskSourceCount > 0, true);
|
||||
assert.equal(audit.sourceManifest.halSourceCount > 0, true);
|
||||
@@ -71,8 +79,10 @@ assert.equal(audit.sourceManifest.motionSourceCount > 0, true);
|
||||
assert.equal(audit.gates.task_hal_web_simulation_boundary_consistent, 1);
|
||||
assert.equal(audit.gates.hardware_drive, 0);
|
||||
assert.equal(audit.gates.host_realtime_kernel, 0);
|
||||
assert.equal(audit.gates.external_user_m_process_ready, 0);
|
||||
assert.equal(audit.gates.tool_db_process_ready, 0);
|
||||
assert.equal(audit.gates.external_user_m_process_ready, 1);
|
||||
assert.equal(audit.gates.tool_db_process_ready, 1);
|
||||
assert.equal(audit.gates.host_external_user_m_process_ready, 0);
|
||||
assert.equal(audit.gates.host_tool_db_process_ready, 0);
|
||||
assert.equal(audit.gates.promotion_scope, "web_simulation_only");
|
||||
|
||||
mkdirSync(artifactDir, { recursive: true });
|
||||
@@ -88,8 +98,10 @@ console.log("task_hal_web_simulation_boundary_consistent=1");
|
||||
console.log(`native_task_hal_host_probe_status=${audit.nativeHostAndHardware.nativeProbeStatus}`);
|
||||
console.log("hardware_drive=0");
|
||||
console.log("host_realtime_kernel=0");
|
||||
console.log("external_user_m_process_ready=0");
|
||||
console.log("tool_db_process_ready=0");
|
||||
console.log("external_user_m_process_ready=1");
|
||||
console.log("tool_db_process_ready=1");
|
||||
console.log("host_external_user_m_process_ready=0");
|
||||
console.log("host_tool_db_process_ready=0");
|
||||
console.log("promotion_scope=web_simulation_only");
|
||||
|
||||
function createPromotedSimulationState() {
|
||||
@@ -156,6 +168,18 @@ function createPromotedSimulationState() {
|
||||
halChangedPinCount: 4,
|
||||
},
|
||||
},
|
||||
toolDbReadiness: {
|
||||
toolDbProcessReady: true,
|
||||
toolDbProcessScope: "web_simulation_only",
|
||||
hostToolDbProcessReady: false,
|
||||
toolCount: 10,
|
||||
},
|
||||
controlledUserMReadiness: {
|
||||
externalUserMProcessReady: true,
|
||||
externalUserMProcessScope: "web_simulation_only",
|
||||
hostExternalUserMProcessReady: false,
|
||||
arbitraryUserMExecution: false,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -30,7 +30,12 @@ assert.equal(xyzacTrtProfile.halPins.includes("motion.switchkins-type"), true);
|
||||
assert.equal(xyzacTrtProfile.halPins.includes("xyzac-trt-kins.tool-offset"), true);
|
||||
assert.equal(xyzacTrtProfile.promotionAllowed, false);
|
||||
assert.equal(xyzacTrtProfile.linuxCncKinematicsReady, false);
|
||||
assert.deepEqual(fiveAxisProfiles.map(({ id }) => id), ["xyzac-trt", "xyzbc-trt", "gmoccapy-xyzab"]);
|
||||
assert.deepEqual(fiveAxisProfiles.map(({ id }) => id), [
|
||||
"xyzac-trt",
|
||||
"xyzbc-trt",
|
||||
"gmoccapy-xyzac-trt",
|
||||
"gmoccapy-xyzab",
|
||||
]);
|
||||
|
||||
const xyzbcTrtProfile = getFiveAxisProfile("xyzbc-trt");
|
||||
assert.equal(xyzbcTrtProfile.id, "xyzbc-trt");
|
||||
@@ -59,6 +64,18 @@ assert.equal(xyzbcSourceSummary.referenceCount >= 7, true);
|
||||
assert.ok(xyzbcSourceSummary.references.some((reference) => reference.path.endsWith("xyzbc-trt.ini")));
|
||||
assert.ok(xyzbcSourceSummary.references.some((reference) => reference.path.endsWith("xyzbc-trt-kins.c")));
|
||||
|
||||
const gmoccapyXyzacTrtProfile = getFiveAxisProfile("gmoccapy-xyzac-trt");
|
||||
assert.equal(gmoccapyXyzacTrtProfile.id, "gmoccapy-xyzac-trt");
|
||||
assert.equal(gmoccapyXyzacTrtProfile.display.display, "gmoccapy");
|
||||
assert.equal(gmoccapyXyzacTrtProfile.kinematics, "xyzac-trt-kins");
|
||||
assert.equal(gmoccapyXyzacTrtProfile.kinematicsModuleId, "xyzac-trt");
|
||||
assert.equal(gmoccapyXyzacTrtProfile.rtcpProof, true);
|
||||
assert.equal(gmoccapyXyzacTrtProfile.kinematicsParameters.fixedTrtDefault, true);
|
||||
const gmoccapyTrtSourceSummary = createProfileSourceReferenceSummary("gmoccapy-xyzac-trt");
|
||||
assert.equal(gmoccapyTrtSourceSummary.referenceCount >= 10, true);
|
||||
assert.ok(gmoccapyTrtSourceSummary.references.some((reference) => reference.path.endsWith("non_trivial_kinematics/table-rotary-tilting/xyzac-trt.ini")));
|
||||
assert.ok(gmoccapyTrtSourceSummary.references.some((reference) => reference.path.endsWith("examples/impeller-7bl-xyzac.ngc")));
|
||||
|
||||
const gmoccapyXyzabProfile = getFiveAxisProfile("gmoccapy-xyzab");
|
||||
assert.equal(gmoccapyXyzabProfile.id, "gmoccapy-xyzab");
|
||||
assert.deepEqual(gmoccapyXyzabProfile.coordinates, ["X", "Y", "Z", "A", "B"]);
|
||||
|
||||
@@ -268,7 +268,7 @@ const store = createSimulationStore();
|
||||
let state;
|
||||
assert.deepEqual(
|
||||
store.getState().availableProfiles.map((profile) => profile.id),
|
||||
["xyzac-trt", "xyzbc-trt", "gmoccapy-xyzab"],
|
||||
["xyzac-trt", "xyzbc-trt", "gmoccapy-xyzac-trt", "gmoccapy-xyzab"],
|
||||
);
|
||||
store.dispatch({ type: "SET_PROFILE", profileId: "xyzbc-trt" });
|
||||
assert.equal(store.getState().machineProfile, "xyzbc-trt");
|
||||
@@ -282,6 +282,9 @@ state = store.getState();
|
||||
assert.equal(state.kinsType, "tcp-xyzbc");
|
||||
assert.equal(state.rtcpFrame.kinematicsModuleId, "xyzbc-trt");
|
||||
assert.equal(state.rtcpFrame.jointPose[3].axis, "B");
|
||||
assert.equal(Number.isFinite(state.tcpPose.b), true);
|
||||
assert.equal(state.rtcpFrame.tcpPose.b, state.tcpPose.b);
|
||||
assert.equal(state.rtcpFrame.tcpPose.b, state.rtcpFrame.axisPose.b);
|
||||
|
||||
store.dispatch({ type: "SET_PROFILE", profileId: "xyzac-trt" });
|
||||
store.dispatch({ type: "RESET" });
|
||||
|
||||
@@ -0,0 +1,142 @@
|
||||
import assert from "node:assert/strict";
|
||||
import { readFile } from "node:fs/promises";
|
||||
|
||||
import { createMemorySessionStorage } from "../../app/src/runtime/five-axis-session.js";
|
||||
import {
|
||||
applyToolCommandSequence,
|
||||
createToolDbReadiness,
|
||||
createToolDbSimulation,
|
||||
editToolEntry,
|
||||
parseLinuxCncToolTable,
|
||||
queryToolEntry,
|
||||
saveToolDbSimulation,
|
||||
} from "../../app/src/runtime/tool-db-simulation.js";
|
||||
import {
|
||||
createControlledUserMReadiness,
|
||||
createControlledUserMSimulation,
|
||||
runControlledUserM,
|
||||
runControlledUserMProgramScan,
|
||||
} from "../../app/src/runtime/controlled-user-m-simulation.js";
|
||||
import { getFiveAxisProfile } from "../../app/src/profiles/index.js";
|
||||
|
||||
const profile = getFiveAxisProfile("xyzac-trt");
|
||||
const toolTableText = await readFile(
|
||||
new URL("../../../linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzac-trt.tbl", import.meta.url),
|
||||
"utf8",
|
||||
);
|
||||
|
||||
const parsed = parseLinuxCncToolTable(toolTableText, {
|
||||
sourceRel: profile.toolTablePath,
|
||||
});
|
||||
assert.equal(parsed.apiName, "web-rtcp-5axis-tool-table");
|
||||
assert.equal(parsed.toolCount, 10);
|
||||
assert.equal(parsed.entries[0].toolNumber, 1);
|
||||
assert.equal(parsed.entries[0].pocket, 1);
|
||||
assert.equal(parsed.entries[1].offset.z, 15);
|
||||
assert.equal(parsed.entries[1].diameter, 8);
|
||||
assert.equal(parsed.semanticBoundary, "linuxcnc_tool_table_text_parsed_for_web_simulation");
|
||||
|
||||
let toolDb = createToolDbSimulation({
|
||||
toolTable: parsed,
|
||||
profile,
|
||||
storageMode: "memory",
|
||||
});
|
||||
assert.equal(toolDb.processReady, true);
|
||||
assert.equal(toolDb.processScope, "web_simulation_only");
|
||||
assert.equal(toolDb.hostProcessReady, false);
|
||||
assert.equal(createToolDbReadiness(toolDb).toolDbProcessReady, true);
|
||||
assert.equal(createToolDbReadiness(toolDb).hostProcessExecution, false);
|
||||
|
||||
toolDb = applyToolCommandSequence(toolDb, [
|
||||
{ code: "T", toolNumber: 2 },
|
||||
{ code: "M6" },
|
||||
{ code: "G43", h: 2 },
|
||||
]);
|
||||
assert.equal(toolDb.toolInSpindle, 2);
|
||||
assert.equal(toolDb.toolFromPocket, 2);
|
||||
assert.equal(toolDb.activeToolOffset.toolNumber, 2);
|
||||
assert.equal(toolDb.activeToolOffset.offset.z, 15);
|
||||
assert.equal(toolDb.iocontrol.toolNumber, 2);
|
||||
assert.equal(toolDb.events.some((event) => event.code === "M6"), true);
|
||||
|
||||
toolDb = applyToolCommandSequence(toolDb, [{ code: "M61", q: 4 }]);
|
||||
assert.equal(toolDb.toolInSpindle, 4);
|
||||
assert.equal(toolDb.iocontrol.toolNumber, 4);
|
||||
|
||||
toolDb = editToolEntry(toolDb, {
|
||||
toolNumber: 4,
|
||||
pocket: 44,
|
||||
diameter: 12.5,
|
||||
offset: { z: 42.25 },
|
||||
comment: "edited by web simulation",
|
||||
});
|
||||
const editedTool = queryToolEntry(toolDb, { toolNumber: 4 });
|
||||
assert.equal(editedTool.pocket, 44);
|
||||
assert.equal(editedTool.diameter, 12.5);
|
||||
assert.equal(editedTool.offset.z, 42.25);
|
||||
|
||||
const storage = createMemorySessionStorage();
|
||||
const save = await saveToolDbSimulation(toolDb, {
|
||||
storage,
|
||||
storageMode: "memory",
|
||||
});
|
||||
assert.equal(save.semanticBoundary, "tool_table_saved_in_web_storage_boundary");
|
||||
assert.equal(save.text.includes("T4 P44 D+12.500000 Z+42.250000 ;edited by web simulation"), true);
|
||||
assert.equal(storage.files.get(save.path), save.text);
|
||||
|
||||
let userM = createControlledUserMSimulation();
|
||||
assert.equal(createControlledUserMReadiness(userM).externalUserMProcessReady, true);
|
||||
assert.equal(createControlledUserMReadiness(userM).hostProcessExecution, false);
|
||||
|
||||
let result = runControlledUserM(userM, "M428", { profile });
|
||||
userM = result.simulation;
|
||||
assert.equal(result.event.allowed, true);
|
||||
assert.equal(result.statePatch.kinsType, "tcp-xyzac");
|
||||
assert.equal(result.statePatch.rtcpState, "on");
|
||||
assert.equal(result.halPatch["motion.switchkins-type"], 1);
|
||||
|
||||
result = runControlledUserM(userM, "M429", { profile });
|
||||
userM = result.simulation;
|
||||
assert.equal(result.event.allowed, true);
|
||||
assert.equal(result.statePatch.kinsType, "identity");
|
||||
assert.equal(result.statePatch.rtcpState, "off");
|
||||
assert.equal(result.halPatch["motion.switchkins-type"], 0);
|
||||
|
||||
result = runControlledUserM(userM, "M430", { profile });
|
||||
userM = result.simulation;
|
||||
assert.equal(result.event.allowed, true);
|
||||
assert.equal(result.statePatch.kinsType, "userk");
|
||||
assert.equal(result.halPatch["motion.switchkins-type"], 2);
|
||||
|
||||
result = runControlledUserM(userM, "M128", { profile });
|
||||
userM = result.simulation;
|
||||
assert.equal(result.event.allowed, true);
|
||||
assert.equal(result.event.hostProcessExecution, false);
|
||||
|
||||
result = runControlledUserM(userM, "M199", { profile });
|
||||
userM = result.simulation;
|
||||
assert.equal(result.event.allowed, false);
|
||||
assert.equal(result.event.semanticBoundary, "arbitrary_external_user_m_blocked");
|
||||
assert.equal(result.event.hostProcessExecution, false);
|
||||
assert.equal(userM.blockedEvents.length, 1);
|
||||
|
||||
const scan = runControlledUserMProgramScan(
|
||||
userM,
|
||||
[
|
||||
"M428",
|
||||
"G0 X1",
|
||||
"M129",
|
||||
"M199",
|
||||
"M429",
|
||||
].join("\n"),
|
||||
{ profile, sourceRel: "operator-test.ngc" },
|
||||
);
|
||||
assert.equal(scan.events.length, 4);
|
||||
assert.equal(scan.events.filter((event) => event.allowed).length, 3);
|
||||
assert.equal(scan.events.filter((event) => !event.allowed).length, 1);
|
||||
|
||||
console.log("tool_db_user_m_simulation_smoke=ok");
|
||||
console.log("tool_db_process_ready_web_simulation_only=1");
|
||||
console.log("external_user_m_process_ready_web_simulation_only=1");
|
||||
console.log("arbitrary_user_m_blocked=1");
|
||||
console.log("host_process_execution=0");
|
||||
@@ -0,0 +1,150 @@
|
||||
import assert from "node:assert/strict";
|
||||
import { readFile } from "node:fs/promises";
|
||||
|
||||
import { createMemorySessionStorage } from "../../app/src/runtime/five-axis-session.js";
|
||||
import {
|
||||
applyToolCommandSequence,
|
||||
createMemoryToolDbStorage,
|
||||
createToolDbReadiness,
|
||||
createToolDbSimulation,
|
||||
editToolEntry,
|
||||
extractToolCommandSequenceFromProgram,
|
||||
listToolEntries,
|
||||
parseLinuxCncToolTable,
|
||||
queryToolEntry,
|
||||
saveToolDbSimulation,
|
||||
} from "../../app/src/runtime/tool-db-simulation.js";
|
||||
import { getFiveAxisProfile } from "../../app/src/profiles/index.js";
|
||||
import { createSimulationStore } from "../../app/src/state/store.js";
|
||||
|
||||
const profile = getFiveAxisProfile("xyzac-trt");
|
||||
const toolTableText = await readFile(
|
||||
new URL("../../../linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzac-trt.tbl", import.meta.url),
|
||||
"utf8",
|
||||
);
|
||||
|
||||
const parsed = parseLinuxCncToolTable(toolTableText, {
|
||||
sourceRel: profile.toolTablePath,
|
||||
});
|
||||
assert.equal(parsed.randomToolChanger, false);
|
||||
assert.equal(parsed.toolCount, 10);
|
||||
assert.equal(parsed.pockets[0].toolNumber, 0);
|
||||
assert.equal(parsed.entries[0].idx, 1);
|
||||
assert.equal(parsed.entries[0].toolNumber, 1);
|
||||
assert.equal(parsed.entries[0].pocket, 1);
|
||||
assert.equal(parsed.entries[1].idx, 2);
|
||||
assert.equal(parsed.entries[1].toolNumber, 2);
|
||||
assert.equal(parsed.entries[1].pocket, 2);
|
||||
assert.equal(parsed.entries[1].offset.z, 15);
|
||||
assert.equal(parsed.entries[1].diameter, 8);
|
||||
|
||||
let toolDb = createToolDbSimulation({
|
||||
toolTable: parsed,
|
||||
profile,
|
||||
});
|
||||
assert.equal(createToolDbReadiness(toolDb).toolDbProcessReady, true);
|
||||
assert.equal(createToolDbReadiness(toolDb).dbProgramReady, false);
|
||||
assert.equal(toolDb.hostProcessExecution, false);
|
||||
assert.equal(toolDb.toolTable.pockets[0].toolNumber, 0);
|
||||
|
||||
assert.equal(listToolEntries(toolDb).length, 10);
|
||||
assert.equal(queryToolEntry(toolDb, { idx: 2 }).toolNumber, 2);
|
||||
assert.equal(queryToolEntry(toolDb, { toolNumber: 2 }).idx, 2);
|
||||
assert.equal(queryToolEntry(toolDb, { pocket: 2 }).diameter, 8);
|
||||
|
||||
toolDb = applyToolCommandSequence(toolDb, [
|
||||
{ code: "T", toolNumber: 2 },
|
||||
{ code: "M6" },
|
||||
{ code: "G43", h: 2 },
|
||||
]);
|
||||
assert.equal(toolDb.toolInSpindle, 2);
|
||||
assert.equal(toolDb.toolFromPocket, 2);
|
||||
assert.equal(toolDb.currentPocket, 2);
|
||||
assert.equal(toolDb.toolTable.pockets[0].toolNumber, 2);
|
||||
assert.equal(toolDb.toolTable.pockets[0].offset.z, 15);
|
||||
assert.equal(queryToolEntry(toolDb, { pocket: 2 }).idx, 2);
|
||||
assert.equal(toolDb.emcioStatus.tool.pocketPrepped, -1);
|
||||
assert.equal(toolDb.iocontrol.toolNumber, 2);
|
||||
assert.equal(toolDb.iocontrol.toolFromPocket, 2);
|
||||
assert.equal(toolDb.activeToolOffset.toolNumber, 2);
|
||||
assert.equal(toolDb.activeToolOffset.offset.z, 15);
|
||||
assert.equal(toolDb.interpreterParameters[5400], 2);
|
||||
assert.equal(toolDb.interpreterParameters[5403], 15);
|
||||
assert.equal(toolDb.interpreterParameters[5410], 8);
|
||||
assert.equal(toolDb.events.some((event) => event.code === "READ_TOOL_INPUTS_PREPARED"), true);
|
||||
assert.equal(toolDb.events.some((event) => event.code === "READ_TOOL_INPUTS_CHANGED"), true);
|
||||
|
||||
const compactToolCommands = extractToolCommandSequenceFromProgram("T2M6G43H2");
|
||||
assert.deepEqual(compactToolCommands.map((command) => command.code), ["T", "M6", "G43"]);
|
||||
assert.equal(compactToolCommands[2].toolNumber, 2);
|
||||
|
||||
toolDb = editToolEntry(toolDb, {
|
||||
toolNumber: 4,
|
||||
pocket: 44,
|
||||
diameter: 12.5,
|
||||
length: 42.25,
|
||||
comment: "edited by web simulation",
|
||||
});
|
||||
const edited = queryToolEntry(toolDb, { toolNumber: 4 });
|
||||
assert.equal(edited.idx, 4);
|
||||
assert.equal(edited.pocket, 44);
|
||||
assert.equal(edited.offset.z, 42.25);
|
||||
assert.equal(edited.diameter, 12.5);
|
||||
|
||||
toolDb = editToolEntry(toolDb, {
|
||||
idx: 6,
|
||||
toolNumber: 66,
|
||||
pocket: 66,
|
||||
diameter: 6.6,
|
||||
toolLength: 16.6,
|
||||
});
|
||||
const renumbered = queryToolEntry(toolDb, { toolNumber: 66 });
|
||||
assert.equal(renumbered.idx, 6);
|
||||
assert.equal(renumbered.pocket, 66);
|
||||
assert.equal(renumbered.offset.z, 16.6);
|
||||
assert.equal(renumbered.diameter, 6.6);
|
||||
|
||||
const storage = createMemoryToolDbStorage();
|
||||
const save = await saveToolDbSimulation(toolDb, {
|
||||
storage,
|
||||
storageMode: "memory",
|
||||
});
|
||||
assert.equal(save.storageMode, "memory");
|
||||
assert.equal(storage.files.get(save.path), save.text);
|
||||
assert.equal(save.text.includes("T4 P44 D+12.500000 Z+42.250000 ;edited by web simulation"), true);
|
||||
assert.equal(save.text.includes("T66 P66 D+6.600000 Z+16.600000"), true);
|
||||
|
||||
const fallbackSave = await saveToolDbSimulation(toolDb);
|
||||
assert.equal(fallbackSave.storageMode, "memory-fallback");
|
||||
assert.equal(fallbackSave.storageCapability.opfsUnavailable, true);
|
||||
|
||||
const store = createSimulationStore();
|
||||
const machineStorage = createMemorySessionStorage();
|
||||
await store.stageMachineFiles({ storage: machineStorage });
|
||||
assert.equal(store.getState().toolDbReadiness.toolDbProcessReady, true);
|
||||
assert.equal(store.queryToolDb({ toolNumber: 2 }).offset.z, 15);
|
||||
assert.equal(store.queryToolDb({ all: true }).length, 10);
|
||||
|
||||
store.editToolDb({
|
||||
toolNumber: 3,
|
||||
pocket: 33,
|
||||
diameter: 9.75,
|
||||
toolLength: 21.5,
|
||||
});
|
||||
assert.equal(store.queryToolDb({ toolNumber: 3 }).pocket, 33);
|
||||
assert.equal(store.queryToolDb({ toolNumber: 3 }).offset.z, 21.5);
|
||||
|
||||
const storeSaveStorage = createMemoryToolDbStorage();
|
||||
const storeSave = await store.saveToolDb({
|
||||
storage: storeSaveStorage,
|
||||
storageMode: "memory",
|
||||
});
|
||||
assert.equal(storeSave.text.includes("T3 P33 D+9.750000 Z+21.500000"), true);
|
||||
assert.equal(storeSaveStorage.files.get(storeSave.path), storeSave.text);
|
||||
|
||||
console.log("tool_db_web_simulation_smoke=ok");
|
||||
console.log("staged_tool_tbl_loaded=1");
|
||||
console.log("tool_db_query_edit_save=1");
|
||||
console.log("tool_db_t_m6_g43_state=1");
|
||||
console.log("tool_db_memory_fallback_save=1");
|
||||
console.log("host_tool_db_process=0");
|
||||
Reference in New Issue
Block a user