完善 gmoccapy XYZAB 参考功能

This commit is contained in:
2026-06-26 17:53:45 -04:00
parent 4e4f1462f5
commit a81b40447d
154 changed files with 17194 additions and 51 deletions

View File

@@ -0,0 +1,116 @@
import assert from "node:assert/strict";
import { getFiveAxisProfile, fiveAxisProfiles } from "../../app/src/profiles/index.js";
import { buildRtcpFrame } from "../../app/src/runtime/rtcp-frame.js";
import { createLinuxCncBoundaryAdapter, createLinuxCncBoundaryReadiness } from "../../app/src/runtime/linuxcnc-boundary-adapter.js";
import { createProfileSourceReferenceSummary } from "../../app/src/profiles/source-reference-map.js";
import { createSimulationStore, validateRunPreconditions } from "../../app/src/state/store.js";
const profile = getFiveAxisProfile("gmoccapy-xyzab");
assert.equal(profile.id, "gmoccapy-xyzab");
assert.equal(profile.title, "gmoccapy XYZAB trivkins reference");
assert.equal(profile.iniPath, "linuxcnc/configs/sim/gmoccapy/gmoccapy_XYZAB.ini");
assert.deepEqual(profile.coordinates, ["X", "Y", "Z", "A", "B"]);
assert.equal(profile.traj.coordinates, "XYZAB");
assert.equal(profile.joints.length, 5);
assert.equal(profile.jointConfig.length, 5);
assert.equal(profile.kinematics, "trivkins coordinates=xyzab");
assert.equal(profile.kinematicsModuleId, "gmoccapy-xyzab-trivkins-reference");
assert.equal(profile.tcpCapable, false);
assert.equal(profile.rtcpProof, false);
assert.equal(profile.linuxCncKinematicsReady, false);
assert.equal(profile.promotionAllowed, false);
assert.equal(profile.semanticBoundary, "gmoccapy_xyzab_trivkins_reference_only_not_rtcp_proof");
assert.equal(profile.homing.noForceHoming, false);
assert.equal(profile.homing.noForceHomingIniValue, 0);
assert.equal(profile.hal.postguiRequiresHalcompReady, true);
assert.deepEqual(profile.hal.halFiles, ["core_sim_XYZAB.hal", "spindle_sim.hal", "simulated_home.hal"]);
assert.deepEqual(profile.hal.postguiHalFiles, ["gmoccapy_postgui.hal"]);
assert.equal(profile.nativeRuntime.task, "milltask");
assert.equal(profile.nativeRuntime.emcmot, "motmod");
assert.equal(profile.nativeRuntime.halui, "halui");
assert.equal(profile.nativeRuntime.displayCycleTimeMs, 100);
assert.equal(profile.nativeRuntime.servoPeriodNs, 1000000);
assert.equal(profile.axisLimits.X.max, 600);
assert.equal(profile.axisLimits.Y.max, 400);
assert.equal(profile.axisLimits.Z.min, -400);
assert.equal(profile.axisLimits.B.maxVelocity, 90);
assert.equal(profile.jointConfig[4].axis, "B");
assert.equal(profile.jointConfig[4].homeOffset, 45);
assert.equal(profile.hal.halcmd.feedbackNets.length, 5);
assert.equal(profile.hal.halcmd.offsetNets.some((net) => net.target === "gmoccapy.tooloffset-z"), true);
assert.equal(profile.hal.halcmd.simulationLoops.some((net) => net.signal === "tool-change-loop"), true);
assert.equal(profile.halPins.includes("gmoccapy.program.current-line"), true);
assert.equal(profile.halPins.includes("gmoccapy.spindle_at_speed_led"), true);
assert.equal(profile.toolTable.toolCount, 17);
assert.equal(profile.macros.includes("go_to_position X-pos Y-pos Z-pos"), true);
assert.equal(profile.panelSchema.id, "gmoccapy-xyzab-hal-component");
assert.equal(profile.panelSchema.boundary, "gmoccapy_hal_component_reference_only");
assert.equal(profile.panelSchema.groups.length, 2);
assert.deepEqual(fiveAxisProfiles.map(({ id }) => id), ["xyzac-trt", "xyzbc-trt", "gmoccapy-xyzab"]);
const sourceSummary = createProfileSourceReferenceSummary("gmoccapy-xyzab");
assert.equal(sourceSummary.profileId, "gmoccapy-xyzab");
assert.equal(sourceSummary.referenceCount >= 10, true);
assert.equal(sourceSummary.kinds.includes("ini"), true);
assert.equal(sourceSummary.kinds.includes("halfile"), true);
assert.equal(sourceSummary.kinds.includes("postgui_hal"), true);
assert.equal(sourceSummary.kinds.includes("icon_manifest"), true);
assert.equal(sourceSummary.kinds.includes("python_gui"), true);
assert.equal(sourceSummary.promotionAllowed, false);
assert.equal(sourceSummary.semanticBoundary, "profile_source_map_only_not_runtime_proof");
assert.ok(sourceSummary.references.some((reference) => reference.path.endsWith("gmoccapy_XYZAB.ini")));
assert.ok(sourceSummary.references.some((reference) => reference.path.endsWith("gmoccapy_postgui.hal")));
assert.ok(sourceSummary.references.some((reference) => reference.path.endsWith("gmoccapy-button-icons.json")));
const adapter = createLinuxCncBoundaryAdapter({ profile });
assert.equal(adapter.profileId, "gmoccapy-xyzab");
assert.equal(adapter.profileSummary.coordinates, "XYZAB");
assert.equal(adapter.profileSummary.jointCount, 5);
assert.equal(adapter.profileSummary.mdiCommandCount, 0);
assert.equal(adapter.profileSummary.remapCount, 2);
assert.equal(adapter.profileSummary.toolCount, 17);
assert.equal(adapter.profileSummary.feedbackNetCount, 5);
assert.equal(adapter.profileSummary.halFileCount, 4);
assert.equal(adapter.promotionAllowed, false);
assert.equal(adapter.linuxCncKinematicsReady, false);
const readiness = createLinuxCncBoundaryReadiness(adapter);
assert.equal(readiness.ready, false);
assert.equal(readiness.promotionAllowed, false);
assert.equal(readiness.missing.includes("kinematics runtime"), true);
const frame = buildRtcpFrame({
axisPose: { x: 10, y: 20, z: -5, a: 30, b: 45, c: 99 },
activeLine: 10,
profile,
});
assert.equal(frame.profileId, "gmoccapy-xyzab");
assert.deepEqual(frame.jointPose.map((joint) => joint.axis), ["X", "Y", "Z", "A", "B"]);
assert.equal(frame.jointPose[4].value, 45);
assert.equal(frame.readiness.linuxCncKinematicsReady, false);
assert.equal(frame.readiness.promotionAllowed, false);
const store = createSimulationStore();
store.dispatch({ type: "SET_PROFILE", profileId: "gmoccapy-xyzab" });
assert.equal(store.getState().machineProfile, "gmoccapy-xyzab");
assert.equal(store.getState().profile.tcpCapable, false);
assert.equal(store.getState().rtcpState, "off");
store.dispatch({ type: "SET_KINS_TYPE", kinsType: "tcp-xyzac" });
assert.equal(store.getState().kinsType, "identity");
assert.equal(store.getState().rtcpState, "off");
assert.equal(store.getState().operatorMessage, "kinematics tcp-xyzac blocked: gmoccapy-xyzab is not TCP capable");
store.dispatch({ type: "SET_RTCP", enabled: true });
assert.equal(store.getState().rtcpState, "off");
assert.equal(store.getState().operatorMessage, "RTCP blocked: gmoccapy-xyzab is trivkins coordinates=xyzab reference only");
const preconditions = validateRunPreconditions(store.getState(), {
requireTaskHalRuntime: false,
requireTaskHalSession: false,
});
assert.equal(preconditions.ok, false);
assert.equal(preconditions.operatorMessage, "run blocked: unsupported five-axis profile gmoccapy-xyzab");
console.log("gmoccapy_xyzab_profile_smoke=ok");