Show line-by-line live G-code execution trace

This commit is contained in:
2026-08-29 07:51:44 +08:00
parent 43670525d6
commit 55627010c3
7 changed files with 63 additions and 33 deletions

View File

@@ -24,6 +24,7 @@ export type FrontendState = {
axisState: AxisStateView | null;
gates: Record<string, { action: string; enabled: boolean; reason: string }>;
toolpath: Array<{ id: number; source_line?: number | null; start: Record<string, number>; end: Record<string, number>; active?: boolean }>;
executionTrace: Array<{ line: number; text: string; program_status?: string | null }>;
};
export const INITIAL_STATE: FrontendState = {
@@ -48,6 +49,7 @@ export const INITIAL_STATE: FrontendState = {
axisState: null,
gates: {},
toolpath: [],
executionTrace: [],
};
function payload<T>(message: MessageEnvelope): T {
@@ -56,6 +58,12 @@ function payload<T>(message: MessageEnvelope): T {
function projection(result: Record<string, unknown>, message: MessageEnvelope, previous: FrontendState) {
const panel = result.panel_snapshot as PanelSnapshotV1 | undefined;
const trace = Array.isArray(result.execution_trace)
? (result.execution_trace as Array<Record<string, unknown>>)
.map((entry) => ({ line: Number(entry.line), text: String(entry.text ?? ""), program_status: entry.program_status ? String(entry.program_status) : null }))
.filter((entry) => Number.isSafeInteger(entry.line) && entry.line > 0)
: [];
const executionTrace = trace.length ? [...previous.executionTrace, ...trace].slice(-32) : previous.executionTrace;
const delta = result.motion_sample as { tick?: number; pose?: Record<string, number>; joints?: number[]; active_segment_id?: number; active_progress?: number } | undefined;
if (!panel && delta && previous.snapshot) {
const pose = delta.pose ?? {};
@@ -89,6 +97,7 @@ function projection(result: Record<string, unknown>, message: MessageEnvelope, p
program: (result.program as Record<string, unknown>) ?? previous.program,
axisState: (result.axis_state as AxisStateView) ?? previous.axisState,
gates: (result.gates as FrontendState["gates"]) ?? previous.gates,
executionTrace,
};
}
if (panel?.schema === "axis-panel-snapshot.v1") {
@@ -145,6 +154,7 @@ function projection(result: Record<string, unknown>, message: MessageEnvelope, p
hal: panel.hal ?? previous.hal,
axisState: panel.axis_state,
gates: { ...panel.gates, jog: panel.gates.jogStart, load: panel.gates.load, run: panel.gates.run, step: panel.gates.step, pause: panel.gates.pause, resume: panel.gates.resume, abort: panel.gates.abort, mdi: panel.gates.mdi, home: panel.gates.home },
executionTrace,
};
}
const wasmMotion = (result.wasm_motion as { state?: Record<string, unknown> } | undefined)?.state;
@@ -186,7 +196,7 @@ function projection(result: Record<string, unknown>, message: MessageEnvelope, p
for (const segment of nextToolpath) segment.active = false;
}
const snapshot = { simulation_tick: message.simulation_tick ?? previous.tick, state_hash: String(result.state_hash ?? previous.snapshot?.state_hash ?? ""), task: result.task as SimSnapshotV1["task"], motion: { axes, joints, velocity: Array.isArray(motionState.velocity) ? motionState.velocity as number[] : [], homed: typeof motionState.homed === "boolean" ? motionState.homed : undefined, homed_axes: Array.isArray(motionState.homed_axes) ? motionState.homed_axes as boolean[] : undefined }, authoritative } satisfies SimSnapshotV1;
return { snapshot, toolpath: nextToolpath, task: (result.task as Record<string, unknown>) ?? previous.task, program: programResult as Record<string, unknown> ?? previous.program, devices: (result.devices as Record<string, unknown>) ?? previous.devices, deviceIo: (result.device_io as Record<string, unknown>) ?? previous.deviceIo, hal: (result.hal_runtime as Record<string, unknown>) ?? previous.hal, plc: (result.plc as Record<string, unknown>) ?? previous.plc, python: (result.python as Record<string, unknown>) ?? previous.python, ioAck: (result.io_ack as Record<string, unknown>) ?? previous.ioAck, axisState: (result.axis_state as AxisStateView) ?? previous.axisState, gates: (result.gates as FrontendState["gates"]) ?? previous.gates };
return { snapshot, toolpath: nextToolpath, task: (result.task as Record<string, unknown>) ?? previous.task, program: programResult as Record<string, unknown> ?? previous.program, devices: (result.devices as Record<string, unknown>) ?? previous.devices, deviceIo: (result.device_io as Record<string, unknown>) ?? previous.deviceIo, hal: (result.hal_runtime as Record<string, unknown>) ?? previous.hal, plc: (result.plc as Record<string, unknown>) ?? previous.plc, python: (result.python as Record<string, unknown>) ?? previous.python, ioAck: (result.io_ack as Record<string, unknown>) ?? previous.ioAck, axisState: (result.axis_state as AxisStateView) ?? previous.axisState, gates: (result.gates as FrontendState["gates"]) ?? previous.gates, executionTrace };
}
export function reduceFrontendState(state: FrontendState, message: MessageEnvelope): FrontendState {