完善虚拟HAL仿真替代能力
This commit is contained in:
@@ -32,8 +32,21 @@ import {
|
||||
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowSummaryViewModel,
|
||||
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlan,
|
||||
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationSummaryViewModel,
|
||||
VIRTUAL_HAL_COVERAGE_STATES,
|
||||
VIRTUAL_HAL_PROJECT_PIN_GROUPS,
|
||||
VIRTUAL_HAL_SIMULATION_REPLACEMENT_TARGETS,
|
||||
VIRTUAL_HAL_SIMULATION_RUNTIME_CAPABILITIES,
|
||||
VIRTUAL_HAL_SOURCE_FILES,
|
||||
VIRTUAL_HAL_SYSTEM_PIN_FAMILIES,
|
||||
VIRTUAL_HAL_WASM_BRIDGE_FUNCTIONS,
|
||||
applyVirtualHalAction,
|
||||
applyVirtualHalPinUpdates,
|
||||
applyVirtualHalToInterpSdk,
|
||||
createVirtualHalSimulationRuntimeReport,
|
||||
createLinuxCncIniSdk,
|
||||
createLinuxCncInterpSdk,
|
||||
createLinuxCncVirtualHalRuntime,
|
||||
createVirtualHalIntegrityReport,
|
||||
createMachineSessionSnapshotPayload,
|
||||
createMachineSessionPersistenceDisplayViewModel,
|
||||
createMachineSessionPersistenceRenderState,
|
||||
@@ -63,6 +76,21 @@ import {
|
||||
createProjectReleaseReadinessArtifactValidationSummaryViewModel,
|
||||
createProjectReleaseReadinessReport,
|
||||
createProjectReleaseReadinessSummaryViewModel,
|
||||
createVirtualHalBridgeActionPlan,
|
||||
createVirtualHalBridgeReadiness,
|
||||
createVirtualHalPinInventory,
|
||||
createVirtualHalPinRegistry,
|
||||
createVirtualHalProjectReport,
|
||||
createVirtualHalSimulationReplacementReport,
|
||||
createVirtualHalState,
|
||||
createVirtualHalSystemCoverageReport,
|
||||
createVirtualHalWasmBridgeSnapshot,
|
||||
executeVirtualHalCommand,
|
||||
executeVirtualHalcmd,
|
||||
readVirtualHalPin,
|
||||
stepVirtualHalMotionController,
|
||||
stepVirtualHalMotion,
|
||||
writeVirtualHalPin,
|
||||
parseProjectReleaseReadinessArtifactJson,
|
||||
createSessionSnapshot,
|
||||
defaultMachinePaths,
|
||||
@@ -186,6 +214,27 @@ const requiredExports = [
|
||||
],
|
||||
["createProjectReleaseReadinessReport", createProjectReleaseReadinessReport],
|
||||
["createProjectReleaseReadinessSummaryViewModel", createProjectReleaseReadinessSummaryViewModel],
|
||||
["applyVirtualHalAction", applyVirtualHalAction],
|
||||
["applyVirtualHalPinUpdates", applyVirtualHalPinUpdates],
|
||||
["applyVirtualHalToInterpSdk", applyVirtualHalToInterpSdk],
|
||||
["createLinuxCncVirtualHalRuntime", createLinuxCncVirtualHalRuntime],
|
||||
["createVirtualHalBridgeActionPlan", createVirtualHalBridgeActionPlan],
|
||||
["createVirtualHalBridgeReadiness", createVirtualHalBridgeReadiness],
|
||||
["createVirtualHalIntegrityReport", createVirtualHalIntegrityReport],
|
||||
["createVirtualHalPinInventory", createVirtualHalPinInventory],
|
||||
["createVirtualHalPinRegistry", createVirtualHalPinRegistry],
|
||||
["createVirtualHalProjectReport", createVirtualHalProjectReport],
|
||||
["createVirtualHalSimulationReplacementReport", createVirtualHalSimulationReplacementReport],
|
||||
["createVirtualHalSimulationRuntimeReport", createVirtualHalSimulationRuntimeReport],
|
||||
["createVirtualHalState", createVirtualHalState],
|
||||
["createVirtualHalSystemCoverageReport", createVirtualHalSystemCoverageReport],
|
||||
["createVirtualHalWasmBridgeSnapshot", createVirtualHalWasmBridgeSnapshot],
|
||||
["executeVirtualHalCommand", executeVirtualHalCommand],
|
||||
["executeVirtualHalcmd", executeVirtualHalcmd],
|
||||
["readVirtualHalPin", readVirtualHalPin],
|
||||
["stepVirtualHalMotionController", stepVirtualHalMotionController],
|
||||
["stepVirtualHalMotion", stepVirtualHalMotion],
|
||||
["writeVirtualHalPin", writeVirtualHalPin],
|
||||
["parseProjectReleaseReadinessArtifactJson", parseProjectReleaseReadinessArtifactJson],
|
||||
[
|
||||
"validateIniPanelShellWorkflowOverviewReleaseReadinessArtifactJson",
|
||||
@@ -411,6 +460,202 @@ for (const [name, value] of requiredExports) {
|
||||
assert.match(sdkReadmeText, new RegExp(`\\b${name}\\b`));
|
||||
}
|
||||
|
||||
assert.equal(VIRTUAL_HAL_WASM_BRIDGE_FUNCTIONS.includes("lcinterp_hal_set_value"), true);
|
||||
assert.equal(VIRTUAL_HAL_PROJECT_PIN_GROUPS.some(({ id }) => id === "axisui"), true);
|
||||
assert.equal(VIRTUAL_HAL_SIMULATION_RUNTIME_CAPABILITIES.includes("halcmd-setp-sets-net-show-getp-gets"), true);
|
||||
assert.equal(VIRTUAL_HAL_SIMULATION_RUNTIME_CAPABILITIES.includes("realtime-hal-simulation-replacement"), true);
|
||||
assert.equal(VIRTUAL_HAL_SIMULATION_RUNTIME_CAPABILITIES.includes("motion-controller-simulation-replacement"), true);
|
||||
assert.equal(VIRTUAL_HAL_SIMULATION_REPLACEMENT_TARGETS.includes("linuxcnc-realtime-hal"), true);
|
||||
assert.equal(VIRTUAL_HAL_SIMULATION_REPLACEMENT_TARGETS.includes("halcmd"), true);
|
||||
assert.equal(VIRTUAL_HAL_SIMULATION_REPLACEMENT_TARGETS.includes("motion-controller"), true);
|
||||
assert.equal(VIRTUAL_HAL_COVERAGE_STATES.runtimeBoundary, "runtime-boundary");
|
||||
assert.equal(VIRTUAL_HAL_SOURCE_FILES.halui, "linuxcnc/src/emc/usr_intf/halui.cc");
|
||||
assert.equal(VIRTUAL_HAL_SYSTEM_PIN_FAMILIES.some(({ id }) => id === "iocontrol"), true);
|
||||
assert.equal(VIRTUAL_HAL_SYSTEM_PIN_FAMILIES.some(({ id }) => id === "motion-core"), true);
|
||||
assert.match(sdkIndexText, /\bVIRTUAL_HAL_WASM_BRIDGE_FUNCTIONS\b/);
|
||||
assert.match(sdkReadmeText, /\bVIRTUAL_HAL_WASM_BRIDGE_FUNCTIONS\b/);
|
||||
assert.match(sdkIndexText, /\bVIRTUAL_HAL_PROJECT_PIN_GROUPS\b/);
|
||||
assert.match(sdkReadmeText, /\bVIRTUAL_HAL_PROJECT_PIN_GROUPS\b/);
|
||||
assert.match(sdkIndexText, /\bVIRTUAL_HAL_SIMULATION_RUNTIME_CAPABILITIES\b/);
|
||||
assert.match(sdkReadmeText, /\bVIRTUAL_HAL_SIMULATION_RUNTIME_CAPABILITIES\b/);
|
||||
assert.match(sdkIndexText, /\bVIRTUAL_HAL_SIMULATION_REPLACEMENT_TARGETS\b/);
|
||||
assert.match(sdkReadmeText, /\bVIRTUAL_HAL_SIMULATION_REPLACEMENT_TARGETS\b/);
|
||||
assert.match(sdkIndexText, /\bVIRTUAL_HAL_SYSTEM_PIN_FAMILIES\b/);
|
||||
assert.match(sdkReadmeText, /\bVIRTUAL_HAL_SYSTEM_PIN_FAMILIES\b/);
|
||||
assert.match(sdkIndexText, /\bexecuteVirtualHalCommand\b/);
|
||||
assert.match(sdkReadmeText, /\bexecuteVirtualHalCommand\b/);
|
||||
assert.match(sdkIndexText, /\bexecuteVirtualHalcmd\b/);
|
||||
assert.match(sdkReadmeText, /\bexecuteVirtualHalcmd\b/);
|
||||
assert.match(sdkIndexText, /\bstepVirtualHalMotion\b/);
|
||||
assert.match(sdkReadmeText, /\bstepVirtualHalMotion\b/);
|
||||
assert.match(sdkIndexText, /\bstepVirtualHalMotionController\b/);
|
||||
assert.match(sdkReadmeText, /\bstepVirtualHalMotionController\b/);
|
||||
assert.match(sdkIndexText, /\bcreateVirtualHalSimulationRuntimeReport\b/);
|
||||
assert.match(sdkReadmeText, /\bcreateVirtualHalSimulationRuntimeReport\b/);
|
||||
assert.match(sdkIndexText, /\bcreateVirtualHalSimulationReplacementReport\b/);
|
||||
assert.match(sdkReadmeText, /\bcreateVirtualHalSimulationReplacementReport\b/);
|
||||
assert.match(sdkIndexText, /\bcreateVirtualHalSystemCoverageReport\b/);
|
||||
assert.match(sdkReadmeText, /\bcreateVirtualHalSystemCoverageReport\b/);
|
||||
assert.match(sdkIndexText, /\bcreateVirtualHalPinRegistry\b/);
|
||||
assert.match(sdkReadmeText, /\bcreateVirtualHalPinRegistry\b/);
|
||||
assert.match(sdkIndexText, /\bcreateVirtualHalIntegrityReport\b/);
|
||||
assert.match(sdkReadmeText, /\bcreateVirtualHalIntegrityReport\b/);
|
||||
assert.match(sdkIndexText, /\breadVirtualHalPin\b/);
|
||||
assert.match(sdkReadmeText, /\breadVirtualHalPin\b/);
|
||||
assert.match(sdkIndexText, /\bwriteVirtualHalPin\b/);
|
||||
assert.match(sdkReadmeText, /\bwriteVirtualHalPin\b/);
|
||||
|
||||
let sdkVirtualHal = createVirtualHalState();
|
||||
sdkVirtualHal = applyVirtualHalAction(sdkVirtualHal, "estop");
|
||||
sdkVirtualHal = applyVirtualHalAction(sdkVirtualHal, "power");
|
||||
sdkVirtualHal = applyVirtualHalAction(sdkVirtualHal, "jog", { axis: "x", increment: "0.01 in", direction: 1 });
|
||||
sdkVirtualHal = writeVirtualHalPin(sdkVirtualHal, { name: "spindle.0.speed-out", type: "HAL_FLOAT", value: 1800 });
|
||||
sdkVirtualHal = writeVirtualHalPin(sdkVirtualHal, { name: "motion.tooloffset.z", type: "HAL_FLOAT", value: 2.5 });
|
||||
sdkVirtualHal = applyVirtualHalPinUpdates(sdkVirtualHal, [
|
||||
{ name: "halui.tool.number", type: "HAL_U32", value: 7 },
|
||||
{ name: "halui.feed-override.value", type: "HAL_FLOAT", value: 0.8 },
|
||||
]);
|
||||
assert.equal(readVirtualHalPin(sdkVirtualHal, "spindle.0.speed-out").value, 1800);
|
||||
assert.equal(readVirtualHalPin(sdkVirtualHal, "motion.tooloffset.z").value, 2.5);
|
||||
assert.equal(readVirtualHalPin(sdkVirtualHal, "halui.tool.number").value, 7);
|
||||
assert.equal(sdkVirtualHal.overrides.feed, 80);
|
||||
const virtualHalSnapshot = createVirtualHalWasmBridgeSnapshot(sdkVirtualHal);
|
||||
assert.equal(virtualHalSnapshot.apiName, "linuxcnc-wasm-virtual-hal-bridge-snapshot");
|
||||
assert.ok(virtualHalSnapshot.values.some(({ name }) => name === "axisui.jog.x"));
|
||||
assert.ok(virtualHalSnapshot.values.some(({ name, value }) => name === "spindle.0.speed-out" && value === 1800));
|
||||
assert.ok(virtualHalSnapshot.values.some(({ name, value }) => name === "motion.tooloffset.z" && value === 2.5));
|
||||
const virtualHalRegistry = createVirtualHalPinRegistry(sdkVirtualHal);
|
||||
assert.equal(virtualHalRegistry.apiName, "linuxcnc-wasm-virtual-hal-pin-registry");
|
||||
assert.equal(virtualHalRegistry.byName["spindle.0.speed-out"].value, 1800);
|
||||
assert.equal(virtualHalRegistry.byName["motion.tooloffset.z"].value, 2.5);
|
||||
assert.equal(virtualHalRegistry.byName["halui.tool.number"].value, 7);
|
||||
assert.equal(virtualHalRegistry.rows.some(({ name, writable }) => name === "halui.machine.on" && writable === true), true);
|
||||
const virtualHalIntegrity = createVirtualHalIntegrityReport({ halState: sdkVirtualHal, registry: virtualHalRegistry });
|
||||
assert.equal(virtualHalIntegrity.apiName, "linuxcnc-wasm-virtual-hal-integrity-report");
|
||||
assert.equal(virtualHalIntegrity.complete, true);
|
||||
assert.equal(virtualHalIntegrity.missingPins.length, 0);
|
||||
const virtualHalInventory = createVirtualHalPinInventory(sdkVirtualHal);
|
||||
assert.equal(virtualHalInventory.apiName, "linuxcnc-wasm-virtual-hal-pin-inventory");
|
||||
assert.equal(virtualHalInventory.groups.some(({ id, pinCount }) => id === "axisui" && pinCount > 0), true);
|
||||
assert.equal(virtualHalInventory.groups.some(({ id, pinCount }) => id === "axis-motion" && pinCount > 0), true);
|
||||
assert.equal(virtualHalInventory.groups.some(({ id, pinCount }) => id === "tool" && pinCount > 0), true);
|
||||
const virtualHalSystemCoverage = createVirtualHalSystemCoverageReport({ snapshot: virtualHalSnapshot });
|
||||
assert.equal(virtualHalSystemCoverage.apiName, "linuxcnc-wasm-virtual-hal-system-coverage-report");
|
||||
assert.equal(virtualHalSystemCoverage.complete, true);
|
||||
assert.equal(virtualHalSystemCoverage.realtimeHalRuntime, false);
|
||||
assert.equal(virtualHalSystemCoverage.sourceFiles.includes("linuxcnc/bin/axis"), true);
|
||||
assert.equal(virtualHalSystemCoverage.sourceFiles.includes("linuxcnc/src/emc/usr_intf/halui.cc"), true);
|
||||
assert.equal(virtualHalSystemCoverage.sourceFiles.includes("linuxcnc/src/emc/task/taskclass.cc"), true);
|
||||
assert.equal(virtualHalSystemCoverage.sourceFiles.includes("linuxcnc/src/emc/motion/motion.c"), true);
|
||||
assert.equal(virtualHalSystemCoverage.families.some(({ id, coverage }) => id === "motion-core" && coverage === "runtime-boundary"), true);
|
||||
assert.equal(virtualHalSystemCoverage.boundaryRows.some(({ id }) => id === "halui-task"), true);
|
||||
const virtualHalBlockedReadiness = createVirtualHalBridgeReadiness({ snapshot: virtualHalSnapshot });
|
||||
assert.equal(virtualHalBlockedReadiness.ready, false);
|
||||
assert.equal(virtualHalBlockedReadiness.missing.includes("wasm-function-evidence"), true);
|
||||
const virtualHalReadyReadiness = createVirtualHalBridgeReadiness({
|
||||
snapshot: virtualHalSnapshot,
|
||||
availableFunctions: VIRTUAL_HAL_WASM_BRIDGE_FUNCTIONS,
|
||||
});
|
||||
assert.equal(virtualHalReadyReadiness.ready, true);
|
||||
assert.equal(createVirtualHalBridgeActionPlan(virtualHalReadyReadiness).nextCommand, null);
|
||||
const virtualHalReport = createVirtualHalProjectReport({
|
||||
halState: sdkVirtualHal,
|
||||
availableFunctions: VIRTUAL_HAL_WASM_BRIDGE_FUNCTIONS,
|
||||
});
|
||||
assert.equal(virtualHalReport.apiName, "linuxcnc-wasm-virtual-hal-project-report");
|
||||
assert.equal(virtualHalReport.ready, true);
|
||||
assert.equal(virtualHalReport.pinInventory.pinCount, virtualHalReport.wasmBridgeSnapshot.values.length);
|
||||
assert.equal(virtualHalReport.systemCoverage.phase, "covered-with-runtime-boundaries");
|
||||
assert.equal(virtualHalReport.systemCoverage.unclassifiedSnapshotPins.length, 0);
|
||||
assert.equal(virtualHalReport.pinRegistry.byName["spindle.0.speed-out"].value, 1800);
|
||||
assert.equal(virtualHalReport.integrity.complete, true);
|
||||
const virtualHalRuntime = createLinuxCncVirtualHalRuntime(sdkVirtualHal);
|
||||
assert.equal(virtualHalRuntime.getProjectReport({ availableFunctions: VIRTUAL_HAL_WASM_BRIDGE_FUNCTIONS }).ready, true);
|
||||
const virtualHalcmdResult = virtualHalRuntime.executeHalCommand(`
|
||||
loadrt trivkins
|
||||
addf motion-controller servo-thread
|
||||
net x-pos axis.x.pos-cmd joint.0.pos-fb
|
||||
setp axis.x.pos-cmd 2.5
|
||||
sets x-pos 1.25
|
||||
show pin axis.x.*
|
||||
motion-step x=2.0
|
||||
`);
|
||||
assert.equal(virtualHalcmdResult.apiName, "linuxcnc-wasm-virtual-halcmd-result");
|
||||
assert.equal(virtualHalcmdResult.ok, true);
|
||||
assert.equal(virtualHalcmdResult.rows.some(({ action }) => action === "net"), true);
|
||||
assert.equal(virtualHalRuntime.getState().hal.signals["x-pos"].value, 1.25);
|
||||
assert.equal(virtualHalRuntime.getState().hal.nets["x-pos"].includes("axis.x.pos-cmd"), true);
|
||||
assert.equal(virtualHalRuntime.getState().hal.loadedComponents.some(({ component }) => component === "trivkins"), true);
|
||||
assert.equal(virtualHalRuntime.getState().hal.functions.some(({ name }) => name === "motion-controller"), true);
|
||||
assert.ok(virtualHalRuntime.getState().position.x > 1.25);
|
||||
const directHalcmdResult = executeVirtualHalCommand(virtualHalRuntime.getState(), "getp axis.x.pos-cmd\ngets x-pos");
|
||||
assert.equal(directHalcmdResult.ok, true);
|
||||
assert.match(directHalcmdResult.output, /axis\.x\.pos-cmd/);
|
||||
assert.match(directHalcmdResult.output, /x-pos/);
|
||||
const directHalcmdAliasResult = executeVirtualHalcmd(virtualHalRuntime.getState(), "setp halui.machine.on 1\nshow pin halui.machine.*");
|
||||
assert.equal(directHalcmdAliasResult.ok, true);
|
||||
assert.equal(directHalcmdAliasResult.apiName, "linuxcnc-wasm-virtual-halcmd-result");
|
||||
assert.match(directHalcmdAliasResult.output, /halui\.machine\.is-on/);
|
||||
const steppedVirtualHal = stepVirtualHalMotion(virtualHalRuntime.getState(), {
|
||||
target: { x: 3 },
|
||||
maxVelocity: 10,
|
||||
dt: 0.1,
|
||||
});
|
||||
assert.ok(steppedVirtualHal.position.x > virtualHalRuntime.getState().position.x);
|
||||
const motionControllerStep = stepVirtualHalMotionController(virtualHalRuntime.getState(), {
|
||||
target: { x: 4 },
|
||||
maxVelocity: 10,
|
||||
dt: 0.1,
|
||||
cycleCount: 3,
|
||||
});
|
||||
assert.equal(motionControllerStep.apiName, "linuxcnc-wasm-virtual-motion-controller-step");
|
||||
assert.equal(motionControllerStep.ok, true);
|
||||
assert.ok(motionControllerStep.cycleCount >= 1);
|
||||
assert.ok(motionControllerStep.state.position.x > virtualHalRuntime.getState().position.x);
|
||||
const simulationRuntimeReport = virtualHalRuntime.getSimulationRuntimeReport();
|
||||
assert.equal(simulationRuntimeReport.apiName, "linuxcnc-wasm-virtual-hal-simulation-runtime-report");
|
||||
assert.equal(simulationRuntimeReport.replacesHostRuntimeForSimulation, true);
|
||||
assert.deepEqual(simulationRuntimeReport.replacementTargets, VIRTUAL_HAL_SIMULATION_REPLACEMENT_TARGETS);
|
||||
assert.equal(simulationRuntimeReport.hardRealtime, false);
|
||||
assert.deepEqual(simulationRuntimeReport.hostRequirements, []);
|
||||
assert.equal(simulationRuntimeReport.capabilities.includes("servo-period-motion-step"), true);
|
||||
assert.equal(createVirtualHalSimulationRuntimeReport(virtualHalRuntime.getState()).ready, true);
|
||||
const runtimeMotionControllerStep = virtualHalRuntime.stepMotionController({
|
||||
target: { x: 4.5 },
|
||||
maxVelocity: 20,
|
||||
dt: 0.1,
|
||||
cycleCount: 2,
|
||||
});
|
||||
assert.equal(runtimeMotionControllerStep.apiName, "linuxcnc-wasm-virtual-motion-controller-step");
|
||||
assert.ok(virtualHalRuntime.getState().position.x > motionControllerStep.state.position.x);
|
||||
const replacementReport = createVirtualHalSimulationReplacementReport(virtualHalRuntime.getState());
|
||||
assert.equal(replacementReport.apiName, "linuxcnc-wasm-virtual-hal-simulation-replacement-report");
|
||||
assert.equal(replacementReport.ready, true);
|
||||
assert.equal(replacementReport.replacesHostRuntimeForSimulation, true);
|
||||
assert.equal(replacementReport.replacements["linuxcnc-realtime-hal"].ready, true);
|
||||
assert.equal(replacementReport.replacements.halcmd.ready, true);
|
||||
assert.equal(replacementReport.replacements["motion-controller"].ready, true);
|
||||
assert.equal(replacementReport.hardRealtime, false);
|
||||
assert.equal(virtualHalRuntime.getSimulationReplacementReport().ready, true);
|
||||
const runtimeProjectReport = virtualHalRuntime.getProjectReport({ availableFunctions: VIRTUAL_HAL_WASM_BRIDGE_FUNCTIONS });
|
||||
assert.equal(runtimeProjectReport.simulationRuntime.replacesHostRuntimeForSimulation, true);
|
||||
assert.equal(runtimeProjectReport.systemCoverage.unclassifiedSnapshotPins.length, 0);
|
||||
const fakeInterpApplyResult = applyVirtualHalToInterpSdk(
|
||||
{
|
||||
applyVirtualHalSnapshot(snapshot, options) {
|
||||
return {
|
||||
apiName: "fake-virtual-hal-apply-result",
|
||||
applied: snapshot.values.length,
|
||||
reset: options.reset !== false,
|
||||
};
|
||||
},
|
||||
},
|
||||
sdkVirtualHal,
|
||||
{ reset: false },
|
||||
);
|
||||
assert.equal(fakeInterpApplyResult.apiName, "fake-virtual-hal-apply-result");
|
||||
assert.equal(fakeInterpApplyResult.reset, false);
|
||||
|
||||
assert.equal(machineIniPath("sdk-mill"), "linuxcnc/machines/sdk-mill/machine.ini");
|
||||
assert.deepEqual(defaultMachinePaths("sdk-mill"), machineFilePaths("sdk-mill"));
|
||||
assert.equal(gcodeProgramPath("demo.ngc"), "linuxcnc/gcode/demo.ngc");
|
||||
|
||||
Reference in New Issue
Block a user