完善云端RUN执行反馈
This commit is contained in:
@@ -172,6 +172,7 @@ const initialState = {
|
||||
programExecutionSampleIndex: 0,
|
||||
programRuntimeFeedback: null,
|
||||
programRuntimeFeedbackHistory: [],
|
||||
programLineExecution: {},
|
||||
taskHalRuntime: null,
|
||||
taskHalRuntimeReadiness: null,
|
||||
taskHalStatus: null,
|
||||
@@ -327,6 +328,25 @@ export function createSimulationStore(seed = {}) {
|
||||
scheduleAsyncKinematicsRefresh();
|
||||
};
|
||||
|
||||
const waitForStatePredicate = (predicate, timeoutMs = 10000) => {
|
||||
if (predicate(state)) return Promise.resolve(state);
|
||||
return new Promise((resolve, reject) => {
|
||||
const startedAt = Date.now();
|
||||
const listener = (nextState) => {
|
||||
if (predicate(nextState)) {
|
||||
listeners.delete(listener);
|
||||
resolve(nextState);
|
||||
return;
|
||||
}
|
||||
if (Date.now() - startedAt > timeoutMs) {
|
||||
listeners.delete(listener);
|
||||
reject(new Error("timed out waiting for store state"));
|
||||
}
|
||||
};
|
||||
listeners.add(listener);
|
||||
});
|
||||
};
|
||||
|
||||
const dispatch = (action) => {
|
||||
switch (action.type) {
|
||||
case "BOOT_READY":
|
||||
@@ -568,6 +588,10 @@ export function createSimulationStore(seed = {}) {
|
||||
programExecutionMotionIndex: 0,
|
||||
programExecutionSampleIndex: 0,
|
||||
programRuntimeFeedback: firstFeedback,
|
||||
programLineExecution: createProgramLineExecutionPatch(state.programLineExecution, firstFeedback, {
|
||||
status: "ready",
|
||||
source: execution.sourceMode,
|
||||
}),
|
||||
programElapsedSeconds: firstTiming.elapsedSeconds,
|
||||
programRemainingSeconds: firstTiming.remainingSeconds,
|
||||
interpreterExecutionPending: false,
|
||||
@@ -603,6 +627,7 @@ export function createSimulationStore(seed = {}) {
|
||||
programExecutionSourceMode: "fixture-line-playback",
|
||||
programExecutionSampleIndex: 0,
|
||||
programRuntimeFeedback: null,
|
||||
programLineExecution: {},
|
||||
interpreterExecutionPending: false,
|
||||
operatorMessage: `LinuxCNC interpreter blocked: ${action.error}`,
|
||||
});
|
||||
@@ -815,6 +840,7 @@ export function createSimulationStore(seed = {}) {
|
||||
axisPose: initialAxisPose,
|
||||
runState: "idle",
|
||||
programRuntimeFeedback: null,
|
||||
programLineExecution: {},
|
||||
preview: {
|
||||
...state.preview,
|
||||
pathPoints: Math.max(loadedProgram.programLines.length, 1),
|
||||
@@ -909,6 +935,14 @@ export function createSimulationStore(seed = {}) {
|
||||
case "RUN_FULL_BOUNDARY_AUDIT_REQUEST":
|
||||
runFullBoundaryAudit(action.options || {}).catch(() => {});
|
||||
break;
|
||||
case "RUN_READY":
|
||||
runReadySequence().catch((error) => {
|
||||
dispatch({
|
||||
type: "TASK_HAL_COMMAND_FAILED",
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
});
|
||||
});
|
||||
break;
|
||||
case "SET_FRAME_SOURCE":
|
||||
setState({
|
||||
sourceMode: action.sourceMode,
|
||||
@@ -1138,6 +1172,7 @@ export function createSimulationStore(seed = {}) {
|
||||
axisPose: initialAxisPose,
|
||||
runState: "idle",
|
||||
programRuntimeFeedback: null,
|
||||
programLineExecution: {},
|
||||
preview: {
|
||||
...state.preview,
|
||||
pathPoints: Math.max(loadedProgram.programLines.length, 1),
|
||||
@@ -1182,6 +1217,10 @@ export function createSimulationStore(seed = {}) {
|
||||
programExecutionMotionIndex: playback.motionIndex,
|
||||
programExecutionSampleIndex: playback.sampleIndex,
|
||||
programRuntimeFeedback: playback.runtimeFeedback,
|
||||
programLineExecution: createProgramLineExecutionPatch(state.programLineExecution, playback.runtimeFeedback, {
|
||||
status: playback.complete ? "done" : "running",
|
||||
source: playback.runtimeFeedback?.sourceMode,
|
||||
}),
|
||||
programElapsedSeconds: playback.timing.elapsedSeconds,
|
||||
programRemainingSeconds: playback.timing.remainingSeconds,
|
||||
feed: {
|
||||
@@ -1375,7 +1414,13 @@ export function createSimulationStore(seed = {}) {
|
||||
if (state.taskHalRuntime?.loaded) {
|
||||
runTaskHalCommandSequence([
|
||||
{ type: "EMC_JOINT_HOME", joint: -1 },
|
||||
], { operatorMessage: "task/HAL machine homed" }).catch(() => {});
|
||||
], {
|
||||
operatorMessage: "task/HAL machine homed",
|
||||
preserveMachine: {
|
||||
...state.machine,
|
||||
allHomed: true,
|
||||
},
|
||||
}).catch(() => {});
|
||||
}
|
||||
setState({
|
||||
machine: {
|
||||
@@ -1493,6 +1538,7 @@ export function createSimulationStore(seed = {}) {
|
||||
programExecutionMotionIndex: 0,
|
||||
programExecutionSampleIndex: 0,
|
||||
programRuntimeFeedback: null,
|
||||
programLineExecution: {},
|
||||
axisPose: initialAxisPose,
|
||||
preview: { ...state.preview, pathPoints: Math.max(state.programLines.length, 1) },
|
||||
operatorMessage: "program reloaded",
|
||||
@@ -1758,6 +1804,57 @@ export function createSimulationStore(seed = {}) {
|
||||
return status;
|
||||
};
|
||||
|
||||
const runReadySequence = async () => {
|
||||
if (!state.machineFileStaging?.selectedGcodeSourceRel) {
|
||||
const sourceRel = defaultLinuxCncGcodeSourceForState(state)?.sourceRel;
|
||||
if (sourceRel) {
|
||||
dispatch({ type: "LOAD_LINUXCNC_GCODE_SOURCE", sourceRel });
|
||||
await waitForStatePredicate((nextState) => nextState.machineFileStaging?.selectedGcodeSourceRel === sourceRel);
|
||||
}
|
||||
}
|
||||
if (state.taskHalRuntime?.loaded) {
|
||||
await initializeTaskHalSession({ openProgram: true });
|
||||
await runTaskHalCommandSequence([
|
||||
{ type: "EMC_TASK_SET_STATE", state: "ON" },
|
||||
{ type: "EMC_JOINT_HOME", joint: -1 },
|
||||
{ type: "EMC_TASK_SET_MODE", mode: "AUTO" },
|
||||
], {
|
||||
taskCycles: 3,
|
||||
operatorMessage: "RUN ready: power on, homed, auto mode",
|
||||
allowFixtureSession: false,
|
||||
preserveMachine: {
|
||||
powerOn: true,
|
||||
estopActive: false,
|
||||
taskState: "on",
|
||||
mode: "auto",
|
||||
allHomed: true,
|
||||
},
|
||||
});
|
||||
const tcpKinsType = state.profile.kinematicsParameters.switchkinsTypes.find((type) => type.value === 1)?.webKinsType || "tcp-xyzac";
|
||||
dispatch({ type: "SET_KINS_TYPE", kinsType: tcpKinsType });
|
||||
return state;
|
||||
}
|
||||
const tcpKinsType = state.profile.kinematicsParameters.switchkinsTypes.find((type) => type.value === 1)?.webKinsType || "tcp-xyzac";
|
||||
setState({
|
||||
machine: {
|
||||
...state.machine,
|
||||
powerOn: true,
|
||||
estopActive: false,
|
||||
taskState: "on",
|
||||
mode: "auto",
|
||||
allHomed: true,
|
||||
interpState: "idle",
|
||||
interpResumeState: "idle",
|
||||
taskPaused: false,
|
||||
},
|
||||
runState: "idle",
|
||||
kinsType: tcpKinsType,
|
||||
rtcpState: "on",
|
||||
operatorMessage: "RUN ready: power on, homed, auto mode",
|
||||
});
|
||||
return state;
|
||||
};
|
||||
|
||||
const loadTaskHalMotionPlanForSession = async (session = state.taskHalSession) => {
|
||||
if (!state.taskHalRuntime?.loaded || typeof state.taskHalRuntime.loadProgramMotionPlan !== "function") {
|
||||
return null;
|
||||
@@ -1882,6 +1979,7 @@ export function createSimulationStore(seed = {}) {
|
||||
operatorMessage = "task/HAL command complete",
|
||||
pendingJogCommand = null,
|
||||
allowFixtureSession = true,
|
||||
preserveMachine = null,
|
||||
} = {}) => {
|
||||
if (!state.taskHalRuntime?.loaded) {
|
||||
throw new Error("LinuxCNC task/HAL runtime not attached");
|
||||
@@ -1910,7 +2008,7 @@ export function createSimulationStore(seed = {}) {
|
||||
if (state.taskHalExecutionSequence !== sequence) {
|
||||
return status;
|
||||
}
|
||||
dispatch({ type: "TASK_HAL_STATUS_APPLIED", status, operatorMessage });
|
||||
dispatch({ type: "TASK_HAL_STATUS_APPLIED", status, operatorMessage, preserveMachine });
|
||||
return status;
|
||||
} catch (error) {
|
||||
dispatch({
|
||||
@@ -2277,6 +2375,11 @@ function applyTaskHalStatusPatch(state, status, operatorMessage, {
|
||||
&& (runState === "running" || runState === "mdi");
|
||||
const nextTickCount = loopActive ? Number(state.taskHalStatusLoop.tickCount || 0) + 1 : Number(state.taskHalStatusLoop?.tickCount || 0);
|
||||
const feedbackHistory = [runtimeFeedback, ...(state.programRuntimeFeedbackHistory || [])].slice(0, 100);
|
||||
const lineStatus = runState === "complete"
|
||||
? "done"
|
||||
: runState === "running" || runState === "mdi"
|
||||
? "running"
|
||||
: runState;
|
||||
|
||||
return {
|
||||
taskHalStatus: status,
|
||||
@@ -2315,6 +2418,10 @@ function applyTaskHalStatusPatch(state, status, operatorMessage, {
|
||||
},
|
||||
programRuntimeFeedback: runtimeFeedback,
|
||||
programRuntimeFeedbackHistory: feedbackHistory,
|
||||
programLineExecution: createProgramLineExecutionPatch(state.programLineExecution, runtimeFeedback, {
|
||||
status: lineStatus,
|
||||
source: "linuxcnc-task-motion-hal-wasm",
|
||||
}),
|
||||
operatorMessage,
|
||||
};
|
||||
}
|
||||
@@ -2451,6 +2558,41 @@ function createTaskHalRuntimeFeedback(state, status, axisPose, activeLine) {
|
||||
};
|
||||
}
|
||||
|
||||
function createProgramLineExecutionPatch(previous = {}, feedback = null, {
|
||||
status = "running",
|
||||
source = null,
|
||||
} = {}) {
|
||||
const line = Number(feedback?.line || 0);
|
||||
if (!Number.isFinite(line) || line <= 0) {
|
||||
return previous || {};
|
||||
}
|
||||
const axisPose = feedback.axisPose || {};
|
||||
return {
|
||||
...(previous || {}),
|
||||
[line]: {
|
||||
status,
|
||||
source: source || feedback.sourceMode || "unknown",
|
||||
line,
|
||||
feed: Number(feedback.currentVelocityMmPerMin || 0),
|
||||
requestedFeed: Number(feedback.requestedVelocityMmPerMin || 0),
|
||||
feedMode: feedback.feedMode || null,
|
||||
axisPose: pickExecutionAxes(axisPose),
|
||||
taskCycle: Number(feedback.taskCycle || 0),
|
||||
servoCycle: Number(feedback.cycle || 0),
|
||||
sampleIndex: Number(feedback.sampleIndex || 0),
|
||||
motionIndex: Number(feedback.motionIndex || 0),
|
||||
updatedAt: new Date().toISOString(),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function pickExecutionAxes(axisPose = {}) {
|
||||
return Object.fromEntries(["x", "y", "z", "a", "b", "c"].map((axis) => [
|
||||
axis,
|
||||
Number(axisPose[axis] || 0),
|
||||
]));
|
||||
}
|
||||
|
||||
function normalizeTaskHalTaskState(value) {
|
||||
const state = String(value || "").toLowerCase().replaceAll("_", "-");
|
||||
if (state === "on") return "on";
|
||||
|
||||
Reference in New Issue
Block a user