Add INI-driven XYZAC and XYZBC parametric machine design
This commit is contained in:
@@ -32,6 +32,7 @@ import { WasmXyzacDeviceIo } from "./wasm-xyzac-device-io.mjs";
|
||||
import { WasmProgramRuntime } from "./wasm-program-runtime.mjs";
|
||||
import { axisGate, xyzacGate, xyzacGateMatrix } from "../app/axis-contract.mjs";
|
||||
import { machineDefinition } from "../workspace/machine-definitions.mjs";
|
||||
import { readTrtGeometry, TRT_GEOMETRY_KEYS } from "../workspace/trt-geometry.mjs";
|
||||
|
||||
const PROTOCOL_SCHEMA = 1;
|
||||
const CONTEXT_ID = "linuxcnc-2.10.0-pre0-wasm-m1-py-c1";
|
||||
@@ -196,7 +197,7 @@ export class SimSession {
|
||||
// thousands of immutable segments on unrelated control responses makes a
|
||||
// loaded program delay abort/power/home commands behind structured-clone
|
||||
// work. Explicit preview transactions still publish the full replacement.
|
||||
const publishXyzacToolpath = ["PROGRAM_LOAD", "PROGRAM_RESTART", "RECOVER", "SNAPSHOT_REQUEST", "VISUAL_CLEAR"].includes(input.kind);
|
||||
const publishXyzacToolpath = ["LOAD_WORKSPACE", "PROGRAM_LOAD", "PROGRAM_RESTART", "RECOVER", "SNAPSHOT_REQUEST", "VISUAL_CLEAR"].includes(input.kind);
|
||||
const panelSnapshot = motionDelta || traceOnlyStep ? null : this.panelSnapshot({
|
||||
task,
|
||||
program,
|
||||
@@ -600,6 +601,9 @@ export class SimSession {
|
||||
const program = this.xyzacProgram.snapshot();
|
||||
const io = this.xyzacIo?.canonical?.() ?? {};
|
||||
const wasmMotion = this.wasmMotion.read();
|
||||
if (input.kind === "LOAD_WORKSPACE" && (io.ready || ["running", "paused"].includes(program.program_status) || Number(wasmMotion.state?.queue_depth) > 0)) {
|
||||
return { enabled: false, reason: "trt_configuration_requires_power_off_idle" };
|
||||
}
|
||||
if (["HOME", "SET_MODE"].includes(input.kind) && Number(wasmMotion.state?.queue_depth) > 0) return { enabled: false, reason: "xyzac_motion_active" };
|
||||
if (input.kind === "JOG_START" && !this.wasmHomeLimit.read().state.homed) return { enabled: false, reason: "xyzac_not_all_homed" };
|
||||
if (input.kind === "PROGRAM_LOAD" && wasmMotion.status === "verified" && Number(wasmMotion.state.queue_depth ?? 0) > 0) {
|
||||
@@ -830,6 +834,12 @@ export class SimSession {
|
||||
return { ...compact, checkpoint_hash: fnv1a64(compact) };
|
||||
}
|
||||
|
||||
validateRecoveryGeometry(state) {
|
||||
if (!this.xyzacKinematics) return;
|
||||
const current = this.xyzacKinematics.snapshot();
|
||||
if (!state?.kinematics || state.kinematics.coordinates !== current.coordinates || TRT_GEOMETRY_KEYS.some((key) => Number(state.kinematics.offsets?.[key] ?? 0) !== current.offsets[key])) throw new Error("trt_recovery_geometry_mismatch");
|
||||
}
|
||||
|
||||
restoreCompactPowerOff(record, transportSeq) {
|
||||
if (!record || record.schema !== "xyzac-power-off-checkpoint.v1" || record.context_id !== this.contextId || !record.state) return { status: "blocked", code: "runtime_checkpoint_schema", reason: "power_off_checkpoint_schema_invalid" };
|
||||
if (fnv1a64(record.state) !== record.state_hash || fnv1a64(Object.fromEntries(Object.entries(record).filter(([key]) => key !== "checkpoint_hash"))) !== record.checkpoint_hash) return { status: "blocked", code: "runtime_checkpoint_hash", reason: "power_off_checkpoint_hash_mismatch" };
|
||||
@@ -839,6 +849,7 @@ export class SimSession {
|
||||
const liveLedger = this.ledger;
|
||||
const liveOperations = [...this.operations.values()];
|
||||
try {
|
||||
this.validateRecoveryGeometry(state);
|
||||
if (!this.xyzacProgram || !state.program?.source_text) throw new Error("power_off_program_missing");
|
||||
const loaded = this.xyzacProgram.load(state.program.source_text, state.program.path ?? null);
|
||||
if (loaded.status !== "verified") throw new Error(loaded.code);
|
||||
@@ -941,6 +952,7 @@ export class SimSession {
|
||||
|
||||
importTrace(trace) {
|
||||
const validated = validateTrace(trace, { contextId: this.contextId });
|
||||
this.validateRecoveryGeometry(trace.state);
|
||||
this.timeline = validated.timeline;
|
||||
this.created = Boolean(trace.state?.created);
|
||||
if (trace.state?.ledger?.entries) this.ledger = new OperationLedger(trace.state.ledger.entries);
|
||||
@@ -977,6 +989,7 @@ export class SimSession {
|
||||
restoreCheckpoint(checkpoint, events = null, reconcile = undefined) {
|
||||
try {
|
||||
validateCheckpoint(checkpoint, { contextId: this.contextId });
|
||||
this.validateRecoveryGeometry(checkpoint.state);
|
||||
} catch (error) {
|
||||
return { schema: "simulation-recovery.v1", status: "blocked", context_id: this.contextId, checkpoint_hash: checkpoint?.checkpoint_hash ?? null, blocked: [{ reason: String(error?.message ?? error) }] };
|
||||
}
|
||||
@@ -1594,7 +1607,15 @@ export class SimSession {
|
||||
const rootPath = input.payload?.root_path;
|
||||
if (!text(rootPath) || !rootPath.startsWith("/") || rootPath.includes("..")) return finish(this.error(input, "workspace_path", "invalid_workspace_path"), "failed");
|
||||
let startupLoaded = false;
|
||||
const configuration = input.payload?.configuration ?? null;
|
||||
let configuration = input.payload?.configuration ?? null;
|
||||
if (machineDefinition(configuration?.entrypoint) || machineDefinition(configuration?.kinematics?.type)) {
|
||||
try {
|
||||
const geometry = readTrtGeometry(configuration);
|
||||
configuration = { ...configuration, kinematics: { ...configuration.kinematics, offsets: geometry.offsets } };
|
||||
} catch (error) {
|
||||
return finish(this.error(input, "trt_geometry", error.message), "failed");
|
||||
}
|
||||
}
|
||||
if (configuration) {
|
||||
this.machineDefinition = machineDefinition(configuration.entrypoint) ?? machineDefinition(configuration.kinematics?.type) ?? this.machineDefinition;
|
||||
this.workspaceFiles = { ...(configuration.files ?? configuration.workspace ?? configuration.workspace_files ?? {}) };
|
||||
@@ -1669,6 +1690,9 @@ export class SimSession {
|
||||
? new WasmLinuxcncTp(this.core, { cycleTime: this.xyzacMotionCycleTime, velocityLimit: this.xyzacRapidVelocity, accelerationLimit: Number(configuration.kinematics?.max_acceleration ?? 300), limits: configuration.home_limits ?? {} })
|
||||
: new WasmMotionQueue(this.core, { cycleTime: this.xyzacMotionCycleTime, velocityLimit: 1e9 });
|
||||
this.xyzacProgram = new WasmProgramRuntime(this.core);
|
||||
this.previewState = null;
|
||||
this.pendingXyzacMotion = null;
|
||||
this.clearLivePlot();
|
||||
this.homingHistory = [];
|
||||
this.xyzacProgramKinematicsMode = XYZAC_MODES.identity;
|
||||
if (typeof this.wasmMotion.setKinematics === "function") this.wasmMotion.setKinematics(this.xyzacKinematics);
|
||||
|
||||
Reference in New Issue
Block a user