Fix paused SIM_STEP resume sequencing

This commit is contained in:
2026-09-02 11:40:28 +08:00
parent 32adda73d6
commit cd0286a3d6
6 changed files with 71 additions and 14 deletions

View File

@@ -1188,7 +1188,8 @@ export class SimSession {
});
}
if (Number.isSafeInteger(input.simulation_tick) && input.simulation_tick >= this.tick) this.tick = input.simulation_tick;
const eventTick = input.kind === "SIM_STEP" && Number.isSafeInteger(input.payload?.cycles)
const pausedStep = input.kind === "SIM_STEP" && this.xyzacProgram && (this.task.state.state === "PAUSED" || this.xyzacProgram.snapshot().status === 3);
const eventTick = input.kind === "SIM_STEP" && Number.isSafeInteger(input.payload?.cycles) && !pausedStep
? this.tick + input.payload.cycles : this.tick;
try {
this.timeline.appendEvent(input.seq, eventTick, input.kind, input.payload ?? {});
@@ -1535,6 +1536,26 @@ export class SimSession {
const cycles = input.payload?.cycles;
const limit = validateLimit("max_tick_step", cycles);
if (limit.status !== "accepted") return finish(this.envelope("ERROR", input, { ...limit, operation_id: input.operation_id ?? null, simulation_tick: this.tick, retryable: false }), "failed");
// A poll may already be in flight when PROGRAM_PAUSE reaches the
// worker. LinuxCNC keeps the paused task/TP state stable; accept that
// transport frame as a no-op instead of rejecting it at the protocol
// layer and leaving the next PROGRAM_RESUME with a sequence gap.
if (this.xyzacProgram && (this.task.state.state === "PAUSED" || this.xyzacProgram.snapshot().status === 3)) {
const pausedProgram = this.xyzacProgram.snapshot();
return finish(this.envelope("COMMAND_RESULT", input, {
status: "verified",
cycles,
program_steps: [],
execution_trace: [],
snapshot_mode: input.payload?.response === "motion_delta" ? "motion_delta" : "full",
program: pausedProgram,
task: this.task.export(),
wasm_motion: this.wasmMotion.read(),
motion: this.wasmMotionProjection(),
motion_authority: "wasm",
operation_id: input.operation_id ?? null,
}), "verified");
}
let program_steps = [];
const motion_trace = [];
let sourceLookaheadReady = false;

View File

@@ -30,6 +30,9 @@ const cursorPaused = paused.payload.program.current_line;
const pausedSnapshot = send("SNAPSHOT_REQUEST", "paused-snapshot");
assert.equal(pausedSnapshot.payload.task.state, "PAUSED");
assert.equal(pausedSnapshot.payload.panel_snapshot.program.current_line, cursorPaused);
const pausedPoll = send("SIM_STEP", "paused-poll", { cycles: 5, response: "motion_delta" });
assert.equal(pausedPoll.payload.task.state, "PAUSED");
assert.equal(pausedPoll.payload.program.program_status, "paused");
const resumed = send("PROGRAM_RESUME", "resume");
assert.equal(resumed.payload.task.state, "RUNNING");
const second = send("SIM_STEP", "step-2", { cycles: 1 });