diff --git a/qa/web-rtcp-5axis-site-test/capture-test-linuxcnc-source-run.mjs b/qa/web-rtcp-5axis-site-test/capture-test-linuxcnc-source-run.mjs index c8dfaf7..6140cc5 100644 --- a/qa/web-rtcp-5axis-site-test/capture-test-linuxcnc-source-run.mjs +++ b/qa/web-rtcp-5axis-site-test/capture-test-linuxcnc-source-run.mjs @@ -90,17 +90,26 @@ try { await wait(800); await captureStep("01-initial-ui", "初始界面", "确认浏览器应用、五轴预览区、G-code 区和 DRO 面板已渲染。"); - await page.evaluate(async ({ ini }) => { - await window.webRtcp5AxisSimulation.stageMachineFiles({ iniText: ini, storageMode: "memory" }); - }, { ini: iniText }); + await page.evaluate(async ({ ini, gcode, sourceRel }) => { + await window.webRtcp5AxisSimulation.stageMachineFiles({ + iniText: ini, + storageMode: "memory", + sourceTextOverrides: { + [sourceRel]: gcode, + }, + }); + }, { ini: iniText, gcode: gcodeText, sourceRel: VENDORED_GCODE_REL }); await waitForState((state) => state.machineFileStaging?.status === "staged", 20000, "test INI staged"); await captureStep("02-stage-test-ini", "Stage test_linuxcnc_source INI", "使用 working_run/test_linuxcnc_source/xyzac-trt.ini 重新 staging machine files。"); - await page.select('[data-action="select-linuxcnc-gcode-source"]', VENDORED_GCODE_REL); + await page.evaluate(({ sourceRel }) => { + window.webRtcp5AxisSimulation.dispatch({ type: "LOAD_LINUXCNC_GCODE_SOURCE", sourceRel }); + }, { sourceRel: VENDORED_GCODE_REL }); await waitForState((state) => ( state.activeProgram?.endsWith("impeller-7bl-xyzac.ngc") && state.programExecutionSourceMode === "linuxcnc-interpreter-wasm" && - state.taskHalSession?.programPath?.endsWith("impeller-7bl-xyzac.ngc") + state.taskHalSession?.programPath?.endsWith("impeller-7bl-xyzac.ngc") && + state.loadedSourceBytes === sourceEvidence.gcodeBytes ), 25000, "impeller program loaded"); await waitForCanvasReady(); await wait(1200); @@ -192,6 +201,8 @@ async function captureRunSample(elapsedMs, name, title) { taskCycle: state.programRuntimeFeedback?.taskCycle ?? null, servoCycle: state.programRuntimeFeedback?.cycle ?? null, historyLength: state.programRuntimeFeedbackHistory?.length || 0, + lineExecution: state.currentLineExecution, + lineExecutionVisible: state.currentLineExecutionVisible, executedPathPoints: Number(step.dataset.threeExecutedPathPoints || 0), currentSegmentHighlight: step.dataset.threeCurrentSegmentHighlight, }; @@ -236,6 +247,7 @@ function addChecks() { check("TCP/刀轴线可见", previewStep?.dataset?.threeTcpMarker === "sphere" && previewStep?.dataset?.threeToolAxisMarker === "line", `tcp=${previewStep?.dataset?.threeTcpMarker}, axis=${previewStep?.dataset?.threeToolAxisMarker}`), check("RUN 采样数量", runSamples.length >= 5, `samples=${runSamples.length}`), check("每行执行高亮同步", runSamples.every((sample) => sample.activeLineMatchesUi), runSamples.map((sample) => `${sample.activeLine}/${sample.activeUiLine}`).join(", ")), + check("程序列表显示每行执行过程", runSamples.every((sample) => sample.lineExecution?.line === sample.activeLine && sample.lineExecutionVisible === true), runSamples.map((sample) => `${sample.activeLine}:${sample.lineExecution?.status || "-"}:${sample.lineExecutionVisible}`).join(", ")), check("执行轨迹可见", runSamples.every((sample) => sample.executedPathPoints >= 1 && sample.currentSegmentHighlight === "ok"), runSamples.map((sample) => `${sample.executedPathPoints}/${sample.currentSegmentHighlight}`).join(", ")), check("实时轴值来自 task/HAL feedback", runSamples.every((sample) => sample.feedbackSource === "linuxcnc-task-motion-hal-wasm" && sample.droMatchesAxisPose), runSamples.map((sample) => `${sample.feedbackSource}/${sample.droMatchesAxisPose}`).join(", ")), check("RUN feed 不是固定 3600 mm/min", movingVelocities.length > 0 && movingVelocities.every((velocity) => Math.abs(velocity - 3600) > 0.001), runSamples.map((sample) => `${sample.elapsedMs}ms=${sample.velocity}`).join(", ")), @@ -256,6 +268,7 @@ function summarizeState(state) { machineProfile: state.machineProfile, iniPath: state.iniConfigReadiness?.path || state.linuxCncIniConfig?.path || null, selectedGcodeSourceRel: state.machineFileStaging?.selectedGcodeSourceRel || null, + loadedSourceBytes: state.machineFileStaging?.save?.files?.find((file) => file.sourceRel === state.machineFileStaging?.selectedGcodeSourceRel)?.bytes || null, taskHalProgramPath: state.taskHalSession?.programPath || null, runState: state.runState, activeLine: state.activeLine, @@ -267,6 +280,8 @@ function summarizeState(state) { axisPose: pickAxes(state.axisPose), programRuntimeFeedback: state.programRuntimeFeedback, currentTimingSegment, + currentLineExecution: state.programLineExecution?.[state.activeLine] || null, + currentLineExecutionVisible: Boolean(state.__activeUiLineExecutionText?.includes("F ") && state.__activeUiLineExecutionText?.includes("cycle")), feedbackHistoryLength: state.programRuntimeFeedbackHistory?.length || 0, taskHalStatusLoop: state.taskHalStatusLoop, taskHalStatus: state.taskHalStatus ? { @@ -316,7 +331,12 @@ async function waitForCanvasReady(timeoutMs = 20000) { async function getStateWithUi() { return page.evaluate(() => { const state = JSON.parse(JSON.stringify(window.webRtcp5AxisSimulation.getState())); - state.__activeUiLine = Number(document.querySelector(".gcode-row.active")?.dataset.programLine || 0); + const activeRow = document.querySelector(".gcode-row.active"); + state.__activeUiLine = Number(activeRow?.dataset.programLine || 0); + state.__activeUiLineExecutionText = activeRow?.querySelector("[data-line-execution]")?.textContent || ""; + state.loadedSourceBytes = state.machineFileStaging?.save?.files + ?.find((file) => file.sourceRel === state.machineFileStaging?.selectedGcodeSourceRel) + ?.bytes || null; return state; }); } diff --git a/qa/web-rtcp-5axis-site-test/output/cloud-run-after-deploy/01-loaded.png b/qa/web-rtcp-5axis-site-test/output/cloud-run-after-deploy/01-loaded.png new file mode 100644 index 0000000..e66fd04 Binary files /dev/null and b/qa/web-rtcp-5axis-site-test/output/cloud-run-after-deploy/01-loaded.png differ diff --git a/qa/web-rtcp-5axis-site-test/output/cloud-run-after-deploy/02-impeller-loaded.png b/qa/web-rtcp-5axis-site-test/output/cloud-run-after-deploy/02-impeller-loaded.png new file mode 100644 index 0000000..b1c399c Binary files /dev/null and b/qa/web-rtcp-5axis-site-test/output/cloud-run-after-deploy/02-impeller-loaded.png differ diff --git a/qa/web-rtcp-5axis-site-test/output/cloud-run-after-deploy/03-run-ready.png b/qa/web-rtcp-5axis-site-test/output/cloud-run-after-deploy/03-run-ready.png new file mode 100644 index 0000000..32c3b2b Binary files /dev/null and b/qa/web-rtcp-5axis-site-test/output/cloud-run-after-deploy/03-run-ready.png differ diff --git a/qa/web-rtcp-5axis-site-test/output/cloud-run-after-deploy/04-run-0500.png b/qa/web-rtcp-5axis-site-test/output/cloud-run-after-deploy/04-run-0500.png new file mode 100644 index 0000000..758c804 Binary files /dev/null and b/qa/web-rtcp-5axis-site-test/output/cloud-run-after-deploy/04-run-0500.png differ diff --git a/qa/web-rtcp-5axis-site-test/output/cloud-run-after-deploy/05-run-3000.png b/qa/web-rtcp-5axis-site-test/output/cloud-run-after-deploy/05-run-3000.png new file mode 100644 index 0000000..ed337f5 Binary files /dev/null and b/qa/web-rtcp-5axis-site-test/output/cloud-run-after-deploy/05-run-3000.png differ diff --git a/qa/web-rtcp-5axis-site-test/output/cloud-run-after-deploy/06-run-7000.png b/qa/web-rtcp-5axis-site-test/output/cloud-run-after-deploy/06-run-7000.png new file mode 100644 index 0000000..b2a11a4 Binary files /dev/null and b/qa/web-rtcp-5axis-site-test/output/cloud-run-after-deploy/06-run-7000.png differ diff --git a/qa/web-rtcp-5axis-site-test/output/cloud-run-after-deploy/cloud-run-after-deploy.json b/qa/web-rtcp-5axis-site-test/output/cloud-run-after-deploy/cloud-run-after-deploy.json new file mode 100644 index 0000000..e720dde --- /dev/null +++ b/qa/web-rtcp-5axis-site-test/output/cloud-run-after-deploy/cloud-run-after-deploy.json @@ -0,0 +1,1182 @@ +{ + "generatedAt": "2026-06-23T07:49:51.440Z", + "target": "https://82.156.24.101:8092/", + "steps": [ + { + "name": "01-loaded", + "screenshot": "/home/meswork/cnc_wams/qa/web-rtcp-5axis-site-test/output/cloud-run-after-deploy/01-loaded.png", + "state": { + "runState": "idle", + "activeLine": 9, + "machine": { + "powerOn": false, + "estopActive": false, + "taskState": "estop-reset", + "mode": "manual", + "interpState": "idle", + "interpResumeState": "idle", + "taskPaused": false, + "allHomed": false, + "noForceHoming": false, + "jogAxis": "x", + "jogIncrement": 1, + "mdiCommand": "G0 X0 Y0 Z0", + "mdiDistanceMode": "absolute", + "resetCount": 0 + }, + "rtcpState": "on", + "kinsType": "tcp-xyzac", + "operatorMessage": "LinuxCNC interpreter motion events 2, switchkins M428/M429", + "selectedGcodeSourceRel": "configs/sim/axis/vismach/5axis/table-rotary-tilting/demos/boat-xyzac.ngc", + "programExecutionSourceMode": "linuxcnc-interpreter-wasm", + "motionEventCount": 2, + "taskHalStatusLoop": { + "apiName": "web-rtcp-5axis-task-hal-status-loop", + "active": false, + "sequence": 0, + "profileId": null, + "iniPath": null, + "kinematicsModuleId": null, + "tickCount": 0, + "batchSize": 5, + "intervalMs": 25, + "taskPeriodNs": 10000000, + "servoPeriodNs": 1000000, + "lastStatusAt": null, + "lastError": null, + "stopReason": null, + "semanticBoundary": "js_status_polling_loop_for_linuxcnc_task_hal_motion_status" + }, + "taskHalStatus": null, + "feedback": { + "apiName": "web-rtcp-5axis-program-runtime-feedback", + "sourceMode": "linuxcnc-tp-runtime-sample", + "semanticBoundary": "linuxcnc_tp_run_cycle_feedback_without_hardware", + "sampleIndex": 0, + "motionIndex": 0, + "line": 10, + "type": "STRAIGHT_TRAVERSE", + "linearUnits": "mm", + "timeSeconds": 0.001, + "axisPose": { + "x": 0, + "y": 0, + "z": 0.00025, + "a": 0, + "b": 0, + "c": 0 + }, + "currentVelocityMmPerMin": 30, + "requestedVelocityMmPerMin": 2100, + "distanceToGo": 4.99975, + "dtg": { + "x": 0, + "y": 0, + "z": 4.99975 + }, + "queueDepth": 1, + "activeDepth": 1, + "cycle": 1 + }, + "feedbackHistoryLength": 0, + "lineExecution": null + }, + "ui": { + "hasRunReady": true, + "activeUiLine": 9, + "activeLineText": "running", + "currentLine": "10", + "canvas": { + "fiveAxisCanvas": "true", + "engine": "three.js r183", + "threeReady": "true", + "threeRevision": "183", + "threePathPoints": "2", + "threeExecutedPathPoints": "1", + "threeSceneObjects": "20", + "threeToolhead": "{\"x\":0,\"y\":0,\"z\":0}", + "threeSceneUnits": "m", + "threeLinearUnits": "mm", + "threeLinearUnitScaleToMeters": "0.001", + "threeToolAxis": "{\"x\":0,\"y\":0,\"z\":1}", + "threeTcpPose": "{\"x\":0,\"y\":0,\"z\":0,\"a\":0,\"c\":0}", + "threeRtcpState": "on", + "threeSelectedView": "iso", + "threeFrameApi": "web-rtcp-5axis-motion-frame", + "threeRenderer": "webgl", + "threeSceneMode": "program-preview-and-tool-execution", + "threePreviewScope": "machine-reference-and-toolpath", + "threeMachineReferenceModel": "webgl-five-axis-reference", + "threeCameraControls": "orbit-pan-zoom", + "threeProgramPreviewSource": "linuxcnc-interpreter-wasm", + "threeToolExecutionMarker": "true", + "threeTcpMarker": "sphere", + "threeToolAxisMarker": "line", + "threeToolpathPreviewSource": "linuxcnc_interpreter_canonical_motion", + "threeToolExecutionTraceSource": "linuxcnc_tp_samples_or_task_motion_hal_feedback", + "threePathFitBounds": "ok", + "threePathBoundsMeters": "{\"center\":{\"x\":0,\"y\":0,\"z\":0.002},\"size\":{\"x\":0,\"y\":0,\"z\":0.005},\"maxSpan\":0.005}", + "threeCurrentSegmentHighlight": "ok", + "threeRapidFeedVisualDistinction": "ok", + "threeNoGcodeSemanticsGeneration": "ok", + "threeRapidPathPoints": "2", + "threeFeedPathPoints": "0", + "threeArcPathPoints": "0", + "threeCurrentSegmentPoints": "2", + "threeCurrentSegmentType": "STRAIGHT_TRAVERSE" + } + } + }, + { + "name": "02-impeller-loaded", + "screenshot": "/home/meswork/cnc_wams/qa/web-rtcp-5axis-site-test/output/cloud-run-after-deploy/02-impeller-loaded.png", + "state": { + "runState": "idle", + "activeLine": 1, + "machine": { + "powerOn": false, + "estopActive": false, + "taskState": "estop-reset", + "mode": "manual", + "interpState": "idle", + "interpResumeState": "idle", + "taskPaused": false, + "allHomed": false, + "noForceHoming": false, + "jogAxis": "x", + "jogIncrement": 1, + "mdiCommand": "G0 X0 Y0 Z0", + "mdiDistanceMode": "absolute", + "resetCount": 0 + }, + "rtcpState": "on", + "kinsType": "tcp-xyzac", + "operatorMessage": "LinuxCNC task/HAL session ready /work/sim/axis/vismach/5axis/table-rotary-tilting/xyzac-trt/demos/impeller-7bl-xyzac.ngc", + "selectedGcodeSourceRel": "configs/sim/axis/vismach/5axis/table-rotary-tilting/demos/impeller-7bl-xyzac.ngc", + "taskHalProgramPath": "/work/sim/axis/vismach/5axis/table-rotary-tilting/xyzac-trt/demos/impeller-7bl-xyzac.ngc", + "programExecutionSourceMode": "linuxcnc-task-motion-hal-wasm", + "motionEventCount": 4492, + "taskHalStatusLoop": { + "apiName": "web-rtcp-5axis-task-hal-status-loop", + "active": false, + "sequence": 0, + "profileId": null, + "iniPath": null, + "kinematicsModuleId": null, + "tickCount": 0, + "batchSize": 5, + "intervalMs": 25, + "taskPeriodNs": 10000000, + "servoPeriodNs": 1000000, + "lastStatusAt": null, + "lastError": null, + "stopReason": null, + "semanticBoundary": "js_status_polling_loop_for_linuxcnc_task_hal_motion_status" + }, + "taskHalStatus": { + "ui": { + "taskState": "estop_reset", + "taskMode": "manual", + "interpState": "idle", + "execState": "done", + "taskCycle": 0, + "servoCycle": 10, + "motionQueueDepth": 0, + "halChangedPinCount": 0, + "activeLine": 1, + "motionProgramLine": 0, + "halProgramLine": 0, + "activeLineSource": "fallback", + "activeLineHalSynced": false, + "switchkinsType": 0, + "axisPose": { + "x": 0, + "y": 0, + "z": 0, + "a": 0, + "b": 0, + "c": 0 + }, + "axisPoseFrame": "work", + "currentVelocity": 0 + }, + "task": { + "state": "ESTOP_RESET", + "mode": "MANUAL", + "interpState": "IDLE", + "execState": "DONE", + "cycle": 1, + "openProgram": "/work/sim/axis/vismach/5axis/table-rotary-tilting/xyzac-trt/demos/impeller-7bl-xyzac.ngc", + "openedLineCount": 4510, + "openedSourceLineCount": 4510, + "executableLineCount": 4498, + "nextProgramLine": 0 + }, + "summary": { + "taskRuntimeReady": true, + "motionRuntimeReady": true, + "halRuntimeReady": true, + "halSyncReady": true, + "taskHalComparisonReady": true, + "switchkinsRemapHalSync": true, + "nativeTaskReady": true, + "nativeHalSyncReady": true, + "fullLinuxCncProgramExecutionReady": false, + "hardwareDrive": false, + "hostRealtimeKernel": false + } + }, + "feedback": { + "apiName": "web-rtcp-5axis-program-runtime-feedback", + "sourceMode": "linuxcnc-task-motion-hal-wasm", + "semanticBoundary": "linuxcnc_task_motion_hal_wasm_simulation_runtime", + "sampleIndex": 10, + "motionIndex": 0, + "line": 1, + "motionProgramLine": 0, + "halProgramLine": 0, + "activeLineSource": "fallback", + "activeLineHalSynced": false, + "type": "TASK_MOTION", + "timeSeconds": 0, + "axisPose": { + "x": 0, + "y": 0, + "z": 0, + "a": 0, + "b": 0, + "c": 0 + }, + "currentVelocityMmPerMin": 0, + "requestedVelocityMmPerMin": 0, + "distanceToGo": 0, + "dtg": { + "x": 0, + "y": 0, + "z": 0 + }, + "queueDepth": 0, + "activeDepth": 0, + "cycle": 10, + "taskCycle": 1, + "halChangedPinCount": 0 + }, + "feedbackHistoryLength": 1, + "lineExecution": { + "status": "idle", + "source": "linuxcnc-task-motion-hal-wasm", + "line": 1, + "feed": 0, + "requestedFeed": 0, + "feedMode": null, + "axisPose": { + "x": 0, + "y": 0, + "z": 0, + "a": 0, + "b": 0, + "c": 0 + }, + "taskCycle": 1, + "servoCycle": 10, + "sampleIndex": 10, + "motionIndex": 0, + "updatedAt": "2026-06-23T07:49:11.339Z" + } + }, + "ui": { + "hasRunReady": true, + "activeUiLine": 1, + "activeLineText": "idle | F 0.0 | X 0.000 | Y 0.000 | Z 0.000 | A 0.000 | C 0.000 | cycle 1/10", + "currentLine": "1", + "canvas": { + "fiveAxisCanvas": "true", + "engine": "three.js r183", + "threeReady": "true", + "threeRevision": "183", + "threePathPoints": "4492", + "threeExecutedPathPoints": "1", + "threeSceneObjects": "20", + "threeToolhead": "{\"x\":0,\"y\":0,\"z\":0}", + "threeSceneUnits": "m", + "threeLinearUnits": "mm", + "threeLinearUnitScaleToMeters": "0.001", + "threeToolAxis": "{\"x\":0,\"y\":0,\"z\":1}", + "threeTcpPose": "{\"x\":0,\"y\":0,\"z\":0,\"a\":0,\"c\":0}", + "threeRtcpState": "on", + "threeSelectedView": "iso", + "threeFrameApi": "web-rtcp-5axis-motion-frame", + "threeRenderer": "webgl", + "threeSceneMode": "program-preview-and-tool-execution", + "threePreviewScope": "machine-reference-and-toolpath", + "threeMachineReferenceModel": "webgl-five-axis-reference", + "threeCameraControls": "orbit-pan-zoom", + "threeProgramPreviewSource": "linuxcnc-interpreter-wasm", + "threeToolExecutionMarker": "true", + "threeTcpMarker": "sphere", + "threeToolAxisMarker": "line", + "threeToolpathPreviewSource": "linuxcnc_interpreter_canonical_motion", + "threeToolExecutionTraceSource": "linuxcnc_tp_samples_or_task_motion_hal_feedback", + "threePathFitBounds": "ok", + "threePathBoundsMeters": "{\"center\":{\"x\":-0.001,\"y\":0,\"z\":0.019},\"size\":{\"x\":0.088,\"y\":0.089,\"z\":0.043},\"maxSpan\":0.089214}", + "threeCurrentSegmentHighlight": "ok", + "threeRapidFeedVisualDistinction": "ok", + "threeNoGcodeSemanticsGeneration": "ok", + "threeRapidPathPoints": "186", + "threeFeedPathPoints": "4306", + "threeArcPathPoints": "0", + "threeCurrentSegmentPoints": "1", + "threeCurrentSegmentType": "STRAIGHT_TRAVERSE" + } + } + }, + { + "name": "03-run-ready", + "screenshot": "/home/meswork/cnc_wams/qa/web-rtcp-5axis-site-test/output/cloud-run-after-deploy/03-run-ready.png", + "state": { + "runState": "idle", + "activeLine": 1, + "machine": { + "powerOn": true, + "estopActive": false, + "taskState": "on", + "mode": "auto", + "interpState": "idle", + "interpResumeState": "idle", + "taskPaused": false, + "allHomed": true, + "noForceHoming": false, + "jogAxis": "x", + "jogIncrement": 1, + "mdiCommand": "G0 X0 Y0 Z0", + "mdiDistanceMode": "absolute", + "resetCount": 0 + }, + "rtcpState": "on", + "kinsType": "tcp-xyzac", + "operatorMessage": "RUN ready: power on, homed, auto mode", + "selectedGcodeSourceRel": "configs/sim/axis/vismach/5axis/table-rotary-tilting/demos/impeller-7bl-xyzac.ngc", + "taskHalProgramPath": "/work/sim/axis/vismach/5axis/table-rotary-tilting/xyzac-trt/demos/impeller-7bl-xyzac.ngc", + "programExecutionSourceMode": "linuxcnc-task-motion-hal-wasm", + "motionEventCount": 4492, + "taskHalStatusLoop": { + "apiName": "web-rtcp-5axis-task-hal-status-loop", + "active": false, + "sequence": 0, + "profileId": null, + "iniPath": null, + "kinematicsModuleId": null, + "tickCount": 0, + "batchSize": 5, + "intervalMs": 25, + "taskPeriodNs": 10000000, + "servoPeriodNs": 1000000, + "lastStatusAt": null, + "lastError": null, + "stopReason": null, + "semanticBoundary": "js_status_polling_loop_for_linuxcnc_task_hal_motion_status" + }, + "taskHalStatus": { + "ui": { + "taskState": "on", + "taskMode": "auto", + "interpState": "idle", + "execState": "done", + "taskCycle": 0, + "servoCycle": 40, + "motionQueueDepth": 0, + "halChangedPinCount": 0, + "activeLine": 1, + "motionProgramLine": 1, + "halProgramLine": 1, + "activeLineSource": "motion-status", + "activeLineHalSynced": true, + "switchkinsType": 0, + "axisPose": { + "x": 0, + "y": 0, + "z": 0, + "a": 0, + "b": 0, + "c": 0 + }, + "axisPoseFrame": "work", + "currentVelocity": 3600 + }, + "task": { + "state": "ON", + "mode": "AUTO", + "interpState": "IDLE", + "execState": "DONE", + "cycle": 4, + "openProgram": "/work/sim/axis/vismach/5axis/table-rotary-tilting/xyzac-trt/demos/impeller-7bl-xyzac.ngc", + "openedLineCount": 4510, + "openedSourceLineCount": 4510, + "executableLineCount": 4498, + "nextProgramLine": 0 + }, + "summary": { + "taskRuntimeReady": true, + "motionRuntimeReady": true, + "halRuntimeReady": true, + "halSyncReady": true, + "taskHalComparisonReady": true, + "switchkinsRemapHalSync": true, + "nativeTaskReady": true, + "nativeHalSyncReady": true, + "fullLinuxCncProgramExecutionReady": false, + "hardwareDrive": false, + "hostRealtimeKernel": false + } + }, + "feedback": { + "apiName": "web-rtcp-5axis-program-runtime-feedback", + "sourceMode": "linuxcnc-task-motion-hal-wasm", + "semanticBoundary": "linuxcnc_task_motion_hal_wasm_simulation_runtime", + "sampleIndex": 40, + "motionIndex": 0, + "line": 1, + "motionProgramLine": 1, + "halProgramLine": 1, + "activeLineSource": "motion-status", + "activeLineHalSynced": true, + "type": "TASK_MOTION", + "timeSeconds": 0, + "axisPose": { + "x": 0, + "y": 0, + "z": 0, + "a": 0, + "b": 0, + "c": 0 + }, + "currentVelocityMmPerMin": 3600, + "requestedVelocityMmPerMin": 3600, + "distanceToGo": 0, + "dtg": { + "x": 0, + "y": 0, + "z": 0 + }, + "queueDepth": 0, + "activeDepth": 0, + "cycle": 40, + "taskCycle": 4, + "halChangedPinCount": 0 + }, + "feedbackHistoryLength": 3, + "lineExecution": { + "status": "idle", + "source": "linuxcnc-task-motion-hal-wasm", + "line": 1, + "feed": 3600, + "requestedFeed": 3600, + "feedMode": null, + "axisPose": { + "x": 0, + "y": 0, + "z": 0, + "a": 0, + "b": 0, + "c": 0 + }, + "taskCycle": 4, + "servoCycle": 40, + "sampleIndex": 40, + "motionIndex": 0, + "updatedAt": "2026-06-23T07:49:23.054Z" + } + }, + "ui": { + "hasRunReady": true, + "activeUiLine": 1, + "activeLineText": "idle | F 3600.0 | X 0.000 | Y 0.000 | Z 0.000 | A 0.000 | C 0.000 | cycle 4/40", + "currentLine": "1", + "canvas": { + "fiveAxisCanvas": "true", + "engine": "three.js r183", + "threeReady": "true", + "threeRevision": "183", + "threePathPoints": "4492", + "threeExecutedPathPoints": "1", + "threeSceneObjects": "20", + "threeToolhead": "{\"x\":0,\"y\":0,\"z\":0}", + "threeSceneUnits": "m", + "threeLinearUnits": "mm", + "threeLinearUnitScaleToMeters": "0.001", + "threeToolAxis": "{\"x\":0,\"y\":0,\"z\":1}", + "threeTcpPose": "{\"x\":0,\"y\":0,\"z\":0,\"a\":0,\"c\":0}", + "threeRtcpState": "on", + "threeSelectedView": "iso", + "threeFrameApi": "web-rtcp-5axis-motion-frame", + "threeRenderer": "webgl", + "threeSceneMode": "program-preview-and-tool-execution", + "threePreviewScope": "machine-reference-and-toolpath", + "threeMachineReferenceModel": "webgl-five-axis-reference", + "threeCameraControls": "orbit-pan-zoom", + "threeProgramPreviewSource": "linuxcnc-interpreter-wasm", + "threeToolExecutionMarker": "true", + "threeTcpMarker": "sphere", + "threeToolAxisMarker": "line", + "threeToolpathPreviewSource": "linuxcnc_interpreter_canonical_motion", + "threeToolExecutionTraceSource": "linuxcnc_tp_samples_or_task_motion_hal_feedback", + "threePathFitBounds": "ok", + "threePathBoundsMeters": "{\"center\":{\"x\":-0.001,\"y\":0,\"z\":0.019},\"size\":{\"x\":0.088,\"y\":0.089,\"z\":0.043},\"maxSpan\":0.089214}", + "threeCurrentSegmentHighlight": "ok", + "threeRapidFeedVisualDistinction": "ok", + "threeNoGcodeSemanticsGeneration": "ok", + "threeRapidPathPoints": "186", + "threeFeedPathPoints": "4306", + "threeArcPathPoints": "0", + "threeCurrentSegmentPoints": "1", + "threeCurrentSegmentType": "STRAIGHT_TRAVERSE" + } + } + }, + { + "name": "04-run-0500", + "screenshot": "/home/meswork/cnc_wams/qa/web-rtcp-5axis-site-test/output/cloud-run-after-deploy/04-run-0500.png", + "state": { + "runState": "running", + "activeLine": 9, + "machine": { + "powerOn": true, + "estopActive": false, + "taskState": "on", + "mode": "auto", + "interpState": "reading", + "interpResumeState": "reading", + "taskPaused": false, + "allHomed": true, + "noForceHoming": false, + "jogAxis": "x", + "jogIncrement": 1, + "mdiCommand": "G0 X0 Y0 Z0", + "mdiDistanceMode": "absolute", + "resetCount": 0 + }, + "rtcpState": "on", + "kinsType": "tcp-xyzac", + "operatorMessage": "task/HAL status tick 1", + "selectedGcodeSourceRel": "configs/sim/axis/vismach/5axis/table-rotary-tilting/demos/impeller-7bl-xyzac.ngc", + "taskHalProgramPath": "/work/sim/axis/vismach/5axis/table-rotary-tilting/xyzac-trt/demos/impeller-7bl-xyzac.ngc", + "programExecutionSourceMode": "linuxcnc-task-motion-hal-wasm", + "motionEventCount": 4492, + "taskHalStatusLoop": { + "apiName": "web-rtcp-5axis-task-hal-status-loop", + "active": true, + "sequence": 1, + "profileId": "xyzac-trt", + "iniPath": "configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzac-trt.ini", + "kinematicsModuleId": "xyzac-trt", + "tickCount": 1, + "batchSize": 5, + "intervalMs": 25, + "taskPeriodNs": 10000000, + "servoPeriodNs": 1000000, + "lastStatusAt": "2026-06-23T07:49:34.569Z", + "lastError": null, + "stopReason": null, + "semanticBoundary": "js_status_polling_loop_for_linuxcnc_task_hal_motion_status" + }, + "taskHalStatus": { + "ui": { + "taskState": "on", + "taskMode": "auto", + "interpState": "reading", + "execState": "waiting_for_motion", + "taskCycle": 0, + "servoCycle": 140, + "motionQueueDepth": 0, + "halChangedPinCount": 0, + "activeLine": 9, + "motionProgramLine": 9, + "halProgramLine": 9, + "activeLineSource": "motion-status", + "activeLineHalSynced": true, + "switchkinsType": 0, + "axisPose": { + "x": 14.3874, + "y": -22.7161, + "z": 32.2622, + "a": -71.841, + "b": 0, + "c": -35.93 + }, + "axisPoseFrame": "work", + "currentVelocity": 2100 + }, + "task": { + "state": "ON", + "mode": "AUTO", + "interpState": "READING", + "execState": "WAITING_FOR_MOTION", + "cycle": 14, + "openProgram": "/work/sim/axis/vismach/5axis/table-rotary-tilting/xyzac-trt/demos/impeller-7bl-xyzac.ngc", + "openedLineCount": 4510, + "openedSourceLineCount": 4510, + "executableLineCount": 4498, + "nextProgramLine": 9 + }, + "summary": { + "taskRuntimeReady": true, + "motionRuntimeReady": true, + "halRuntimeReady": true, + "halSyncReady": true, + "taskHalComparisonReady": true, + "switchkinsRemapHalSync": true, + "nativeTaskReady": true, + "nativeHalSyncReady": true, + "fullLinuxCncProgramExecutionReady": false, + "hardwareDrive": false, + "hostRealtimeKernel": false + } + }, + "feedback": { + "apiName": "web-rtcp-5axis-program-runtime-feedback", + "sourceMode": "linuxcnc-task-motion-hal-wasm", + "semanticBoundary": "linuxcnc_task_motion_hal_wasm_simulation_runtime", + "sampleIndex": 140, + "motionIndex": 8, + "line": 9, + "motionProgramLine": 9, + "halProgramLine": 9, + "activeLineSource": "motion-status", + "activeLineHalSynced": true, + "type": "TASK_MOTION", + "timeSeconds": 0, + "axisPose": { + "x": 14.3874, + "y": -22.7161, + "z": 32.2622, + "a": -71.841, + "b": 0, + "c": -35.93 + }, + "currentVelocityMmPerMin": 2100, + "requestedVelocityMmPerMin": 2100, + "distanceToGo": 0, + "dtg": { + "x": 0, + "y": 0, + "z": 0 + }, + "queueDepth": 0, + "activeDepth": 0, + "cycle": 140, + "taskCycle": 14, + "halChangedPinCount": 0 + }, + "feedbackHistoryLength": 1, + "lineExecution": { + "status": "running", + "source": "linuxcnc-task-motion-hal-wasm", + "line": 9, + "feed": 2100, + "requestedFeed": 2100, + "feedMode": null, + "axisPose": { + "x": 14.3874, + "y": -22.7161, + "z": 32.2622, + "a": -71.841, + "b": 0, + "c": -35.93 + }, + "taskCycle": 14, + "servoCycle": 140, + "sampleIndex": 140, + "motionIndex": 8, + "updatedAt": "2026-06-23T07:49:34.569Z" + } + }, + "ui": { + "hasRunReady": true, + "activeUiLine": 9, + "activeLineText": "running | F 2100.0 | X 13.412 | Y -21.370 | Z 31.717 | A -71.841 | C -35.930 | cycle 19/190", + "currentLine": "9", + "canvas": { + "fiveAxisCanvas": "true", + "engine": "three.js r183", + "threeReady": "true", + "threeRevision": "183", + "threePathPoints": "4492", + "threeExecutedPathPoints": "1", + "threeSceneObjects": "20", + "threeToolhead": "{\"x\":0.013,\"y\":-0.021,\"z\":0.032}", + "threeSceneUnits": "m", + "threeLinearUnits": "mm", + "threeLinearUnitScaleToMeters": "0.001", + "threeToolAxis": "{\"x\":0.558,\"y\":0.769,\"z\":0.312}", + "threeTcpPose": "{\"x\":-33.435,\"y\":-86.014,\"z\":5.532,\"a\":-71.841,\"c\":-35.93}", + "threeRtcpState": "on", + "threeSelectedView": "iso", + "threeFrameApi": "web-rtcp-5axis-motion-frame", + "threeRenderer": "webgl", + "threeSceneMode": "program-preview-and-tool-execution", + "threePreviewScope": "machine-reference-and-toolpath", + "threeMachineReferenceModel": "webgl-five-axis-reference", + "threeCameraControls": "orbit-pan-zoom", + "threeProgramPreviewSource": "linuxcnc-interpreter-wasm", + "threeToolExecutionMarker": "true", + "threeTcpMarker": "sphere", + "threeToolAxisMarker": "line", + "threeToolpathPreviewSource": "linuxcnc_interpreter_canonical_motion", + "threeToolExecutionTraceSource": "linuxcnc_tp_samples_or_task_motion_hal_feedback", + "threePathFitBounds": "ok", + "threePathBoundsMeters": "{\"center\":{\"x\":-0.001,\"y\":0,\"z\":0.019},\"size\":{\"x\":0.088,\"y\":0.089,\"z\":0.043},\"maxSpan\":0.089214}", + "threeCurrentSegmentHighlight": "ok", + "threeRapidFeedVisualDistinction": "ok", + "threeNoGcodeSemanticsGeneration": "ok", + "threeRapidPathPoints": "186", + "threeFeedPathPoints": "4306", + "threeArcPathPoints": "0", + "threeCurrentSegmentPoints": "1", + "threeCurrentSegmentType": "STRAIGHT_TRAVERSE" + } + } + }, + { + "name": "05-run-3000", + "screenshot": "/home/meswork/cnc_wams/qa/web-rtcp-5axis-site-test/output/cloud-run-after-deploy/05-run-3000.png", + "state": { + "runState": "running", + "activeLine": 9, + "machine": { + "powerOn": true, + "estopActive": false, + "taskState": "on", + "mode": "auto", + "interpState": "reading", + "interpResumeState": "reading", + "taskPaused": false, + "allHomed": true, + "noForceHoming": false, + "jogAxis": "x", + "jogIncrement": 1, + "mdiCommand": "G0 X0 Y0 Z0", + "mdiDistanceMode": "absolute", + "resetCount": 0 + }, + "rtcpState": "on", + "kinsType": "tcp-xyzac", + "operatorMessage": "task/HAL status tick 8", + "selectedGcodeSourceRel": "configs/sim/axis/vismach/5axis/table-rotary-tilting/demos/impeller-7bl-xyzac.ngc", + "taskHalProgramPath": "/work/sim/axis/vismach/5axis/table-rotary-tilting/xyzac-trt/demos/impeller-7bl-xyzac.ngc", + "programExecutionSourceMode": "linuxcnc-task-motion-hal-wasm", + "motionEventCount": 4492, + "taskHalStatusLoop": { + "apiName": "web-rtcp-5axis-task-hal-status-loop", + "active": true, + "sequence": 1, + "profileId": "xyzac-trt", + "iniPath": "configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzac-trt.ini", + "kinematicsModuleId": "xyzac-trt", + "tickCount": 8, + "batchSize": 5, + "intervalMs": 25, + "taskPeriodNs": 10000000, + "servoPeriodNs": 1000000, + "lastStatusAt": "2026-06-23T07:49:40.075Z", + "lastError": null, + "stopReason": null, + "semanticBoundary": "js_status_polling_loop_for_linuxcnc_task_hal_motion_status" + }, + "taskHalStatus": { + "ui": { + "taskState": "on", + "taskMode": "auto", + "interpState": "reading", + "execState": "waiting_for_motion", + "taskCycle": 0, + "servoCycle": 490, + "motionQueueDepth": 0, + "halChangedPinCount": 0, + "activeLine": 9, + "motionProgramLine": 9, + "halProgramLine": 9, + "activeLineSource": "motion-status", + "activeLineHalSynced": true, + "switchkinsType": 0, + "axisPose": { + "x": 7.55697, + "y": -13.2911, + "z": 28.4442, + "a": -71.841, + "b": 0, + "c": -35.93 + }, + "axisPoseFrame": "work", + "currentVelocity": 2100 + }, + "task": { + "state": "ON", + "mode": "AUTO", + "interpState": "READING", + "execState": "WAITING_FOR_MOTION", + "cycle": 49, + "openProgram": "/work/sim/axis/vismach/5axis/table-rotary-tilting/xyzac-trt/demos/impeller-7bl-xyzac.ngc", + "openedLineCount": 4510, + "openedSourceLineCount": 4510, + "executableLineCount": 4498, + "nextProgramLine": 9 + }, + "summary": { + "taskRuntimeReady": true, + "motionRuntimeReady": true, + "halRuntimeReady": true, + "halSyncReady": true, + "taskHalComparisonReady": true, + "switchkinsRemapHalSync": true, + "nativeTaskReady": true, + "nativeHalSyncReady": true, + "fullLinuxCncProgramExecutionReady": false, + "hardwareDrive": false, + "hostRealtimeKernel": false + } + }, + "feedback": { + "apiName": "web-rtcp-5axis-program-runtime-feedback", + "sourceMode": "linuxcnc-task-motion-hal-wasm", + "semanticBoundary": "linuxcnc_task_motion_hal_wasm_simulation_runtime", + "sampleIndex": 490, + "motionIndex": 8, + "line": 9, + "motionProgramLine": 9, + "halProgramLine": 9, + "activeLineSource": "motion-status", + "activeLineHalSynced": true, + "type": "TASK_MOTION", + "timeSeconds": 0, + "axisPose": { + "x": 7.55697, + "y": -13.2911, + "z": 28.4442, + "a": -71.841, + "b": 0, + "c": -35.93 + }, + "currentVelocityMmPerMin": 2100, + "requestedVelocityMmPerMin": 2100, + "distanceToGo": 0, + "dtg": { + "x": 0, + "y": 0, + "z": 0 + }, + "queueDepth": 0, + "activeDepth": 0, + "cycle": 490, + "taskCycle": 49, + "halChangedPinCount": 0 + }, + "feedbackHistoryLength": 8, + "lineExecution": { + "status": "running", + "source": "linuxcnc-task-motion-hal-wasm", + "line": 9, + "feed": 2100, + "requestedFeed": 2100, + "feedMode": null, + "axisPose": { + "x": 7.55697, + "y": -13.2911, + "z": 28.4442, + "a": -71.841, + "b": 0, + "c": -35.93 + }, + "taskCycle": 49, + "servoCycle": 490, + "sampleIndex": 490, + "motionIndex": 8, + "updatedAt": "2026-06-23T07:49:40.075Z" + } + }, + "ui": { + "hasRunReady": true, + "activeUiLine": 10, + "activeLineText": "running | F 635.7 | X 7.164 | Y -12.749 | Z 28.225 | A -71.841 | C -35.930 | cycle 54/540", + "currentLine": "10", + "canvas": { + "fiveAxisCanvas": "true", + "engine": "three.js r183", + "threeReady": "true", + "threeRevision": "183", + "threePathPoints": "4492", + "threeExecutedPathPoints": "1", + "threeSceneObjects": "20", + "threeToolhead": "{\"x\":0.007,\"y\":-0.013,\"z\":0.028}", + "threeSceneUnits": "m", + "threeLinearUnits": "mm", + "threeLinearUnitScaleToMeters": "0.001", + "threeToolAxis": "{\"x\":0.558,\"y\":0.769,\"z\":0.312}", + "threeTcpPose": "{\"x\":-39.683,\"y\":-77.394,\"z\":2.04,\"a\":-71.841,\"c\":-35.93}", + "threeRtcpState": "on", + "threeSelectedView": "iso", + "threeFrameApi": "web-rtcp-5axis-motion-frame", + "threeRenderer": "webgl", + "threeSceneMode": "program-preview-and-tool-execution", + "threePreviewScope": "machine-reference-and-toolpath", + "threeMachineReferenceModel": "webgl-five-axis-reference", + "threeCameraControls": "orbit-pan-zoom", + "threeProgramPreviewSource": "linuxcnc-interpreter-wasm", + "threeToolExecutionMarker": "true", + "threeTcpMarker": "sphere", + "threeToolAxisMarker": "line", + "threeToolpathPreviewSource": "linuxcnc_interpreter_canonical_motion", + "threeToolExecutionTraceSource": "linuxcnc_tp_samples_or_task_motion_hal_feedback", + "threePathFitBounds": "ok", + "threePathBoundsMeters": "{\"center\":{\"x\":-0.001,\"y\":0,\"z\":0.019},\"size\":{\"x\":0.088,\"y\":0.089,\"z\":0.043},\"maxSpan\":0.089214}", + "threeCurrentSegmentHighlight": "ok", + "threeRapidFeedVisualDistinction": "ok", + "threeNoGcodeSemanticsGeneration": "ok", + "threeRapidPathPoints": "186", + "threeFeedPathPoints": "4306", + "threeArcPathPoints": "0", + "threeCurrentSegmentPoints": "1", + "threeCurrentSegmentType": "STRAIGHT_TRAVERSE" + } + } + }, + { + "name": "06-run-7000", + "screenshot": "/home/meswork/cnc_wams/qa/web-rtcp-5axis-site-test/output/cloud-run-after-deploy/06-run-7000.png", + "state": { + "runState": "running", + "activeLine": 11, + "machine": { + "powerOn": true, + "estopActive": false, + "taskState": "on", + "mode": "auto", + "interpState": "reading", + "interpResumeState": "reading", + "taskPaused": false, + "allHomed": true, + "noForceHoming": false, + "jogAxis": "x", + "jogIncrement": 1, + "mdiCommand": "G0 X0 Y0 Z0", + "mdiDistanceMode": "absolute", + "resetCount": 0 + }, + "rtcpState": "on", + "kinsType": "tcp-xyzac", + "operatorMessage": "task/HAL status tick 18", + "selectedGcodeSourceRel": "configs/sim/axis/vismach/5axis/table-rotary-tilting/demos/impeller-7bl-xyzac.ngc", + "taskHalProgramPath": "/work/sim/axis/vismach/5axis/table-rotary-tilting/xyzac-trt/demos/impeller-7bl-xyzac.ngc", + "programExecutionSourceMode": "linuxcnc-task-motion-hal-wasm", + "motionEventCount": 4492, + "taskHalStatusLoop": { + "apiName": "web-rtcp-5axis-task-hal-status-loop", + "active": true, + "sequence": 1, + "profileId": "xyzac-trt", + "iniPath": "configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzac-trt.ini", + "kinematicsModuleId": "xyzac-trt", + "tickCount": 18, + "batchSize": 5, + "intervalMs": 25, + "taskPeriodNs": 10000000, + "servoPeriodNs": 1000000, + "lastStatusAt": "2026-06-23T07:49:47.116Z", + "lastError": null, + "stopReason": null, + "semanticBoundary": "js_status_polling_loop_for_linuxcnc_task_hal_motion_status" + }, + "taskHalStatus": { + "ui": { + "taskState": "on", + "taskMode": "auto", + "interpState": "reading", + "execState": "waiting_for_motion", + "taskCycle": 0, + "servoCycle": 990, + "motionQueueDepth": 0, + "halChangedPinCount": 0, + "activeLine": 11, + "motionProgramLine": 11, + "halProgramLine": 11, + "activeLineSource": "motion-status", + "activeLineHalSynced": true, + "switchkinsType": 0, + "axisPose": { + "x": 6.34714, + "y": -12.2515, + "z": 26.4816, + "a": -71.3776, + "b": 0, + "c": -33.5032 + }, + "axisPoseFrame": "work", + "currentVelocity": 283.9176 + }, + "task": { + "state": "ON", + "mode": "AUTO", + "interpState": "READING", + "execState": "WAITING_FOR_MOTION", + "cycle": 99, + "openProgram": "/work/sim/axis/vismach/5axis/table-rotary-tilting/xyzac-trt/demos/impeller-7bl-xyzac.ngc", + "openedLineCount": 4510, + "openedSourceLineCount": 4510, + "executableLineCount": 4498, + "nextProgramLine": 11 + }, + "summary": { + "taskRuntimeReady": true, + "motionRuntimeReady": true, + "halRuntimeReady": true, + "halSyncReady": true, + "taskHalComparisonReady": true, + "switchkinsRemapHalSync": true, + "nativeTaskReady": true, + "nativeHalSyncReady": true, + "fullLinuxCncProgramExecutionReady": false, + "hardwareDrive": false, + "hostRealtimeKernel": false + } + }, + "feedback": { + "apiName": "web-rtcp-5axis-program-runtime-feedback", + "sourceMode": "linuxcnc-task-motion-hal-wasm", + "semanticBoundary": "linuxcnc_task_motion_hal_wasm_simulation_runtime", + "sampleIndex": 990, + "motionIndex": 10, + "line": 11, + "motionProgramLine": 11, + "halProgramLine": 11, + "activeLineSource": "motion-status", + "activeLineHalSynced": true, + "type": "TASK_MOTION", + "timeSeconds": 0, + "axisPose": { + "x": 6.34714, + "y": -12.2515, + "z": 26.4816, + "a": -71.3776, + "b": 0, + "c": -33.5032 + }, + "currentVelocityMmPerMin": 283.9176, + "requestedVelocityMmPerMin": 283.9176, + "distanceToGo": 0, + "dtg": { + "x": 0, + "y": 0, + "z": 0 + }, + "queueDepth": 0, + "activeDepth": 0, + "cycle": 990, + "taskCycle": 99, + "halChangedPinCount": 0 + }, + "feedbackHistoryLength": 18, + "lineExecution": { + "status": "running", + "source": "linuxcnc-task-motion-hal-wasm", + "line": 11, + "feed": 283.9176, + "requestedFeed": 283.9176, + "feedMode": null, + "axisPose": { + "x": 6.34714, + "y": -12.2515, + "z": 26.4816, + "a": -71.3776, + "b": 0, + "c": -33.5032 + }, + "taskCycle": 99, + "servoCycle": 990, + "sampleIndex": 990, + "motionIndex": 10, + "updatedAt": "2026-06-23T07:49:47.116Z" + } + }, + "ui": { + "hasRunReady": true, + "activeUiLine": 11, + "activeLineText": "running | F 283.9 | X 6.347 | Y -12.252 | Z 26.482 | A -71.378 | C -33.503 | cycle 99/990", + "currentLine": "11", + "canvas": { + "fiveAxisCanvas": "true", + "engine": "three.js r183", + "threeReady": "true", + "threeRevision": "183", + "threePathPoints": "4492", + "threeExecutedPathPoints": "1", + "threeSceneObjects": "20", + "threeToolhead": "{\"x\":0.006,\"y\":-0.012,\"z\":0.026}", + "threeSceneUnits": "m", + "threeLinearUnits": "mm", + "threeLinearUnitScaleToMeters": "0.001", + "threeToolAxis": "{\"x\":0.523,\"y\":0.79,\"z\":0.319}", + "threeTcpPose": "{\"x\":6.347,\"y\":-12.251,\"z\":26.482,\"a\":-71.378,\"c\":-33.503}", + "threeRtcpState": "on", + "threeSelectedView": "iso", + "threeFrameApi": "web-rtcp-5axis-motion-frame", + "threeRenderer": "webgl", + "threeSceneMode": "program-preview-and-tool-execution", + "threePreviewScope": "machine-reference-and-toolpath", + "threeMachineReferenceModel": "webgl-five-axis-reference", + "threeCameraControls": "orbit-pan-zoom", + "threeProgramPreviewSource": "linuxcnc-interpreter-wasm", + "threeToolExecutionMarker": "true", + "threeTcpMarker": "sphere", + "threeToolAxisMarker": "line", + "threeToolpathPreviewSource": "linuxcnc_interpreter_canonical_motion", + "threeToolExecutionTraceSource": "linuxcnc_tp_samples_or_task_motion_hal_feedback", + "threePathFitBounds": "ok", + "threePathBoundsMeters": "{\"center\":{\"x\":-0.001,\"y\":0,\"z\":0.019},\"size\":{\"x\":0.088,\"y\":0.089,\"z\":0.043},\"maxSpan\":0.089214}", + "threeCurrentSegmentHighlight": "ok", + "threeRapidFeedVisualDistinction": "ok", + "threeNoGcodeSemanticsGeneration": "ok", + "threeRapidPathPoints": "186", + "threeFeedPathPoints": "4306", + "threeArcPathPoints": "0", + "threeCurrentSegmentPoints": "1", + "threeCurrentSegmentType": "STRAIGHT_TRAVERSE" + } + } + }, + { + "name": "ERROR", + "error": "Error: Node is detached from document\n at CdpElementHandle.assertConnectedElement (file:///home/meswork/cnc_wams/qa/web-rtcp-5axis-site-test/node_modules/puppeteer-core/lib/puppeteer/api/ElementHandle.js:1300:23)\n at async CdpElementHandle.isIntersectingViewport (file:///home/meswork/cnc_wams/qa/web-rtcp-5axis-site-test/node_modules/puppeteer-core/lib/puppeteer/api/ElementHandle.js:1325:17)\n at async CdpElementHandle. (file:///home/meswork/cnc_wams/qa/web-rtcp-5axis-site-test/node_modules/puppeteer-core/lib/puppeteer/api/ElementHandle.js:118:20)\n at async CdpElementHandle.scrollIntoViewIfNeeded (file:///home/meswork/cnc_wams/qa/web-rtcp-5axis-site-test/node_modules/puppeteer-core/lib/puppeteer/api/ElementHandle.js:1307:17)\n at async CdpElementHandle.click (file:///home/meswork/cnc_wams/qa/web-rtcp-5axis-site-test/node_modules/puppeteer-core/lib/puppeteer/api/ElementHandle.js:721:13)\n at async CdpElementHandle. (file:///home/meswork/cnc_wams/qa/web-rtcp-5axis-site-test/node_modules/puppeteer-core/lib/puppeteer/api/ElementHandle.js:129:24)\n at async CdpFrame.click (file:///home/meswork/cnc_wams/qa/web-rtcp-5axis-site-test/node_modules/puppeteer-core/lib/puppeteer/api/Frame.js:749:17)\n at async file:///home/meswork/cnc_wams/qa/web-rtcp-5axis-site-test/[eval1]:96:3" + } + ], + "consoleLogs": [ + { + "type": "warn", + "text": "[.WebGL-0x9c000ec000]GL Driver Message (OpenGL, Performance, GL_CLOSE_PATH_NV, High): GPU stall due to ReadPixels", + "location": { + "url": "https://82.156.24.101:8092/" + } + }, + { + "type": "warn", + "text": "[.WebGL-0x9c000ec000]GL Driver Message (OpenGL, Performance, GL_CLOSE_PATH_NV, High): GPU stall due to ReadPixels", + "location": { + "url": "https://82.156.24.101:8092/" + } + }, + { + "type": "warn", + "text": "[.WebGL-0x9c000ec000]GL Driver Message (OpenGL, Performance, GL_CLOSE_PATH_NV, High): GPU stall due to ReadPixels", + "location": { + "url": "https://82.156.24.101:8092/" + } + }, + { + "type": "warn", + "text": "[.WebGL-0x9c000ec000]GL Driver Message (OpenGL, Performance, GL_CLOSE_PATH_NV, High): GPU stall due to ReadPixels (this message will no longer repeat)", + "location": { + "url": "https://82.156.24.101:8092/" + } + } + ], + "pageErrors": [], + "requestFailures": [] +} diff --git a/qa/web-rtcp-5axis-site-test/output/cloud-run-stop-after-deploy/01-ready.png b/qa/web-rtcp-5axis-site-test/output/cloud-run-stop-after-deploy/01-ready.png new file mode 100644 index 0000000..6c02c37 Binary files /dev/null and b/qa/web-rtcp-5axis-site-test/output/cloud-run-stop-after-deploy/01-ready.png differ diff --git a/qa/web-rtcp-5axis-site-test/output/cloud-run-stop-after-deploy/02-running.png b/qa/web-rtcp-5axis-site-test/output/cloud-run-stop-after-deploy/02-running.png new file mode 100644 index 0000000..dc33d44 Binary files /dev/null and b/qa/web-rtcp-5axis-site-test/output/cloud-run-stop-after-deploy/02-running.png differ diff --git a/qa/web-rtcp-5axis-site-test/output/cloud-run-stop-after-deploy/03-stopped.png b/qa/web-rtcp-5axis-site-test/output/cloud-run-stop-after-deploy/03-stopped.png new file mode 100644 index 0000000..8c38fef Binary files /dev/null and b/qa/web-rtcp-5axis-site-test/output/cloud-run-stop-after-deploy/03-stopped.png differ diff --git a/qa/web-rtcp-5axis-site-test/output/cloud-run-stop-after-deploy/cloud-run-stop-after-deploy.json b/qa/web-rtcp-5axis-site-test/output/cloud-run-stop-after-deploy/cloud-run-stop-after-deploy.json new file mode 100644 index 0000000..d661764 --- /dev/null +++ b/qa/web-rtcp-5axis-site-test/output/cloud-run-stop-after-deploy/cloud-run-stop-after-deploy.json @@ -0,0 +1,345 @@ +{ + "generatedAt": "2026-06-23T07:51:30.866Z", + "target": "https://82.156.24.101:8092/", + "steps": [ + { + "name": "01-ready", + "screenshot": "/home/meswork/cnc_wams/qa/web-rtcp-5axis-site-test/output/cloud-run-stop-after-deploy/01-ready.png", + "state": { + "runState": "idle", + "activeLine": 1, + "machine": { + "powerOn": true, + "estopActive": false, + "taskState": "on", + "mode": "auto", + "interpState": "idle", + "interpResumeState": "idle", + "taskPaused": false, + "allHomed": true, + "noForceHoming": false, + "jogAxis": "x", + "jogIncrement": 1, + "mdiCommand": "G0 X0 Y0 Z0", + "mdiDistanceMode": "absolute", + "resetCount": 0 + }, + "rtcpState": "on", + "kinsType": "tcp-xyzac", + "message": "RUN ready: power on, homed, auto mode", + "loop": { + "apiName": "web-rtcp-5axis-task-hal-status-loop", + "active": false, + "sequence": 0, + "profileId": null, + "iniPath": null, + "kinematicsModuleId": null, + "tickCount": 0, + "batchSize": 5, + "intervalMs": 25, + "taskPeriodNs": 10000000, + "servoPeriodNs": 1000000, + "lastStatusAt": null, + "lastError": null, + "stopReason": null, + "semanticBoundary": "js_status_polling_loop_for_linuxcnc_task_hal_motion_status" + }, + "feedback": { + "apiName": "web-rtcp-5axis-program-runtime-feedback", + "sourceMode": "linuxcnc-task-motion-hal-wasm", + "semanticBoundary": "linuxcnc_task_motion_hal_wasm_simulation_runtime", + "sampleIndex": 40, + "motionIndex": 0, + "line": 1, + "motionProgramLine": 1, + "halProgramLine": 1, + "activeLineSource": "motion-status", + "activeLineHalSynced": true, + "type": "TASK_MOTION", + "timeSeconds": 0, + "axisPose": { + "x": 0, + "y": 0, + "z": 0, + "a": 0, + "b": 0, + "c": 0 + }, + "currentVelocityMmPerMin": 3600, + "requestedVelocityMmPerMin": 3600, + "distanceToGo": 0, + "dtg": { + "x": 0, + "y": 0, + "z": 0 + }, + "queueDepth": 0, + "activeDepth": 0, + "cycle": 40, + "taskCycle": 4, + "halChangedPinCount": 0 + }, + "history": 3, + "lineExecution": { + "status": "idle", + "source": "linuxcnc-task-motion-hal-wasm", + "line": 1, + "feed": 3600, + "requestedFeed": 3600, + "feedMode": null, + "axisPose": { + "x": 0, + "y": 0, + "z": 0, + "a": 0, + "b": 0, + "c": 0 + }, + "taskCycle": 4, + "servoCycle": 40, + "sampleIndex": 40, + "motionIndex": 0, + "updatedAt": "2026-06-23T07:51:07.542Z" + }, + "source": "configs/sim/axis/vismach/5axis/table-rotary-tilting/demos/impeller-7bl-xyzac.ngc" + }, + "ui": { + "activeUiLine": 1, + "lineText": "idle | F 3600.0 | X 0.000 | Y 0.000 | Z 0.000 | A 0.000 | C 0.000 | cycle 4/40", + "stopExists": true + } + }, + { + "name": "02-running", + "screenshot": "/home/meswork/cnc_wams/qa/web-rtcp-5axis-site-test/output/cloud-run-stop-after-deploy/02-running.png", + "state": { + "runState": "running", + "activeLine": 9, + "machine": { + "powerOn": true, + "estopActive": false, + "taskState": "on", + "mode": "auto", + "interpState": "reading", + "interpResumeState": "reading", + "taskPaused": false, + "allHomed": true, + "noForceHoming": false, + "jogAxis": "x", + "jogIncrement": 1, + "mdiCommand": "G0 X0 Y0 Z0", + "mdiDistanceMode": "absolute", + "resetCount": 0 + }, + "rtcpState": "on", + "kinsType": "tcp-xyzac", + "message": "task/HAL status tick 5", + "loop": { + "apiName": "web-rtcp-5axis-task-hal-status-loop", + "active": true, + "sequence": 1, + "profileId": "xyzac-trt", + "iniPath": "configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzac-trt.ini", + "kinematicsModuleId": "xyzac-trt", + "tickCount": 5, + "batchSize": 5, + "intervalMs": 25, + "taskPeriodNs": 10000000, + "servoPeriodNs": 1000000, + "lastStatusAt": "2026-06-23T07:51:21.038Z", + "lastError": null, + "stopReason": null, + "semanticBoundary": "js_status_polling_loop_for_linuxcnc_task_hal_motion_status" + }, + "feedback": { + "apiName": "web-rtcp-5axis-program-runtime-feedback", + "sourceMode": "linuxcnc-task-motion-hal-wasm", + "semanticBoundary": "linuxcnc_task_motion_hal_wasm_simulation_runtime", + "sampleIndex": 340, + "motionIndex": 8, + "line": 9, + "motionProgramLine": 9, + "halProgramLine": 9, + "activeLineSource": "motion-status", + "activeLineHalSynced": true, + "type": "TASK_MOTION", + "timeSeconds": 0, + "axisPose": { + "x": 10.4843, + "y": -17.3304, + "z": 30.0805, + "a": -71.841, + "b": 0, + "c": -35.93 + }, + "currentVelocityMmPerMin": 2100, + "requestedVelocityMmPerMin": 2100, + "distanceToGo": 0, + "dtg": { + "x": 0, + "y": 0, + "z": 0 + }, + "queueDepth": 0, + "activeDepth": 0, + "cycle": 340, + "taskCycle": 34, + "halChangedPinCount": 0 + }, + "history": 5, + "lineExecution": { + "status": "running", + "source": "linuxcnc-task-motion-hal-wasm", + "line": 9, + "feed": 2100, + "requestedFeed": 2100, + "feedMode": null, + "axisPose": { + "x": 10.4843, + "y": -17.3304, + "z": 30.0805, + "a": -71.841, + "b": 0, + "c": -35.93 + }, + "taskCycle": 34, + "servoCycle": 340, + "sampleIndex": 340, + "motionIndex": 8, + "updatedAt": "2026-06-23T07:51:21.038Z" + }, + "source": "configs/sim/axis/vismach/5axis/table-rotary-tilting/demos/impeller-7bl-xyzac.ngc" + }, + "ui": { + "activeUiLine": 9, + "lineText": "running | F 2100.0 | X 10.484 | Y -17.330 | Z 30.081 | A -71.841 | C -35.930 | cycle 34/340", + "stopExists": true + } + }, + { + "name": "03-stopped", + "screenshot": "/home/meswork/cnc_wams/qa/web-rtcp-5axis-site-test/output/cloud-run-stop-after-deploy/03-stopped.png", + "state": { + "runState": "stopped", + "activeLine": 9, + "machine": { + "powerOn": true, + "estopActive": false, + "taskState": "on", + "mode": "auto", + "interpState": "idle", + "interpResumeState": "idle", + "taskPaused": false, + "allHomed": true, + "noForceHoming": false, + "jogAxis": "x", + "jogIncrement": 1, + "mdiCommand": "G0 X0 Y0 Z0", + "mdiDistanceMode": "absolute", + "resetCount": 0 + }, + "rtcpState": "on", + "kinsType": "tcp-xyzac", + "message": "task/HAL program stopped", + "loop": { + "apiName": "web-rtcp-5axis-task-hal-status-loop", + "active": false, + "sequence": 1, + "profileId": "xyzac-trt", + "iniPath": "configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzac-trt.ini", + "kinematicsModuleId": "xyzac-trt", + "tickCount": 7, + "batchSize": 5, + "intervalMs": 25, + "taskPeriodNs": 10000000, + "servoPeriodNs": 1000000, + "lastStatusAt": "2026-06-23T07:51:24.831Z", + "lastError": null, + "stopReason": "running", + "semanticBoundary": "js_status_polling_loop_for_linuxcnc_task_hal_motion_status" + }, + "feedback": { + "apiName": "web-rtcp-5axis-program-runtime-feedback", + "sourceMode": "linuxcnc-task-motion-hal-wasm", + "semanticBoundary": "linuxcnc_task_motion_hal_wasm_simulation_runtime", + "sampleIndex": 500, + "motionIndex": 8, + "line": 9, + "motionProgramLine": 9, + "halProgramLine": 9, + "activeLineSource": "motion-status", + "activeLineHalSynced": true, + "type": "TASK_MOTION", + "timeSeconds": 0, + "axisPose": { + "x": 7.55697, + "y": -13.2911, + "z": 28.4442, + "a": -71.841, + "b": 0, + "c": -35.93 + }, + "currentVelocityMmPerMin": 2100, + "requestedVelocityMmPerMin": 2100, + "distanceToGo": 0, + "dtg": { + "x": 0, + "y": 0, + "z": 0 + }, + "queueDepth": 0, + "activeDepth": 0, + "cycle": 500, + "taskCycle": 50, + "halChangedPinCount": 0 + }, + "history": 9, + "lineExecution": { + "status": "stopped", + "source": "linuxcnc-task-motion-hal-wasm", + "line": 9, + "feed": 2100, + "requestedFeed": 2100, + "feedMode": null, + "axisPose": { + "x": 7.55697, + "y": -13.2911, + "z": 28.4442, + "a": -71.841, + "b": 0, + "c": -35.93 + }, + "taskCycle": 50, + "servoCycle": 500, + "sampleIndex": 500, + "motionIndex": 8, + "updatedAt": "2026-06-23T07:51:26.643Z" + }, + "source": "configs/sim/axis/vismach/5axis/table-rotary-tilting/demos/impeller-7bl-xyzac.ngc" + }, + "ui": { + "activeUiLine": 9, + "lineText": "stopped | F 2100.0 | X 7.557 | Y -13.291 | Z 28.444 | A -71.841 | C -35.930 | cycle 50/500", + "stopExists": true + } + } + ], + "logs": [ + { + "type": "warn", + "text": "[.WebGL-0x35b4000f0200]GL Driver Message (OpenGL, Performance, GL_CLOSE_PATH_NV, High): GPU stall due to ReadPixels" + }, + { + "type": "warn", + "text": "[.WebGL-0x35b4000f0200]GL Driver Message (OpenGL, Performance, GL_CLOSE_PATH_NV, High): GPU stall due to ReadPixels" + }, + { + "type": "warn", + "text": "[.WebGL-0x35b4000f0200]GL Driver Message (OpenGL, Performance, GL_CLOSE_PATH_NV, High): GPU stall due to ReadPixels" + }, + { + "type": "warn", + "text": "[.WebGL-0x35b4000f0200]GL Driver Message (OpenGL, Performance, GL_CLOSE_PATH_NV, High): GPU stall due to ReadPixels (this message will no longer repeat)" + } + ] +} diff --git a/qa/web-rtcp-5axis-site-test/output/test-linuxcnc-source-run-report-2026-06-23.docx b/qa/web-rtcp-5axis-site-test/output/test-linuxcnc-source-run-report-2026-06-23.docx new file mode 100644 index 0000000..52ffb76 Binary files /dev/null and b/qa/web-rtcp-5axis-site-test/output/test-linuxcnc-source-run-report-2026-06-23.docx differ diff --git a/qa/web-rtcp-5axis-site-test/output/test-linuxcnc-source-run-report.json b/qa/web-rtcp-5axis-site-test/output/test-linuxcnc-source-run-report.json index 5a372ca..9cb3bd2 100644 --- a/qa/web-rtcp-5axis-site-test/output/test-linuxcnc-source-run-report.json +++ b/qa/web-rtcp-5axis-site-test/output/test-linuxcnc-source-run-report.json @@ -1,6 +1,6 @@ { - "generatedAt": "2026-06-22T23:26:12.518Z", - "targetUrl": "http://127.0.0.1:36437/web-rtcp-5axis-sim-plan/app/index.html", + "generatedAt": "2026-06-23T07:39:18.278Z", + "targetUrl": "http://127.0.0.1:40261/web-rtcp-5axis-sim-plan/app/index.html", "chromePath": "/usr/bin/google-chrome", "sourceEvidence": { "iniPath": "/home/meswork/cnc_wams/web-rtcp-5axis-sim-plan/working_run/test_linuxcnc_source/xyzac-trt.ini", @@ -71,8 +71,8 @@ "pixelStats": { "width": 1600, "height": 1200, - "averageLuminance": 121.22, - "nonBlackRatio": 0.7609 + "averageLuminance": 128.52, + "nonBlackRatio": 0.7817 }, "state": { "activeProgram": "configs/sim/axis/vismach/5axis/table-rotary-tilting/demos/boat-xyzac.ngc", @@ -112,6 +112,7 @@ "machineProfile": "xyzac-trt", "iniPath": "configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzac-trt.ini", "selectedGcodeSourceRel": "configs/sim/axis/vismach/5axis/table-rotary-tilting/demos/boat-xyzac.ngc", + "loadedSourceBytes": 70847, "taskHalProgramPath": "/work/sim/axis/vismach/5axis/table-rotary-tilting/xyzac-trt/demos/boat-xyzac.ngc", "runState": "idle", "activeLine": 1, @@ -154,9 +155,13 @@ "apiName": "web-rtcp-5axis-program-runtime-feedback", "sourceMode": "linuxcnc-task-motion-hal-wasm", "semanticBoundary": "linuxcnc_task_motion_hal_wasm_simulation_runtime", - "sampleIndex": 0, + "sampleIndex": 20, "motionIndex": 0, "line": 1, + "motionProgramLine": 0, + "halProgramLine": 0, + "activeLineSource": "fallback", + "activeLineHalSynced": false, "type": "TASK_MOTION", "timeSeconds": 0, "axisPose": { @@ -177,11 +182,33 @@ }, "queueDepth": 0, "activeDepth": 0, - "cycle": 0, - "taskCycle": 0, + "cycle": 20, + "taskCycle": 2, "halChangedPinCount": 0 }, "currentTimingSegment": null, + "currentLineExecution": { + "status": "idle", + "source": "linuxcnc-task-motion-hal-wasm", + "line": 1, + "feed": 0, + "requestedFeed": 0, + "feedMode": null, + "axisPose": { + "x": 0, + "y": 0, + "z": 0, + "a": 0, + "b": 0, + "c": 0 + }, + "taskCycle": 2, + "servoCycle": 20, + "sampleIndex": 20, + "motionIndex": 0, + "updatedAt": "2026-06-23T07:39:20.015Z" + }, + "currentLineExecutionVisible": true, "feedbackHistoryLength": 2, "taskHalStatusLoop": { "apiName": "web-rtcp-5axis-task-hal-status-loop", @@ -206,7 +233,7 @@ "interpState": "idle", "activeLine": 1, "taskCycle": null, - "servoCycle": null + "servoCycle": 20 } } }, @@ -257,8 +284,8 @@ "pixelStats": { "width": 1600, "height": 1200, - "averageLuminance": 121.41, - "nonBlackRatio": 0.7609 + "averageLuminance": 128.59, + "nonBlackRatio": 0.7817 }, "state": { "activeProgram": "configs/sim/axis/vismach/5axis/table-rotary-tilting/demos/boat-xyzac.ngc", @@ -298,6 +325,7 @@ "machineProfile": "xyzac-trt", "iniPath": "configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzac-trt.ini", "selectedGcodeSourceRel": null, + "loadedSourceBytes": null, "taskHalProgramPath": "/work/sim/axis/vismach/5axis/table-rotary-tilting/xyzac-trt/demos/xyzac_switchkins.ngc", "runState": "idle", "activeLine": 1, @@ -340,9 +368,13 @@ "apiName": "web-rtcp-5axis-program-runtime-feedback", "sourceMode": "linuxcnc-task-motion-hal-wasm", "semanticBoundary": "linuxcnc_task_motion_hal_wasm_simulation_runtime", - "sampleIndex": 0, + "sampleIndex": 10, "motionIndex": 0, "line": 1, + "motionProgramLine": 0, + "halProgramLine": 0, + "activeLineSource": "fallback", + "activeLineHalSynced": false, "type": "TASK_MOTION", "timeSeconds": 0, "axisPose": { @@ -363,11 +395,33 @@ }, "queueDepth": 0, "activeDepth": 0, - "cycle": 0, - "taskCycle": 0, + "cycle": 10, + "taskCycle": 1, "halChangedPinCount": 0 }, "currentTimingSegment": null, + "currentLineExecution": { + "status": "idle", + "source": "linuxcnc-task-motion-hal-wasm", + "line": 1, + "feed": 0, + "requestedFeed": 0, + "feedMode": null, + "axisPose": { + "x": 0, + "y": 0, + "z": 0, + "a": 0, + "b": 0, + "c": 0 + }, + "taskCycle": 1, + "servoCycle": 10, + "sampleIndex": 10, + "motionIndex": 0, + "updatedAt": "2026-06-23T07:39:22.617Z" + }, + "currentLineExecutionVisible": true, "feedbackHistoryLength": 3, "taskHalStatusLoop": { "apiName": "web-rtcp-5axis-task-hal-status-loop", @@ -392,7 +446,7 @@ "interpState": "idle", "activeLine": 1, "taskCycle": null, - "servoCycle": null + "servoCycle": 10 } } }, @@ -409,7 +463,7 @@ "threePathPoints": "4492", "threeExecutedPathPoints": "1", "threeSceneObjects": "20", - "threeToolhead": "{\"x\":0.016,\"y\":-0.025,\"z\":0.033}", + "threeToolhead": "{\"x\":0,\"y\":0,\"z\":0}", "threeSceneUnits": "m", "threeLinearUnits": "mm", "threeLinearUnitScaleToMeters": "0.001", @@ -428,7 +482,7 @@ "threeTcpMarker": "sphere", "threeToolAxisMarker": "line", "threeToolpathPreviewSource": "linuxcnc_interpreter_canonical_motion", - "threeToolExecutionTraceSource": "fixture_line_playback_not_promoted", + "threeToolExecutionTraceSource": "linuxcnc_tp_samples_or_task_motion_hal_feedback", "threePathFitBounds": "ok", "threePathBoundsMeters": "{\"center\":{\"x\":-0.001,\"y\":0,\"z\":0.019},\"size\":{\"x\":0.088,\"y\":0.089,\"z\":0.043},\"maxSpan\":0.089214}", "threeCurrentSegmentHighlight": "ok", @@ -443,13 +497,13 @@ "pixelStats": { "width": 1600, "height": 1200, - "averageLuminance": 122.99, - "nonBlackRatio": 0.7481 + "averageLuminance": 127.63, + "nonBlackRatio": 0.7643 }, "state": { "activeProgram": "configs/sim/axis/vismach/5axis/table-rotary-tilting/demos/impeller-7bl-xyzac.ngc", "programSource": "linuxcnc-vendored-5axis-gcode", - "programExecutionSourceMode": "linuxcnc-interpreter-wasm", + "programExecutionSourceMode": "linuxcnc-task-motion-hal-wasm", "programSummary": { "ready": true, "programLineCount": 4507, @@ -485,10 +539,11 @@ "machineProfile": "xyzac-trt", "iniPath": "configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzac-trt.ini", "selectedGcodeSourceRel": "configs/sim/axis/vismach/5axis/table-rotary-tilting/demos/impeller-7bl-xyzac.ngc", + "loadedSourceBytes": 294411, "taskHalProgramPath": "/work/sim/axis/vismach/5axis/table-rotary-tilting/xyzac-trt/demos/impeller-7bl-xyzac.ngc", "runState": "idle", - "activeLine": 8, - "activeUiLine": 8, + "activeLine": 1, + "activeUiLine": 1, "machine": { "powerOn": false, "estopActive": false, @@ -525,24 +580,27 @@ }, "programRuntimeFeedback": { "apiName": "web-rtcp-5axis-program-runtime-feedback", - "sourceMode": "linuxcnc-canonical-motion", - "semanticBoundary": "linuxcnc_canonical_motion_feedback_without_tp_sample", - "sampleIndex": 0, + "sourceMode": "linuxcnc-task-motion-hal-wasm", + "semanticBoundary": "linuxcnc_task_motion_hal_wasm_simulation_runtime", + "sampleIndex": 10, "motionIndex": 0, - "line": 8, - "type": "STRAIGHT_TRAVERSE", - "linearUnits": "mm", + "line": 1, + "motionProgramLine": 0, + "halProgramLine": 0, + "activeLineSource": "fallback", + "activeLineHalSynced": false, + "type": "TASK_MOTION", "timeSeconds": 0, "axisPose": { - "x": 16.339, - "y": -25.409, - "z": 33.353, - "a": -71.841, + "x": 0, + "y": 0, + "z": 0, + "a": 0, "b": 0, - "c": -35.93 + "c": 0 }, - "currentVelocityMmPerMin": 2100, - "requestedVelocityMmPerMin": 2100, + "currentVelocityMmPerMin": 0, + "requestedVelocityMmPerMin": 0, "distanceToGo": 0, "dtg": { "x": 0, @@ -551,69 +609,33 @@ }, "queueDepth": 0, "activeDepth": 0, - "cycle": 0 + "cycle": 10, + "taskCycle": 1, + "halChangedPinCount": 0 }, - "currentTimingSegment": { - "index": 0, - "line": 8, - "type": "STRAIGHT_TRAVERSE", - "motionClass": "rapid", - "feedMode": "inverse-time", - "linearDistanceMm": 0, - "angularDistanceDeg": 0, - "feedRate": 4500000, - "requestedVelocityMmPerMin": 2100, - "velocityMmPerMin": 2100, - "angularVelocityDegPerMin": 1800, - "durationSeconds": 0, - "startSeconds": 0, - "startAxes": { - "x": 16.339, - "y": -25.409, - "z": 33.353, - "u": 0, - "v": 0, - "w": 0, - "a": -71.841, - "b": 0, - "c": -35.93 - }, - "endAxes": { - "x": 16.339, - "y": -25.409, - "z": 33.353, - "u": 0, - "v": 0, - "w": 0, - "a": -71.841, - "b": 0, - "c": -35.93 - }, - "axes": { - "x": 16.339, - "y": -25.409, - "z": 33.353, - "u": 0, - "v": 0, - "w": 0, - "a": -71.841, - "b": 0, - "c": -35.93 - }, - "deltas": { + "currentTimingSegment": null, + "currentLineExecution": { + "status": "idle", + "source": "linuxcnc-task-motion-hal-wasm", + "line": 1, + "feed": 0, + "requestedFeed": 0, + "feedMode": null, + "axisPose": { "x": 0, "y": 0, "z": 0, - "u": 0, - "v": 0, - "w": 0, "a": 0, "b": 0, "c": 0 }, - "linearUnits": "mm", - "elapsedSeconds": 0 + "taskCycle": 1, + "servoCycle": 10, + "sampleIndex": 10, + "motionIndex": 0, + "updatedAt": "2026-06-23T07:39:29.596Z" }, + "currentLineExecutionVisible": true, "feedbackHistoryLength": 4, "taskHalStatusLoop": { "apiName": "web-rtcp-5axis-task-hal-status-loop", @@ -638,7 +660,7 @@ "interpState": "idle", "activeLine": 1, "taskCycle": null, - "servoCycle": null + "servoCycle": 10 } } }, @@ -689,8 +711,8 @@ "pixelStats": { "width": 1600, "height": 1200, - "averageLuminance": 120.33, - "nonBlackRatio": 0.7425 + "averageLuminance": 127.67, + "nonBlackRatio": 0.7643 }, "state": { "activeProgram": "configs/sim/axis/vismach/5axis/table-rotary-tilting/demos/impeller-7bl-xyzac.ngc", @@ -731,6 +753,7 @@ "machineProfile": "xyzac-trt", "iniPath": "configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzac-trt.ini", "selectedGcodeSourceRel": "configs/sim/axis/vismach/5axis/table-rotary-tilting/demos/impeller-7bl-xyzac.ngc", + "loadedSourceBytes": 294411, "taskHalProgramPath": "/work/sim/axis/vismach/5axis/table-rotary-tilting/xyzac-trt/demos/impeller-7bl-xyzac.ngc", "runState": "idle", "activeLine": 1, @@ -773,9 +796,13 @@ "apiName": "web-rtcp-5axis-program-runtime-feedback", "sourceMode": "linuxcnc-task-motion-hal-wasm", "semanticBoundary": "linuxcnc_task_motion_hal_wasm_simulation_runtime", - "sampleIndex": 30, + "sampleIndex": 50, "motionIndex": 0, "line": 1, + "motionProgramLine": 1, + "halProgramLine": 1, + "activeLineSource": "motion-status", + "activeLineHalSynced": true, "type": "TASK_MOTION", "timeSeconds": 0, "axisPose": { @@ -786,8 +813,8 @@ "b": 0, "c": 0 }, - "currentVelocityMmPerMin": 0, - "requestedVelocityMmPerMin": 0, + "currentVelocityMmPerMin": 3600, + "requestedVelocityMmPerMin": 3600, "distanceToGo": 0, "dtg": { "x": 0, @@ -796,12 +823,34 @@ }, "queueDepth": 0, "activeDepth": 0, - "cycle": 30, - "taskCycle": 3, + "cycle": 50, + "taskCycle": 5, "halChangedPinCount": 0 }, "currentTimingSegment": null, - "feedbackHistoryLength": 7, + "currentLineExecution": { + "status": "idle", + "source": "linuxcnc-task-motion-hal-wasm", + "line": 1, + "feed": 3600, + "requestedFeed": 3600, + "feedMode": null, + "axisPose": { + "x": 0, + "y": 0, + "z": 0, + "a": 0, + "b": 0, + "c": 0 + }, + "taskCycle": 5, + "servoCycle": 50, + "sampleIndex": 50, + "motionIndex": 0, + "updatedAt": "2026-06-23T07:39:43.258Z" + }, + "currentLineExecutionVisible": true, + "feedbackHistoryLength": 5, "taskHalStatusLoop": { "apiName": "web-rtcp-5axis-task-hal-status-loop", "active": false, @@ -825,7 +874,7 @@ "interpState": "idle", "activeLine": 1, "taskCycle": null, - "servoCycle": 30 + "servoCycle": 50 } } }, @@ -876,8 +925,8 @@ "pixelStats": { "width": 1600, "height": 1200, - "averageLuminance": 121.96, - "nonBlackRatio": 0.7432 + "averageLuminance": 130.81, + "nonBlackRatio": 0.765 }, "state": { "activeProgram": "configs/sim/axis/vismach/5axis/table-rotary-tilting/demos/impeller-7bl-xyzac.ngc", @@ -918,6 +967,7 @@ "machineProfile": "xyzac-trt", "iniPath": "configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzac-trt.ini", "selectedGcodeSourceRel": "configs/sim/axis/vismach/5axis/table-rotary-tilting/demos/impeller-7bl-xyzac.ngc", + "loadedSourceBytes": 294411, "taskHalProgramPath": "/work/sim/axis/vismach/5axis/table-rotary-tilting/xyzac-trt/demos/impeller-7bl-xyzac.ngc", "runState": "running", "activeLine": 9, @@ -960,9 +1010,13 @@ "apiName": "web-rtcp-5axis-program-runtime-feedback", "sourceMode": "linuxcnc-task-motion-hal-wasm", "semanticBoundary": "linuxcnc_task_motion_hal_wasm_simulation_runtime", - "sampleIndex": 330, + "sampleIndex": 350, "motionIndex": 8, "line": 9, + "motionProgramLine": 9, + "halProgramLine": 9, + "activeLineSource": "motion-status", + "activeLineHalSynced": true, "type": "TASK_MOTION", "timeSeconds": 0, "axisPose": { @@ -983,8 +1037,8 @@ }, "queueDepth": 0, "activeDepth": 0, - "cycle": 330, - "taskCycle": 33, + "cycle": 350, + "taskCycle": 35, "halChangedPinCount": 0 }, "currentTimingSegment": { @@ -1048,6 +1102,28 @@ "linearUnits": "mm", "elapsedSeconds": 0.4571722972663097 }, + "currentLineExecution": { + "status": "running", + "source": "linuxcnc-task-motion-hal-wasm", + "line": 9, + "feed": 2100, + "requestedFeed": 2100, + "feedMode": null, + "axisPose": { + "x": 10.4843, + "y": -17.3304, + "z": 30.0805, + "a": -71.841, + "b": 0, + "c": -35.93 + }, + "taskCycle": 35, + "servoCycle": 350, + "sampleIndex": 350, + "motionIndex": 8, + "updatedAt": "2026-06-23T07:39:58.821Z" + }, + "currentLineExecutionVisible": true, "feedbackHistoryLength": 5, "taskHalStatusLoop": { "apiName": "web-rtcp-5axis-task-hal-status-loop", @@ -1061,7 +1137,7 @@ "intervalMs": 25, "taskPeriodNs": 10000000, "servoPeriodNs": 1000000, - "lastStatusAt": "2026-06-22T23:26:45.667Z", + "lastStatusAt": "2026-06-23T07:39:58.821Z", "lastError": null, "stopReason": null, "semanticBoundary": "js_status_polling_loop_for_linuxcnc_task_hal_motion_status" @@ -1072,7 +1148,7 @@ "interpState": "reading", "activeLine": 9, "taskCycle": null, - "servoCycle": 330 + "servoCycle": 350 } } }, @@ -1089,12 +1165,12 @@ "threePathPoints": "4492", "threeExecutedPathPoints": "1", "threeSceneObjects": "20", - "threeToolhead": "{\"x\":0.007,\"y\":-0.013,\"z\":0.028}", + "threeToolhead": "{\"x\":0.007,\"y\":-0.012,\"z\":0.028}", "threeSceneUnits": "m", "threeLinearUnits": "mm", "threeLinearUnitScaleToMeters": "0.001", "threeToolAxis": "{\"x\":0.558,\"y\":0.769,\"z\":0.312}", - "threeTcpPose": "{\"x\":7.164,\"y\":-12.749,\"z\":28.225,\"a\":-71.841,\"c\":-35.93}", + "threeTcpPose": "{\"x\":-39.978,\"y\":-76.986,\"z\":1.875,\"a\":-71.841,\"c\":-35.93}", "threeRtcpState": "on", "threeSelectedView": "iso", "threeFrameApi": "web-rtcp-5axis-motion-frame", @@ -1123,8 +1199,8 @@ "pixelStats": { "width": 1600, "height": 1200, - "averageLuminance": 121.76, - "nonBlackRatio": 0.7434 + "averageLuminance": 130.59, + "nonBlackRatio": 0.7649 }, "state": { "activeProgram": "configs/sim/axis/vismach/5axis/table-rotary-tilting/demos/impeller-7bl-xyzac.ngc", @@ -1165,6 +1241,7 @@ "machineProfile": "xyzac-trt", "iniPath": "configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzac-trt.ini", "selectedGcodeSourceRel": "configs/sim/axis/vismach/5axis/table-rotary-tilting/demos/impeller-7bl-xyzac.ngc", + "loadedSourceBytes": 294411, "taskHalProgramPath": "/work/sim/axis/vismach/5axis/table-rotary-tilting/xyzac-trt/demos/impeller-7bl-xyzac.ngc", "runState": "running", "activeLine": 10, @@ -1188,17 +1265,17 @@ "rtcpState": "on", "kinsType": "tcp-xyzac", "dro": { - "x": 7.16391, - "y": -12.7489, - "z": 28.2246, + "x": 6.86843, + "y": -12.3413, + "z": 28.0595, "a": -71.841, "b": 0, "c": -35.93 }, "axisPose": { - "x": 7.16391, - "y": -12.7489, - "z": 28.2246, + "x": 6.86843, + "y": -12.3413, + "z": 28.0595, "a": -71.841, "b": 0, "c": -35.93 @@ -1207,15 +1284,19 @@ "apiName": "web-rtcp-5axis-program-runtime-feedback", "sourceMode": "linuxcnc-task-motion-hal-wasm", "semanticBoundary": "linuxcnc_task_motion_hal_wasm_simulation_runtime", - "sampleIndex": 530, + "sampleIndex": 600, "motionIndex": 9, "line": 10, + "motionProgramLine": 10, + "halProgramLine": 10, + "activeLineSource": "motion-status", + "activeLineHalSynced": true, "type": "TASK_MOTION", "timeSeconds": 0, "axisPose": { - "x": 7.16391, - "y": -12.7489, - "z": 28.2246, + "x": 6.86843, + "y": -12.3413, + "z": 28.0595, "a": -71.841, "b": 0, "c": -35.93 @@ -1230,8 +1311,8 @@ }, "queueDepth": 0, "activeDepth": 0, - "cycle": 530, - "taskCycle": 53, + "cycle": 600, + "taskCycle": 60, "halChangedPinCount": 0 }, "currentTimingSegment": { @@ -1295,7 +1376,29 @@ "linearUnits": "mm", "elapsedSeconds": 0.6458515425493285 }, - "feedbackHistoryLength": 9, + "currentLineExecution": { + "status": "running", + "source": "linuxcnc-task-motion-hal-wasm", + "line": 10, + "feed": 635.748, + "requestedFeed": 635.748, + "feedMode": null, + "axisPose": { + "x": 6.86843, + "y": -12.3413, + "z": 28.0595, + "a": -71.841, + "b": 0, + "c": -35.93 + }, + "taskCycle": 60, + "servoCycle": 600, + "sampleIndex": 600, + "motionIndex": 9, + "updatedAt": "2026-06-23T07:40:03.250Z" + }, + "currentLineExecutionVisible": true, + "feedbackHistoryLength": 10, "taskHalStatusLoop": { "apiName": "web-rtcp-5axis-task-hal-status-loop", "active": true, @@ -1303,12 +1406,12 @@ "profileId": "xyzac-trt", "iniPath": "configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzac-trt.ini", "kinematicsModuleId": "xyzac-trt", - "tickCount": 9, + "tickCount": 10, "batchSize": 5, "intervalMs": 25, "taskPeriodNs": 10000000, "servoPeriodNs": 1000000, - "lastStatusAt": "2026-06-22T23:26:49.069Z", + "lastStatusAt": "2026-06-23T07:40:03.250Z", "lastError": null, "stopReason": null, "semanticBoundary": "js_status_polling_loop_for_linuxcnc_task_hal_motion_status" @@ -1319,7 +1422,7 @@ "interpState": "reading", "activeLine": 10, "taskCycle": null, - "servoCycle": 530 + "servoCycle": 600 } } }, @@ -1340,8 +1443,8 @@ "threeSceneUnits": "m", "threeLinearUnits": "mm", "threeLinearUnitScaleToMeters": "0.001", - "threeToolAxis": "{\"x\":0.546,\"y\":0.777,\"z\":0.314}", - "threeTcpPose": "{\"x\":-39.545,\"y\":-77.055,\"z\":0.905,\"a\":-71.682,\"c\":-35.099}", + "threeToolAxis": "{\"x\":0.54,\"y\":0.78,\"z\":0.316}", + "threeTcpPose": "{\"x\":-39.062,\"y\":-77.457,\"z\":0.592,\"a\":-71.606,\"c\":-34.7}", "threeRtcpState": "on", "threeSelectedView": "iso", "threeFrameApi": "web-rtcp-5axis-motion-frame", @@ -1370,8 +1473,8 @@ "pixelStats": { "width": 1600, "height": 1200, - "averageLuminance": 121.61, - "nonBlackRatio": 0.7432 + "averageLuminance": 130.48, + "nonBlackRatio": 0.7649 }, "state": { "activeProgram": "configs/sim/axis/vismach/5axis/table-rotary-tilting/demos/impeller-7bl-xyzac.ngc", @@ -1412,6 +1515,7 @@ "machineProfile": "xyzac-trt", "iniPath": "configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzac-trt.ini", "selectedGcodeSourceRel": "configs/sim/axis/vismach/5axis/table-rotary-tilting/demos/impeller-7bl-xyzac.ngc", + "loadedSourceBytes": 294411, "taskHalProgramPath": "/work/sim/axis/vismach/5axis/table-rotary-tilting/xyzac-trt/demos/impeller-7bl-xyzac.ngc", "runState": "running", "activeLine": 11, @@ -1435,37 +1539,41 @@ "rtcpState": "on", "kinsType": "tcp-xyzac", "dro": { - "x": 6.31746, - "y": -11.7968, - "z": 27.3111, - "a": -71.6823, + "x": 6.32488, + "y": -11.9105, + "z": 27.1037, + "a": -71.6061, "b": 0, - "c": -35.099 + "c": -34.7 }, "axisPose": { - "x": 6.31746, - "y": -11.7968, - "z": 27.3111, - "a": -71.6823, + "x": 6.32488, + "y": -11.9105, + "z": 27.1037, + "a": -71.6061, "b": 0, - "c": -35.099 + "c": -34.7 }, "programRuntimeFeedback": { "apiName": "web-rtcp-5axis-program-runtime-feedback", "sourceMode": "linuxcnc-task-motion-hal-wasm", "semanticBoundary": "linuxcnc_task_motion_hal_wasm_simulation_runtime", - "sampleIndex": 780, + "sampleIndex": 850, "motionIndex": 10, "line": 11, + "motionProgramLine": 11, + "halProgramLine": 11, + "activeLineSource": "motion-status", + "activeLineHalSynced": true, "type": "TASK_MOTION", "timeSeconds": 0, "axisPose": { - "x": 6.31746, - "y": -11.7968, - "z": 27.3111, - "a": -71.6823, + "x": 6.32488, + "y": -11.9105, + "z": 27.1037, + "a": -71.6061, "b": 0, - "c": -35.099 + "c": -34.7 }, "currentVelocityMmPerMin": 283.9176, "requestedVelocityMmPerMin": 283.9176, @@ -1477,8 +1585,8 @@ }, "queueDepth": 0, "activeDepth": 0, - "cycle": 780, - "taskCycle": 78, + "cycle": 850, + "taskCycle": 85, "halChangedPinCount": 0 }, "currentTimingSegment": { @@ -1542,7 +1650,29 @@ "linearUnits": "mm", "elapsedSeconds": 1.0232100331153662 }, - "feedbackHistoryLength": 14, + "currentLineExecution": { + "status": "running", + "source": "linuxcnc-task-motion-hal-wasm", + "line": 11, + "feed": 283.9176, + "requestedFeed": 283.9176, + "feedMode": null, + "axisPose": { + "x": 6.32488, + "y": -11.9105, + "z": 27.1037, + "a": -71.6061, + "b": 0, + "c": -34.7 + }, + "taskCycle": 85, + "servoCycle": 850, + "sampleIndex": 850, + "motionIndex": 10, + "updatedAt": "2026-06-23T07:40:07.592Z" + }, + "currentLineExecutionVisible": true, + "feedbackHistoryLength": 15, "taskHalStatusLoop": { "apiName": "web-rtcp-5axis-task-hal-status-loop", "active": true, @@ -1550,12 +1680,12 @@ "profileId": "xyzac-trt", "iniPath": "configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzac-trt.ini", "kinematicsModuleId": "xyzac-trt", - "tickCount": 14, + "tickCount": 15, "batchSize": 5, "intervalMs": 25, "taskPeriodNs": 10000000, "servoPeriodNs": 1000000, - "lastStatusAt": "2026-06-22T23:26:52.810Z", + "lastStatusAt": "2026-06-23T07:40:07.592Z", "lastError": null, "stopReason": null, "semanticBoundary": "js_status_polling_loop_for_linuxcnc_task_hal_motion_status" @@ -1566,7 +1696,7 @@ "interpState": "reading", "activeLine": 11, "taskCycle": null, - "servoCycle": 780 + "servoCycle": 850 } } }, @@ -1587,8 +1717,8 @@ "threeSceneUnits": "m", "threeLinearUnits": "mm", "threeLinearUnitScaleToMeters": "0.001", - "threeToolAxis": "{\"x\":0.523,\"y\":0.79,\"z\":0.319}", - "threeTcpPose": "{\"x\":6.347,\"y\":-12.251,\"z\":26.482,\"a\":-71.378,\"c\":-33.503}", + "threeToolAxis": "{\"x\":0.514,\"y\":0.795,\"z\":0.321}", + "threeTcpPose": "{\"x\":-36.831,\"y\":-79.254,\"z\":-0.84,\"a\":-71.258,\"c\":-32.875}", "threeRtcpState": "on", "threeSelectedView": "iso", "threeFrameApi": "web-rtcp-5axis-motion-frame", @@ -1617,255 +1747,8 @@ "pixelStats": { "width": 1600, "height": 1200, - "averageLuminance": 121.57, - "nonBlackRatio": 0.7432 - }, - "state": { - "activeProgram": "configs/sim/axis/vismach/5axis/table-rotary-tilting/demos/impeller-7bl-xyzac.ngc", - "programSource": "linuxcnc-vendored-5axis-gcode", - "programExecutionSourceMode": "linuxcnc-task-motion-hal-wasm", - "programSummary": { - "ready": true, - "programLineCount": 4507, - "canonicalEventCount": 22313, - "motionEventCount": 4492, - "motionTypes": [ - "STRAIGHT_TRAVERSE", - "STRAIGHT_FEED" - ], - "finalAxes": { - "x": 0, - "y": 0, - "z": 40, - "a": 0, - "b": 0, - "c": 0, - "u": 0, - "v": 0, - "w": 0 - }, - "switchkinsEventCount": 2, - "switchkinsCodes": [ - "M428", - "M429" - ], - "switchkinsRemapBoundary": "linuxcnc_switchkins_remap_mcode_preserved_web_runtime_applied", - "remapRuntimeReady": false, - "plannerRuntimeReady": true, - "plannerSemanticBoundary": "linuxcnc_tp_queue_runtime_timing_from_canonical_motion", - "machineFileExecutionReady": false, - "fullLinuxCncProgramExecutionReady": false - }, - "machineProfile": "xyzac-trt", - "iniPath": "configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzac-trt.ini", - "selectedGcodeSourceRel": "configs/sim/axis/vismach/5axis/table-rotary-tilting/demos/impeller-7bl-xyzac.ngc", - "taskHalProgramPath": "/work/sim/axis/vismach/5axis/table-rotary-tilting/xyzac-trt/demos/impeller-7bl-xyzac.ngc", - "runState": "running", - "activeLine": 11, - "activeUiLine": 11, - "machine": { - "powerOn": true, - "estopActive": false, - "taskState": "on", - "mode": "auto", - "interpState": "reading", - "interpResumeState": "reading", - "taskPaused": false, - "allHomed": true, - "noForceHoming": false, - "jogAxis": "x", - "jogIncrement": 1, - "mdiCommand": "G0 X0 Y0 Z0", - "mdiDistanceMode": "absolute", - "resetCount": 0 - }, - "rtcpState": "on", - "kinsType": "tcp-xyzac", - "dro": { - "x": 6.35456, - "y": -12.3652, - "z": 26.2743, - "a": -71.3014, - "b": 0, - "c": -33.1042 - }, - "axisPose": { - "x": 6.35456, - "y": -12.3652, - "z": 26.2743, - "a": -71.3014, - "b": 0, - "c": -33.1042 - }, - "programRuntimeFeedback": { - "apiName": "web-rtcp-5axis-program-runtime-feedback", - "sourceMode": "linuxcnc-task-motion-hal-wasm", - "semanticBoundary": "linuxcnc_task_motion_hal_wasm_simulation_runtime", - "sampleIndex": 1030, - "motionIndex": 10, - "line": 11, - "type": "TASK_MOTION", - "timeSeconds": 0, - "axisPose": { - "x": 6.35456, - "y": -12.3652, - "z": 26.2743, - "a": -71.3014, - "b": 0, - "c": -33.1042 - }, - "currentVelocityMmPerMin": 283.9176, - "requestedVelocityMmPerMin": 283.9176, - "distanceToGo": 0, - "dtg": { - "x": 0, - "y": 0, - "z": 0 - }, - "queueDepth": 0, - "activeDepth": 0, - "cycle": 1030, - "taskCycle": 103, - "halChangedPinCount": 0 - }, - "currentTimingSegment": { - "index": 3, - "line": 11, - "type": "STRAIGHT_FEED", - "motionClass": "feed", - "feedMode": "inverse-time", - "linearDistanceMm": 1.7856441414794806, - "angularDistanceDeg": 3.0654112285303587, - "feedRate": 159, - "requestedVelocityMmPerMin": 283.9174184952374, - "velocityMmPerMin": 283.9174184952374, - "angularVelocityDegPerMin": 487.40038533632696, - "durationSeconds": 0.37735849056603776, - "startSeconds": 0.6458515425493285, - "startAxes": { - "x": 6.302, - "y": -11.56, - "z": 27.743, - "u": 0, - "v": 0, - "w": 0, - "a": -71.841, - "b": 0, - "c": -35.93 - }, - "endAxes": { - "x": 6.358, - "y": -12.418, - "z": 26.178, - "u": 0, - "v": 0, - "w": 0, - "a": -71.266, - "b": 0, - "c": -32.919 - }, - "axes": { - "x": 6.358, - "y": -12.418, - "z": 26.178, - "u": 0, - "v": 0, - "w": 0, - "a": -71.266, - "b": 0, - "c": -32.919 - }, - "deltas": { - "x": 0.05600000000000005, - "y": -0.8579999999999988, - "z": -1.5649999999999977, - "u": 0, - "v": 0, - "w": 0, - "a": 0.5749999999999886, - "b": 0, - "c": 3.011000000000003 - }, - "linearUnits": "mm", - "elapsedSeconds": 1.0232100331153662 - }, - "feedbackHistoryLength": 19, - "taskHalStatusLoop": { - "apiName": "web-rtcp-5axis-task-hal-status-loop", - "active": true, - "sequence": 1, - "profileId": "xyzac-trt", - "iniPath": "configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzac-trt.ini", - "kinematicsModuleId": "xyzac-trt", - "tickCount": 19, - "batchSize": 5, - "intervalMs": 25, - "taskPeriodNs": 10000000, - "servoPeriodNs": 1000000, - "lastStatusAt": "2026-06-22T23:26:56.582Z", - "lastError": null, - "stopReason": null, - "semanticBoundary": "js_status_polling_loop_for_linuxcnc_task_hal_motion_status" - }, - "taskHalStatus": { - "taskState": "on", - "taskMode": "auto", - "interpState": "reading", - "activeLine": 11, - "taskCycle": null, - "servoCycle": 1030 - } - } - }, - { - "name": "05-run-5000ms", - "title": "G-code 执行 5000ms", - "description": "采集 G-code 当前高亮行、执行轨迹、实时 DRO/axisPose 和 task/HAL feedback。", - "screenshotPath": "/home/meswork/cnc_wams/qa/web-rtcp-5axis-site-test/screenshots/test-linuxcnc-source-run/05-run-5000ms.png", - "dataset": { - "fiveAxisCanvas": "true", - "engine": "three.js r183", - "threeReady": "true", - "threeRevision": "183", - "threePathPoints": "4492", - "threeExecutedPathPoints": "1", - "threeSceneObjects": "20", - "threeToolhead": "{\"x\":0.006,\"y\":-0.013,\"z\":0.026}", - "threeSceneUnits": "m", - "threeLinearUnits": "mm", - "threeLinearUnitScaleToMeters": "0.001", - "threeToolAxis": "{\"x\":0.509,\"y\":0.798,\"z\":0.322}", - "threeTcpPose": "{\"x\":-36.442,\"y\":-79.576,\"z\":-1.089,\"a\":-71.201,\"c\":-32.549}", - "threeRtcpState": "on", - "threeSelectedView": "iso", - "threeFrameApi": "web-rtcp-5axis-motion-frame", - "threeRenderer": "webgl", - "threeSceneMode": "program-preview-and-tool-execution", - "threePreviewScope": "machine-reference-and-toolpath", - "threeMachineReferenceModel": "webgl-five-axis-reference", - "threeCameraControls": "orbit-pan-zoom", - "threeProgramPreviewSource": "linuxcnc-interpreter-wasm", - "threeToolExecutionMarker": "true", - "threeTcpMarker": "sphere", - "threeToolAxisMarker": "line", - "threeToolpathPreviewSource": "linuxcnc_interpreter_canonical_motion", - "threeToolExecutionTraceSource": "linuxcnc_tp_samples_or_task_motion_hal_feedback", - "threePathFitBounds": "ok", - "threePathBoundsMeters": "{\"center\":{\"x\":-0.001,\"y\":0,\"z\":0.019},\"size\":{\"x\":0.088,\"y\":0.089,\"z\":0.043},\"maxSpan\":0.089214}", - "threeCurrentSegmentHighlight": "ok", - "threeRapidFeedVisualDistinction": "ok", - "threeNoGcodeSemanticsGeneration": "ok", - "threeRapidPathPoints": "186", - "threeFeedPathPoints": "4306", - "threeArcPathPoints": "0", - "threeCurrentSegmentPoints": "1", - "threeCurrentSegmentType": "STRAIGHT_TRAVERSE" - }, - "pixelStats": { - "width": 1600, - "height": 1200, - "averageLuminance": 121.55, - "nonBlackRatio": 0.743 + "averageLuminance": 130.47, + "nonBlackRatio": 0.7649 }, "state": { "activeProgram": "configs/sim/axis/vismach/5axis/table-rotary-tilting/demos/impeller-7bl-xyzac.ngc", @@ -1906,6 +1789,7 @@ "machineProfile": "xyzac-trt", "iniPath": "configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzac-trt.ini", "selectedGcodeSourceRel": "configs/sim/axis/vismach/5axis/table-rotary-tilting/demos/impeller-7bl-xyzac.ngc", + "loadedSourceBytes": 294411, "taskHalProgramPath": "/work/sim/axis/vismach/5axis/table-rotary-tilting/xyzac-trt/demos/impeller-7bl-xyzac.ngc", "runState": "running", "activeLine": 12, @@ -1929,37 +1813,41 @@ "rtcpState": "on", "kinsType": "tcp-xyzac", "dro": { - "x": 6.35079, - "y": -12.5316, - "z": 25.9857, - "a": -71.2011, + "x": 6.35715, + "y": -12.4314, + "z": 26.1553, + "a": -71.2583, "b": 0, - "c": -32.5494 + "c": -32.8753 }, "axisPose": { - "x": 6.35079, - "y": -12.5316, - "z": 25.9857, - "a": -71.2011, + "x": 6.35715, + "y": -12.4314, + "z": 26.1553, + "a": -71.2583, "b": 0, - "c": -32.5494 + "c": -32.8753 }, "programRuntimeFeedback": { "apiName": "web-rtcp-5axis-program-runtime-feedback", "sourceMode": "linuxcnc-task-motion-hal-wasm", "semanticBoundary": "linuxcnc_task_motion_hal_wasm_simulation_runtime", - "sampleIndex": 1280, + "sampleIndex": 1100, "motionIndex": 11, "line": 12, + "motionProgramLine": 12, + "halProgramLine": 12, + "activeLineSource": "motion-status", + "activeLineHalSynced": true, "type": "TASK_MOTION", "timeSeconds": 0, "axisPose": { - "x": 6.35079, - "y": -12.5316, - "z": 25.9857, - "a": -71.2011, + "x": 6.35715, + "y": -12.4314, + "z": 26.1553, + "a": -71.2583, "b": 0, - "c": -32.5494 + "c": -32.8753 }, "currentVelocityMmPerMin": 59.12256, "requestedVelocityMmPerMin": 59.12256, @@ -1971,8 +1859,8 @@ }, "queueDepth": 0, "activeDepth": 0, - "cycle": 1280, - "taskCycle": 128, + "cycle": 1100, + "taskCycle": 110, "halChangedPinCount": 0 }, "currentTimingSegment": { @@ -2036,7 +1924,29 @@ "linearUnits": "mm", "elapsedSeconds": 1.4005685236814038 }, - "feedbackHistoryLength": 24, + "currentLineExecution": { + "status": "running", + "source": "linuxcnc-task-motion-hal-wasm", + "line": 12, + "feed": 59.12256, + "requestedFeed": 59.12256, + "feedMode": null, + "axisPose": { + "x": 6.35715, + "y": -12.4314, + "z": 26.1553, + "a": -71.2583, + "b": 0, + "c": -32.8753 + }, + "taskCycle": 110, + "servoCycle": 1100, + "sampleIndex": 1100, + "motionIndex": 11, + "updatedAt": "2026-06-23T07:40:11.943Z" + }, + "currentLineExecutionVisible": true, + "feedbackHistoryLength": 20, "taskHalStatusLoop": { "apiName": "web-rtcp-5axis-task-hal-status-loop", "active": true, @@ -2044,12 +1954,12 @@ "profileId": "xyzac-trt", "iniPath": "configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzac-trt.ini", "kinematicsModuleId": "xyzac-trt", - "tickCount": 24, + "tickCount": 20, "batchSize": 5, "intervalMs": 25, "taskPeriodNs": 10000000, "servoPeriodNs": 1000000, - "lastStatusAt": "2026-06-22T23:27:00.399Z", + "lastStatusAt": "2026-06-23T07:40:11.943Z", "lastError": null, "stopReason": null, "semanticBoundary": "js_status_polling_loop_for_linuxcnc_task_hal_motion_status" @@ -2060,15 +1970,15 @@ "interpState": "reading", "activeLine": 12, "taskCycle": null, - "servoCycle": 1280 + "servoCycle": 1100 } } }, { - "name": "05-run-17000ms", - "title": "G-code 执行 17000ms", + "name": "05-run-5000ms", + "title": "G-code 执行 5000ms", "description": "采集 G-code 当前高亮行、执行轨迹、实时 DRO/axisPose 和 task/HAL feedback。", - "screenshotPath": "/home/meswork/cnc_wams/qa/web-rtcp-5axis-site-test/screenshots/test-linuxcnc-source-run/05-run-17000ms.png", + "screenshotPath": "/home/meswork/cnc_wams/qa/web-rtcp-5axis-site-test/screenshots/test-linuxcnc-source-run/05-run-5000ms.png", "dataset": { "fiveAxisCanvas": "true", "engine": "three.js r183", @@ -2081,8 +1991,8 @@ "threeSceneUnits": "m", "threeLinearUnits": "mm", "threeLinearUnitScaleToMeters": "0.001", - "threeToolAxis": "{\"x\":0.505,\"y\":0.801,\"z\":0.323}", - "threeTcpPose": "{\"x\":6.341,\"y\":-12.633,\"z\":25.818,\"a\":-71.149,\"c\":-32.227}", + "threeToolAxis": "{\"x\":0.508,\"y\":0.799,\"z\":0.322}", + "threeTcpPose": "{\"x\":-36.345,\"y\":-79.656,\"z\":-1.151,\"a\":-71.187,\"c\":-32.468}", "threeRtcpState": "on", "threeSelectedView": "iso", "threeFrameApi": "web-rtcp-5axis-motion-frame", @@ -2111,8 +2021,8 @@ "pixelStats": { "width": 1600, "height": 1200, - "averageLuminance": 121.53, - "nonBlackRatio": 0.7431 + "averageLuminance": 130.45, + "nonBlackRatio": 0.7648 }, "state": { "activeProgram": "configs/sim/axis/vismach/5axis/table-rotary-tilting/demos/impeller-7bl-xyzac.ngc", @@ -2153,6 +2063,281 @@ "machineProfile": "xyzac-trt", "iniPath": "configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzac-trt.ini", "selectedGcodeSourceRel": "configs/sim/axis/vismach/5axis/table-rotary-tilting/demos/impeller-7bl-xyzac.ngc", + "loadedSourceBytes": 294411, + "taskHalProgramPath": "/work/sim/axis/vismach/5axis/table-rotary-tilting/xyzac-trt/demos/impeller-7bl-xyzac.ngc", + "runState": "running", + "activeLine": 12, + "activeUiLine": 12, + "machine": { + "powerOn": true, + "estopActive": false, + "taskState": "on", + "mode": "auto", + "interpState": "reading", + "interpResumeState": "reading", + "taskPaused": false, + "allHomed": true, + "noForceHoming": false, + "jogAxis": "x", + "jogIncrement": 1, + "mdiCommand": "G0 X0 Y0 Z0", + "mdiDistanceMode": "absolute", + "resetCount": 0 + }, + "rtcpState": "on", + "kinsType": "tcp-xyzac", + "dro": { + "x": 6.3492, + "y": -12.5566, + "z": 25.9433, + "a": -71.1868, + "b": 0, + "c": -32.4679 + }, + "axisPose": { + "x": 6.3492, + "y": -12.5566, + "z": 25.9433, + "a": -71.1868, + "b": 0, + "c": -32.4679 + }, + "programRuntimeFeedback": { + "apiName": "web-rtcp-5axis-program-runtime-feedback", + "sourceMode": "linuxcnc-task-motion-hal-wasm", + "semanticBoundary": "linuxcnc_task_motion_hal_wasm_simulation_runtime", + "sampleIndex": 1350, + "motionIndex": 11, + "line": 12, + "motionProgramLine": 12, + "halProgramLine": 12, + "activeLineSource": "motion-status", + "activeLineHalSynced": true, + "type": "TASK_MOTION", + "timeSeconds": 0, + "axisPose": { + "x": 6.3492, + "y": -12.5566, + "z": 25.9433, + "a": -71.1868, + "b": 0, + "c": -32.4679 + }, + "currentVelocityMmPerMin": 59.12256, + "requestedVelocityMmPerMin": 59.12256, + "distanceToGo": 0, + "dtg": { + "x": 0, + "y": 0, + "z": 0 + }, + "queueDepth": 0, + "activeDepth": 0, + "cycle": 1350, + "taskCycle": 135, + "halChangedPinCount": 0 + }, + "currentTimingSegment": { + "index": 4, + "line": 12, + "type": "STRAIGHT_FEED", + "motionClass": "feed", + "feedMode": "inverse-time", + "linearDistanceMm": 0.3718400193631667, + "angularDistanceDeg": 0.6244109223900512, + "feedRate": 159, + "requestedVelocityMmPerMin": 59.122563078743504, + "velocityMmPerMin": 59.122563078743504, + "angularVelocityDegPerMin": 99.28133666001814, + "durationSeconds": 0.37735849056603776, + "startSeconds": 1.0232100331153662, + "startAxes": { + "x": 6.358, + "y": -12.418, + "z": 26.178, + "u": 0, + "v": 0, + "w": 0, + "a": -71.266, + "b": 0, + "c": -32.919 + }, + "endAxes": { + "x": 6.346, + "y": -12.607, + "z": 25.858, + "u": 0, + "v": 0, + "w": 0, + "a": -71.158, + "b": 0, + "c": -32.304 + }, + "axes": { + "x": 6.346, + "y": -12.607, + "z": 25.858, + "u": 0, + "v": 0, + "w": 0, + "a": -71.158, + "b": 0, + "c": -32.304 + }, + "deltas": { + "x": -0.011999999999999567, + "y": -0.18900000000000006, + "z": -0.3200000000000003, + "u": 0, + "v": 0, + "w": 0, + "a": 0.10800000000000409, + "b": 0, + "c": 0.6149999999999949 + }, + "linearUnits": "mm", + "elapsedSeconds": 1.4005685236814038 + }, + "currentLineExecution": { + "status": "running", + "source": "linuxcnc-task-motion-hal-wasm", + "line": 12, + "feed": 59.12256, + "requestedFeed": 59.12256, + "feedMode": null, + "axisPose": { + "x": 6.3492, + "y": -12.5566, + "z": 25.9433, + "a": -71.1868, + "b": 0, + "c": -32.4679 + }, + "taskCycle": 135, + "servoCycle": 1350, + "sampleIndex": 1350, + "motionIndex": 11, + "updatedAt": "2026-06-23T07:40:16.328Z" + }, + "currentLineExecutionVisible": true, + "feedbackHistoryLength": 25, + "taskHalStatusLoop": { + "apiName": "web-rtcp-5axis-task-hal-status-loop", + "active": true, + "sequence": 1, + "profileId": "xyzac-trt", + "iniPath": "configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzac-trt.ini", + "kinematicsModuleId": "xyzac-trt", + "tickCount": 25, + "batchSize": 5, + "intervalMs": 25, + "taskPeriodNs": 10000000, + "servoPeriodNs": 1000000, + "lastStatusAt": "2026-06-23T07:40:16.328Z", + "lastError": null, + "stopReason": null, + "semanticBoundary": "js_status_polling_loop_for_linuxcnc_task_hal_motion_status" + }, + "taskHalStatus": { + "taskState": "on", + "taskMode": "auto", + "interpState": "reading", + "activeLine": 12, + "taskCycle": null, + "servoCycle": 1350 + } + } + }, + { + "name": "05-run-17000ms", + "title": "G-code 执行 17000ms", + "description": "采集 G-code 当前高亮行、执行轨迹、实时 DRO/axisPose 和 task/HAL feedback。", + "screenshotPath": "/home/meswork/cnc_wams/qa/web-rtcp-5axis-site-test/screenshots/test-linuxcnc-source-run/05-run-17000ms.png", + "dataset": { + "fiveAxisCanvas": "true", + "engine": "three.js r183", + "threeReady": "true", + "threeRevision": "183", + "threePathPoints": "4492", + "threeExecutedPathPoints": "1", + "threeSceneObjects": "20", + "threeToolhead": "{\"x\":0.006,\"y\":-0.013,\"z\":0.026}", + "threeSceneUnits": "m", + "threeLinearUnits": "mm", + "threeLinearUnitScaleToMeters": "0.001", + "threeToolAxis": "{\"x\":0.504,\"y\":0.801,\"z\":0.323}", + "threeTcpPose": "{\"x\":6.336,\"y\":-12.659,\"z\":25.777,\"a\":-71.141,\"c\":-32.149}", + "threeRtcpState": "on", + "threeSelectedView": "iso", + "threeFrameApi": "web-rtcp-5axis-motion-frame", + "threeRenderer": "webgl", + "threeSceneMode": "program-preview-and-tool-execution", + "threePreviewScope": "machine-reference-and-toolpath", + "threeMachineReferenceModel": "webgl-five-axis-reference", + "threeCameraControls": "orbit-pan-zoom", + "threeProgramPreviewSource": "linuxcnc-interpreter-wasm", + "threeToolExecutionMarker": "true", + "threeTcpMarker": "sphere", + "threeToolAxisMarker": "line", + "threeToolpathPreviewSource": "linuxcnc_interpreter_canonical_motion", + "threeToolExecutionTraceSource": "linuxcnc_tp_samples_or_task_motion_hal_feedback", + "threePathFitBounds": "ok", + "threePathBoundsMeters": "{\"center\":{\"x\":-0.001,\"y\":0,\"z\":0.019},\"size\":{\"x\":0.088,\"y\":0.089,\"z\":0.043},\"maxSpan\":0.089214}", + "threeCurrentSegmentHighlight": "ok", + "threeRapidFeedVisualDistinction": "ok", + "threeNoGcodeSemanticsGeneration": "ok", + "threeRapidPathPoints": "186", + "threeFeedPathPoints": "4306", + "threeArcPathPoints": "0", + "threeCurrentSegmentPoints": "1", + "threeCurrentSegmentType": "STRAIGHT_TRAVERSE" + }, + "pixelStats": { + "width": 1600, + "height": 1200, + "averageLuminance": 130.44, + "nonBlackRatio": 0.765 + }, + "state": { + "activeProgram": "configs/sim/axis/vismach/5axis/table-rotary-tilting/demos/impeller-7bl-xyzac.ngc", + "programSource": "linuxcnc-vendored-5axis-gcode", + "programExecutionSourceMode": "linuxcnc-task-motion-hal-wasm", + "programSummary": { + "ready": true, + "programLineCount": 4507, + "canonicalEventCount": 22313, + "motionEventCount": 4492, + "motionTypes": [ + "STRAIGHT_TRAVERSE", + "STRAIGHT_FEED" + ], + "finalAxes": { + "x": 0, + "y": 0, + "z": 40, + "a": 0, + "b": 0, + "c": 0, + "u": 0, + "v": 0, + "w": 0 + }, + "switchkinsEventCount": 2, + "switchkinsCodes": [ + "M428", + "M429" + ], + "switchkinsRemapBoundary": "linuxcnc_switchkins_remap_mcode_preserved_web_runtime_applied", + "remapRuntimeReady": false, + "plannerRuntimeReady": true, + "plannerSemanticBoundary": "linuxcnc_tp_queue_runtime_timing_from_canonical_motion", + "machineFileExecutionReady": false, + "fullLinuxCncProgramExecutionReady": false + }, + "machineProfile": "xyzac-trt", + "iniPath": "configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzac-trt.ini", + "selectedGcodeSourceRel": "configs/sim/axis/vismach/5axis/table-rotary-tilting/demos/impeller-7bl-xyzac.ngc", + "loadedSourceBytes": 294411, "taskHalProgramPath": "/work/sim/axis/vismach/5axis/table-rotary-tilting/xyzac-trt/demos/impeller-7bl-xyzac.ngc", "runState": "running", "activeLine": 13, @@ -2195,9 +2380,13 @@ "apiName": "web-rtcp-5axis-program-runtime-feedback", "sourceMode": "linuxcnc-task-motion-hal-wasm", "semanticBoundary": "linuxcnc_task_motion_hal_wasm_simulation_runtime", - "sampleIndex": 1530, + "sampleIndex": 1550, "motionIndex": 12, "line": 13, + "motionProgramLine": 13, + "halProgramLine": 13, + "activeLineSource": "motion-status", + "activeLineHalSynced": true, "type": "TASK_MOTION", "timeSeconds": 0, "axisPose": { @@ -2218,8 +2407,8 @@ }, "queueDepth": 0, "activeDepth": 0, - "cycle": 1530, - "taskCycle": 153, + "cycle": 1550, + "taskCycle": 155, "halChangedPinCount": 0 }, "currentTimingSegment": { @@ -2283,6 +2472,28 @@ "linearUnits": "mm", "elapsedSeconds": 1.7779270142474415 }, + "currentLineExecution": { + "status": "running", + "source": "linuxcnc-task-motion-hal-wasm", + "line": 13, + "feed": 58.19616, + "requestedFeed": 58.19616, + "feedMode": null, + "axisPose": { + "x": 6.33572, + "y": -12.6589, + "z": 25.7774, + "a": -71.1409, + "b": 0, + "c": -32.1488 + }, + "taskCycle": 155, + "servoCycle": 1550, + "sampleIndex": 1550, + "motionIndex": 12, + "updatedAt": "2026-06-23T07:40:20.100Z" + }, + "currentLineExecutionVisible": true, "feedbackHistoryLength": 29, "taskHalStatusLoop": { "apiName": "web-rtcp-5axis-task-hal-status-loop", @@ -2296,7 +2507,7 @@ "intervalMs": 25, "taskPeriodNs": 10000000, "servoPeriodNs": 1000000, - "lastStatusAt": "2026-06-22T23:27:04.211Z", + "lastStatusAt": "2026-06-23T07:40:20.100Z", "lastError": null, "stopReason": null, "semanticBoundary": "js_status_polling_loop_for_linuxcnc_task_hal_motion_status" @@ -2307,7 +2518,7 @@ "interpState": "reading", "activeLine": 13, "taskCycle": null, - "servoCycle": 1530 + "servoCycle": 1550 } } }, @@ -2358,8 +2569,8 @@ "pixelStats": { "width": 1600, "height": 1200, - "averageLuminance": 121.5, - "nonBlackRatio": 0.7429 + "averageLuminance": 130.4, + "nonBlackRatio": 0.7647 }, "state": { "activeProgram": "configs/sim/axis/vismach/5axis/table-rotary-tilting/demos/impeller-7bl-xyzac.ngc", @@ -2400,6 +2611,7 @@ "machineProfile": "xyzac-trt", "iniPath": "configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzac-trt.ini", "selectedGcodeSourceRel": "configs/sim/axis/vismach/5axis/table-rotary-tilting/demos/impeller-7bl-xyzac.ngc", + "loadedSourceBytes": 294411, "taskHalProgramPath": "/work/sim/axis/vismach/5axis/table-rotary-tilting/xyzac-trt/demos/impeller-7bl-xyzac.ngc", "runState": "stopped", "activeLine": 13, @@ -2442,9 +2654,13 @@ "apiName": "web-rtcp-5axis-program-runtime-feedback", "sourceMode": "linuxcnc-task-motion-hal-wasm", "semanticBoundary": "linuxcnc_task_motion_hal_wasm_simulation_runtime", - "sampleIndex": 1590, + "sampleIndex": 1610, "motionIndex": 12, "line": 13, + "motionProgramLine": 13, + "halProgramLine": 13, + "activeLineSource": "motion-status", + "activeLineHalSynced": true, "type": "TASK_MOTION", "timeSeconds": 0, "axisPose": { @@ -2465,8 +2681,8 @@ }, "queueDepth": 0, "activeDepth": 0, - "cycle": 1590, - "taskCycle": 159, + "cycle": 1610, + "taskCycle": 161, "halChangedPinCount": 0 }, "currentTimingSegment": { @@ -2530,6 +2746,28 @@ "linearUnits": "mm", "elapsedSeconds": 1.7779270142474415 }, + "currentLineExecution": { + "status": "stopped", + "source": "linuxcnc-task-motion-hal-wasm", + "line": 13, + "feed": 58.19616, + "requestedFeed": 58.19616, + "feedMode": null, + "axisPose": { + "x": 6.33056, + "y": -12.685, + "z": 25.7368, + "a": -71.1323, + "b": 0, + "c": -32.0708 + }, + "taskCycle": 161, + "servoCycle": 1610, + "sampleIndex": 1610, + "motionIndex": 12, + "updatedAt": "2026-06-23T07:40:24.497Z" + }, + "currentLineExecutionVisible": true, "feedbackHistoryLength": 31, "taskHalStatusLoop": { "apiName": "web-rtcp-5axis-task-hal-status-loop", @@ -2538,14 +2776,14 @@ "profileId": "xyzac-trt", "iniPath": "configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzac-trt.ini", "kinematicsModuleId": "xyzac-trt", - "tickCount": 29, + "tickCount": 30, "batchSize": 5, "intervalMs": 25, "taskPeriodNs": 10000000, "servoPeriodNs": 1000000, - "lastStatusAt": "2026-06-22T23:27:08.118Z", + "lastStatusAt": "2026-06-23T07:40:22.134Z", "lastError": null, - "stopReason": "idle", + "stopReason": "stopped", "semanticBoundary": "js_status_polling_loop_for_linuxcnc_task_hal_motion_status" }, "taskHalStatus": { @@ -2554,7 +2792,7 @@ "interpState": "idle", "activeLine": 13, "taskCycle": null, - "servoCycle": 1590 + "servoCycle": 1610 } } } @@ -2593,7 +2831,12 @@ { "name": "每行执行高亮同步", "pass": true, - "detail": "9/9, 10/10, 11/11, 11/11, 12/12, 13/13" + "detail": "9/9, 10/10, 11/11, 12/12, 12/12, 13/13" + }, + { + "name": "程序列表显示每行执行过程", + "pass": true, + "detail": "9:running:true, 10:running:true, 11:running:true, 12:running:true, 12:running:true, 13:running:true" }, { "name": "执行轨迹可见", @@ -2608,7 +2851,7 @@ { "name": "RUN feed 不是固定 3600 mm/min", "pass": true, - "detail": "200ms=2100, 500ms=635.748, 1000ms=283.9176, 2000ms=283.9176, 5000ms=59.12256, 17000ms=58.19616" + "detail": "200ms=2100, 500ms=635.748, 1000ms=283.9176, 2000ms=59.12256, 5000ms=59.12256, 17000ms=58.19616" }, { "name": "RUN feed 随实际 G-code F/G93 段变化", @@ -2623,12 +2866,12 @@ { "name": "task/HAL cycle 推进", "pass": true, - "detail": "33/330, 53/530, 78/780, 103/1030, 128/1280, 153/1530" + "detail": "35/350, 60/600, 85/850, 110/1100, 135/1350, 155/1550" }, { "name": "STOP 后 loop 停止", "pass": true, - "detail": "active=false, stopReason=idle" + "detail": "active=false, stopReason=stopped" } ], "samples": [ @@ -2663,9 +2906,31 @@ "segmentDurationSeconds": 0.4571722972663097, "distanceToGo": 0, "feedbackSource": "linuxcnc-task-motion-hal-wasm", - "taskCycle": 33, - "servoCycle": 330, + "taskCycle": 35, + "servoCycle": 350, "historyLength": 0, + "lineExecution": { + "status": "running", + "source": "linuxcnc-task-motion-hal-wasm", + "line": 9, + "feed": 2100, + "requestedFeed": 2100, + "feedMode": null, + "axisPose": { + "x": 10.4843, + "y": -17.3304, + "z": 30.0805, + "a": -71.841, + "b": 0, + "c": -35.93 + }, + "taskCycle": 35, + "servoCycle": 350, + "sampleIndex": 350, + "motionIndex": 8, + "updatedAt": "2026-06-23T07:39:58.821Z" + }, + "lineExecutionVisible": true, "executedPathPoints": 1, "currentSegmentHighlight": "ok" }, @@ -2677,17 +2942,17 @@ "activeLineMatchesUi": true, "runState": "running", "axisPose": { - "x": 7.16391, - "y": -12.7489, - "z": 28.2246, + "x": 6.86843, + "y": -12.3413, + "z": 28.0595, "a": -71.841, "b": 0, "c": -35.93 }, "dro": { - "x": 7.16391, - "y": -12.7489, - "z": 28.2246, + "x": 6.86843, + "y": -12.3413, + "z": 28.0595, "a": -71.841, "b": 0, "c": -35.93 @@ -2700,9 +2965,31 @@ "segmentDurationSeconds": 0.18867924528301888, "distanceToGo": 0, "feedbackSource": "linuxcnc-task-motion-hal-wasm", - "taskCycle": 53, - "servoCycle": 530, + "taskCycle": 60, + "servoCycle": 600, "historyLength": 0, + "lineExecution": { + "status": "running", + "source": "linuxcnc-task-motion-hal-wasm", + "line": 10, + "feed": 635.748, + "requestedFeed": 635.748, + "feedMode": null, + "axisPose": { + "x": 6.86843, + "y": -12.3413, + "z": 28.0595, + "a": -71.841, + "b": 0, + "c": -35.93 + }, + "taskCycle": 60, + "servoCycle": 600, + "sampleIndex": 600, + "motionIndex": 9, + "updatedAt": "2026-06-23T07:40:03.250Z" + }, + "lineExecutionVisible": true, "executedPathPoints": 1, "currentSegmentHighlight": "ok" }, @@ -2714,20 +3001,20 @@ "activeLineMatchesUi": true, "runState": "running", "axisPose": { - "x": 6.31746, - "y": -11.7968, - "z": 27.3111, - "a": -71.6823, + "x": 6.32488, + "y": -11.9105, + "z": 27.1037, + "a": -71.6061, "b": 0, - "c": -35.099 + "c": -34.7 }, "dro": { - "x": 6.31746, - "y": -11.7968, - "z": 27.3111, - "a": -71.6823, + "x": 6.32488, + "y": -11.9105, + "z": 27.1037, + "a": -71.6061, "b": 0, - "c": -35.099 + "c": -34.7 }, "droMatchesAxisPose": true, "velocity": 283.9176, @@ -2737,46 +3024,90 @@ "segmentDurationSeconds": 0.37735849056603776, "distanceToGo": 0, "feedbackSource": "linuxcnc-task-motion-hal-wasm", - "taskCycle": 78, - "servoCycle": 780, + "taskCycle": 85, + "servoCycle": 850, "historyLength": 0, + "lineExecution": { + "status": "running", + "source": "linuxcnc-task-motion-hal-wasm", + "line": 11, + "feed": 283.9176, + "requestedFeed": 283.9176, + "feedMode": null, + "axisPose": { + "x": 6.32488, + "y": -11.9105, + "z": 27.1037, + "a": -71.6061, + "b": 0, + "c": -34.7 + }, + "taskCycle": 85, + "servoCycle": 850, + "sampleIndex": 850, + "motionIndex": 10, + "updatedAt": "2026-06-23T07:40:07.592Z" + }, + "lineExecutionVisible": true, "executedPathPoints": 1, "currentSegmentHighlight": "ok" }, { "elapsedMs": 2000, "screenshotPath": "/home/meswork/cnc_wams/qa/web-rtcp-5axis-site-test/screenshots/test-linuxcnc-source-run/05-run-2000ms.png", - "activeLine": 11, - "activeUiLine": 11, + "activeLine": 12, + "activeUiLine": 12, "activeLineMatchesUi": true, "runState": "running", "axisPose": { - "x": 6.35456, - "y": -12.3652, - "z": 26.2743, - "a": -71.3014, + "x": 6.35715, + "y": -12.4314, + "z": 26.1553, + "a": -71.2583, "b": 0, - "c": -33.1042 + "c": -32.8753 }, "dro": { - "x": 6.35456, - "y": -12.3652, - "z": 26.2743, - "a": -71.3014, + "x": 6.35715, + "y": -12.4314, + "z": 26.1553, + "a": -71.2583, "b": 0, - "c": -33.1042 + "c": -32.8753 }, "droMatchesAxisPose": true, - "velocity": 283.9176, - "expectedVelocity": 283.9174184952374, + "velocity": 59.12256, + "expectedVelocity": 59.122563078743504, "feedRate": 159, "feedMode": "inverse-time", "segmentDurationSeconds": 0.37735849056603776, "distanceToGo": 0, "feedbackSource": "linuxcnc-task-motion-hal-wasm", - "taskCycle": 103, - "servoCycle": 1030, + "taskCycle": 110, + "servoCycle": 1100, "historyLength": 0, + "lineExecution": { + "status": "running", + "source": "linuxcnc-task-motion-hal-wasm", + "line": 12, + "feed": 59.12256, + "requestedFeed": 59.12256, + "feedMode": null, + "axisPose": { + "x": 6.35715, + "y": -12.4314, + "z": 26.1553, + "a": -71.2583, + "b": 0, + "c": -32.8753 + }, + "taskCycle": 110, + "servoCycle": 1100, + "sampleIndex": 1100, + "motionIndex": 11, + "updatedAt": "2026-06-23T07:40:11.943Z" + }, + "lineExecutionVisible": true, "executedPathPoints": 1, "currentSegmentHighlight": "ok" }, @@ -2788,20 +3119,20 @@ "activeLineMatchesUi": true, "runState": "running", "axisPose": { - "x": 6.35079, - "y": -12.5316, - "z": 25.9857, - "a": -71.2011, + "x": 6.3492, + "y": -12.5566, + "z": 25.9433, + "a": -71.1868, "b": 0, - "c": -32.5494 + "c": -32.4679 }, "dro": { - "x": 6.35079, - "y": -12.5316, - "z": 25.9857, - "a": -71.2011, + "x": 6.3492, + "y": -12.5566, + "z": 25.9433, + "a": -71.1868, "b": 0, - "c": -32.5494 + "c": -32.4679 }, "droMatchesAxisPose": true, "velocity": 59.12256, @@ -2811,9 +3142,31 @@ "segmentDurationSeconds": 0.37735849056603776, "distanceToGo": 0, "feedbackSource": "linuxcnc-task-motion-hal-wasm", - "taskCycle": 128, - "servoCycle": 1280, + "taskCycle": 135, + "servoCycle": 1350, "historyLength": 0, + "lineExecution": { + "status": "running", + "source": "linuxcnc-task-motion-hal-wasm", + "line": 12, + "feed": 59.12256, + "requestedFeed": 59.12256, + "feedMode": null, + "axisPose": { + "x": 6.3492, + "y": -12.5566, + "z": 25.9433, + "a": -71.1868, + "b": 0, + "c": -32.4679 + }, + "taskCycle": 135, + "servoCycle": 1350, + "sampleIndex": 1350, + "motionIndex": 11, + "updatedAt": "2026-06-23T07:40:16.328Z" + }, + "lineExecutionVisible": true, "executedPathPoints": 1, "currentSegmentHighlight": "ok" }, @@ -2848,9 +3201,31 @@ "segmentDurationSeconds": 0.37735849056603776, "distanceToGo": 0, "feedbackSource": "linuxcnc-task-motion-hal-wasm", - "taskCycle": 153, - "servoCycle": 1530, + "taskCycle": 155, + "servoCycle": 1550, "historyLength": 0, + "lineExecution": { + "status": "running", + "source": "linuxcnc-task-motion-hal-wasm", + "line": 13, + "feed": 58.19616, + "requestedFeed": 58.19616, + "feedMode": null, + "axisPose": { + "x": 6.33572, + "y": -12.6589, + "z": 25.7774, + "a": -71.1409, + "b": 0, + "c": -32.1488 + }, + "taskCycle": 155, + "servoCycle": 1550, + "sampleIndex": 1550, + "motionIndex": 12, + "updatedAt": "2026-06-23T07:40:20.100Z" + }, + "lineExecutionVisible": true, "executedPathPoints": 1, "currentSegmentHighlight": "ok" } @@ -2861,5 +3236,5 @@ ], "status": "PASS", "jsonPath": "/home/meswork/cnc_wams/qa/web-rtcp-5axis-site-test/output/test-linuxcnc-source-run-report.json", - "docxPath": "/home/meswork/cnc_wams/qa/web-rtcp-5axis-site-test/output/test-linuxcnc-source-run-report-2026-06-22.docx" + "docxPath": "/home/meswork/cnc_wams/qa/web-rtcp-5axis-site-test/output/test-linuxcnc-source-run-report-2026-06-23.docx" } diff --git a/qa/web-rtcp-5axis-site-test/screenshots/test-linuxcnc-source-run/01-initial-ui.png b/qa/web-rtcp-5axis-site-test/screenshots/test-linuxcnc-source-run/01-initial-ui.png index 9f6f79a..f24f380 100644 Binary files a/qa/web-rtcp-5axis-site-test/screenshots/test-linuxcnc-source-run/01-initial-ui.png and b/qa/web-rtcp-5axis-site-test/screenshots/test-linuxcnc-source-run/01-initial-ui.png differ diff --git a/qa/web-rtcp-5axis-site-test/screenshots/test-linuxcnc-source-run/02-stage-test-ini.png b/qa/web-rtcp-5axis-site-test/screenshots/test-linuxcnc-source-run/02-stage-test-ini.png index 0627ea4..6a1866a 100644 Binary files a/qa/web-rtcp-5axis-site-test/screenshots/test-linuxcnc-source-run/02-stage-test-ini.png and b/qa/web-rtcp-5axis-site-test/screenshots/test-linuxcnc-source-run/02-stage-test-ini.png differ diff --git a/qa/web-rtcp-5axis-site-test/screenshots/test-linuxcnc-source-run/03-toolpath-preview.png b/qa/web-rtcp-5axis-site-test/screenshots/test-linuxcnc-source-run/03-toolpath-preview.png index a6a7ab4..b1c399c 100644 Binary files a/qa/web-rtcp-5axis-site-test/screenshots/test-linuxcnc-source-run/03-toolpath-preview.png and b/qa/web-rtcp-5axis-site-test/screenshots/test-linuxcnc-source-run/03-toolpath-preview.png differ diff --git a/qa/web-rtcp-5axis-site-test/screenshots/test-linuxcnc-source-run/04-ready-before-run.png b/qa/web-rtcp-5axis-site-test/screenshots/test-linuxcnc-source-run/04-ready-before-run.png index 2eb00ab..77e5c9a 100644 Binary files a/qa/web-rtcp-5axis-site-test/screenshots/test-linuxcnc-source-run/04-ready-before-run.png and b/qa/web-rtcp-5axis-site-test/screenshots/test-linuxcnc-source-run/04-ready-before-run.png differ diff --git a/qa/web-rtcp-5axis-site-test/screenshots/test-linuxcnc-source-run/05-run-0200ms.png b/qa/web-rtcp-5axis-site-test/screenshots/test-linuxcnc-source-run/05-run-0200ms.png index 6f73e60..f9492dc 100644 Binary files a/qa/web-rtcp-5axis-site-test/screenshots/test-linuxcnc-source-run/05-run-0200ms.png and b/qa/web-rtcp-5axis-site-test/screenshots/test-linuxcnc-source-run/05-run-0200ms.png differ diff --git a/qa/web-rtcp-5axis-site-test/screenshots/test-linuxcnc-source-run/05-run-0500ms.png b/qa/web-rtcp-5axis-site-test/screenshots/test-linuxcnc-source-run/05-run-0500ms.png index 0dcde42..b518bc5 100644 Binary files a/qa/web-rtcp-5axis-site-test/screenshots/test-linuxcnc-source-run/05-run-0500ms.png and b/qa/web-rtcp-5axis-site-test/screenshots/test-linuxcnc-source-run/05-run-0500ms.png differ diff --git a/qa/web-rtcp-5axis-site-test/screenshots/test-linuxcnc-source-run/05-run-1000ms.png b/qa/web-rtcp-5axis-site-test/screenshots/test-linuxcnc-source-run/05-run-1000ms.png index 65c6948..9682c8e 100644 Binary files a/qa/web-rtcp-5axis-site-test/screenshots/test-linuxcnc-source-run/05-run-1000ms.png and b/qa/web-rtcp-5axis-site-test/screenshots/test-linuxcnc-source-run/05-run-1000ms.png differ diff --git a/qa/web-rtcp-5axis-site-test/screenshots/test-linuxcnc-source-run/05-run-17000ms.png b/qa/web-rtcp-5axis-site-test/screenshots/test-linuxcnc-source-run/05-run-17000ms.png index 89b4374..5e374f7 100644 Binary files a/qa/web-rtcp-5axis-site-test/screenshots/test-linuxcnc-source-run/05-run-17000ms.png and b/qa/web-rtcp-5axis-site-test/screenshots/test-linuxcnc-source-run/05-run-17000ms.png differ diff --git a/qa/web-rtcp-5axis-site-test/screenshots/test-linuxcnc-source-run/05-run-2000ms.png b/qa/web-rtcp-5axis-site-test/screenshots/test-linuxcnc-source-run/05-run-2000ms.png index 8d70051..c823a3b 100644 Binary files a/qa/web-rtcp-5axis-site-test/screenshots/test-linuxcnc-source-run/05-run-2000ms.png and b/qa/web-rtcp-5axis-site-test/screenshots/test-linuxcnc-source-run/05-run-2000ms.png differ diff --git a/qa/web-rtcp-5axis-site-test/screenshots/test-linuxcnc-source-run/05-run-5000ms.png b/qa/web-rtcp-5axis-site-test/screenshots/test-linuxcnc-source-run/05-run-5000ms.png index b2f1f72..9fbb4d7 100644 Binary files a/qa/web-rtcp-5axis-site-test/screenshots/test-linuxcnc-source-run/05-run-5000ms.png and b/qa/web-rtcp-5axis-site-test/screenshots/test-linuxcnc-source-run/05-run-5000ms.png differ diff --git a/qa/web-rtcp-5axis-site-test/screenshots/test-linuxcnc-source-run/06-stop-after-run.png b/qa/web-rtcp-5axis-site-test/screenshots/test-linuxcnc-source-run/06-stop-after-run.png index cbb74e7..fe7e5c2 100644 Binary files a/qa/web-rtcp-5axis-site-test/screenshots/test-linuxcnc-source-run/06-stop-after-run.png and b/qa/web-rtcp-5axis-site-test/screenshots/test-linuxcnc-source-run/06-stop-after-run.png differ diff --git a/web-rtcp-5axis-sim-plan/app/scripts/build-static.mjs b/web-rtcp-5axis-sim-plan/app/scripts/build-static.mjs index bb6a9f4..a7c2bdd 100644 --- a/web-rtcp-5axis-sim-plan/app/scripts/build-static.mjs +++ b/web-rtcp-5axis-sim-plan/app/scripts/build-static.mjs @@ -12,6 +12,7 @@ await cp(join(appRoot, "index.html"), join(distDir, "index.html")); await cp(join(appRoot, "src"), join(distDir, "src"), { recursive: true }); await copyLinuxCncManifest(); await copyLinuxCncConfigAssets(); +await copyBundledTestLinuxCncSourceAssets(); await copyKinematicsRuntimeAssets(); await copyInterpreterRuntimeAssets(); await copyTpRuntimeAssets(); @@ -68,6 +69,13 @@ async function copyLinuxCncConfigAssets() { await cp(configSrcDir, vendorConfigDistDir, { recursive: true }); } +async function copyBundledTestLinuxCncSourceAssets() { + const testSourceDir = join(repoRoot, "web-rtcp-5axis-sim-plan/working_run/test_linuxcnc_source"); + const testSourceDistDir = join(distDir, "working_run/test_linuxcnc_source"); + await mkdir(testSourceDistDir, { recursive: true }); + await cp(testSourceDir, testSourceDistDir, { recursive: true }); +} + async function copyLinuxCncManifest() { const manifestDistDir = join(distDir, "wasm-port/tools"); await mkdir(manifestDistDir, { recursive: true }); diff --git a/web-rtcp-5axis-sim-plan/app/src/runtime/linuxcnc-machine-file-staging.js b/web-rtcp-5axis-sim-plan/app/src/runtime/linuxcnc-machine-file-staging.js index 33ac2f4..debc63c 100644 --- a/web-rtcp-5axis-sim-plan/app/src/runtime/linuxcnc-machine-file-staging.js +++ b/web-rtcp-5axis-sim-plan/app/src/runtime/linuxcnc-machine-file-staging.js @@ -7,6 +7,11 @@ const DEFAULT_VENDOR_ROOT_URLS = [ new URL("../../../../wasm-port/vendor/linuxcnc/", import.meta.url).href, new URL("../../wasm-port/vendor/linuxcnc/", import.meta.url).href, ]; +const DEFAULT_TEST_SOURCE_ROOT_URLS = [ + new URL("../../../working_run/test_linuxcnc_source/", import.meta.url).href, + new URL("../../working_run/test_linuxcnc_source/", import.meta.url).href, + new URL("../../../../working_run/test_linuxcnc_source/", import.meta.url).href, +]; const TRT_MACHINE_REL = "axis/vismach/5axis/table-rotary-tilting"; const TRT_DEMO_SOURCE_PREFIX = `configs/sim/${TRT_MACHINE_REL}/demos/`; const OPFS_ROOT = "web-rtcp-5axis-sim-plan/machines"; @@ -125,9 +130,12 @@ export async function saveMachineFileStagingPlan(plan, options = {}) { throw new Error("saveMachineFileStagingPlan requires a machine-file staging plan"); } const storage = resolveMachineFileStorage(options); + const sourceTextOverrides = options.sourceTextOverrides || {}; const savedFiles = []; for (const file of plan.files) { - const text = await readTextFromCandidateUrls(sourceUrlsFor(file.sourceRel)); + const text = typeof sourceTextOverrides[file.sourceRel] === "string" + ? sourceTextOverrides[file.sourceRel] + : await readTextFromCandidateUrls(sourceUrlsFor(file.sourceRel)); await saveTextFile(file.opfsPath, text, storage.storage); savedFiles.push({ sourceRel: file.sourceRel, @@ -182,6 +190,7 @@ export async function stageProfileMachineFiles(profile, options = {}) { const save = await saveMachineFileStagingPlan(plan, { storage: options.storage, storageMode: options.storageMode, + sourceTextOverrides: options.sourceTextOverrides, }); return { plan, save }; } @@ -441,7 +450,22 @@ function splitPath(path) { } function sourceUrlsFor(sourceRel) { - return DEFAULT_VENDOR_ROOT_URLS.map((rootUrl) => new URL(sourceRel, rootUrl).href); + return sourceOverrideUrlsFor(sourceRel).concat( + DEFAULT_VENDOR_ROOT_URLS.map((rootUrl) => new URL(sourceRel, rootUrl).href), + ); +} + +function sourceOverrideUrlsFor(sourceRel) { + const basenameValue = basename(sourceRel); + if (!basenameValue) return []; + + if (sourceRel === `configs/sim/${TRT_MACHINE_REL}/xyzac-trt.ini`) { + return DEFAULT_TEST_SOURCE_ROOT_URLS.map((rootUrl) => new URL("xyzac-trt.ini", rootUrl).href); + } + if (sourceRel === `${TRT_DEMO_SOURCE_PREFIX}impeller-7bl-xyzac.ngc`) { + return DEFAULT_TEST_SOURCE_ROOT_URLS.map((rootUrl) => new URL("impeller-7bl-xyzac.ngc", rootUrl).href); + } + return []; } function basename(path) { diff --git a/web-rtcp-5axis-sim-plan/app/src/state/store.js b/web-rtcp-5axis-sim-plan/app/src/state/store.js index 6eb0a66..ed16b59 100644 --- a/web-rtcp-5axis-sim-plan/app/src/state/store.js +++ b/web-rtcp-5axis-sim-plan/app/src/state/store.js @@ -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"; diff --git a/web-rtcp-5axis-sim-plan/app/src/styles/gmoccapy.css b/web-rtcp-5axis-sim-plan/app/src/styles/gmoccapy.css index 2f20cf1..affe9f6 100644 --- a/web-rtcp-5axis-sim-plan/app/src/styles/gmoccapy.css +++ b/web-rtcp-5axis-sim-plan/app/src/styles/gmoccapy.css @@ -21,16 +21,22 @@ html, body { - width: 100%; - min-width: 1180px; - min-height: 640px; - height: 100%; + width: 100vw; + height: 100vh; + height: 100dvh; margin: 0; overflow: hidden; background: #c8c4bc; color: var(--text); } +#app { + width: 100vw; + height: 100vh; + height: 100dvh; + overflow: hidden; +} + button { border: 1px solid #bdb8ad; border-radius: 5px; @@ -66,21 +72,21 @@ button:active { .gmoccapy-shell { display: grid; grid-template-columns: - minmax(610px, 1.34fr) - minmax(270px, 0.58fr) - minmax(260px, 0.56fr) + minmax(0, 1.34fr) + minmax(0, 0.58fr) + minmax(0, 0.56fr) 108px; - grid-template-rows: 40px minmax(210px, 1fr) minmax(170px, 0.78fr) 150px 68px; + grid-template-rows: 40px minmax(0, 1fr) minmax(0, 0.82fr) minmax(110px, 0.48fr) 68px; grid-template-areas: "title title title title" "preview dro dro side" "preview gcode gcode side" "info override spindle side" "bottom bottom bottom side"; - width: 100vw; - height: 100vh; - min-width: 1180px; - min-height: 640px; + width: 100%; + height: 100%; + min-width: 0; + min-height: 0; border: 1px solid var(--border); background: var(--panel); } @@ -140,6 +146,35 @@ button:active { text-transform: uppercase; } +.current-line-indicator { + display: grid; + grid-template-columns: auto minmax(44px, auto); + align-items: center; + gap: 8px; + flex: 0 0 auto; + min-width: 0; + padding: 4px 8px; + border: 1px solid #8d887f; + background: #f7f1d0; + color: #171717; +} + +.current-line-indicator span { + min-width: 0; + overflow: hidden; + font-size: 11px; + font-weight: 700; + text-overflow: ellipsis; + text-transform: uppercase; + white-space: nowrap; +} + +.current-line-indicator strong { + color: #005bab; + font: 700 20px/1 "Courier New", monospace; + text-align: right; +} + .preview-panel { grid-area: preview; position: relative; @@ -336,7 +371,7 @@ button:active { .gcode-panel { grid-area: gcode; display: grid; - grid-template-rows: 32px minmax(0, 1fr) 20px 54px; + grid-template-rows: auto auto minmax(96px, 1fr) 20px 54px; min-width: 0; min-height: 0; overflow: hidden; @@ -357,6 +392,38 @@ button:active { font-size: 13px; } +.linuxcnc-source-row { + display: grid; + grid-template-columns: minmax(260px, 1fr) auto minmax(180px, 1fr); + align-items: center; + gap: 8px; + min-width: 0; + padding: 5px 8px; + border-bottom: 1px solid #d5d0c7; + background: #f6f4ef; + font-size: 12px; +} + +.linuxcnc-source-row label { + display: grid; + grid-template-columns: auto minmax(150px, 240px); + align-items: center; + gap: 6px; + min-width: 0; +} + +.linuxcnc-source-row select { + min-width: 0; + max-width: 100%; +} + +.linuxcnc-source-row [data-linuxcnc-gcode-source="status"] { + min-width: 0; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; +} + .gcode-header strong, .gcode-header span { min-width: 0; @@ -385,26 +452,54 @@ button:active { display: grid; grid-template-columns: 42px minmax(0, 1fr); gap: 6px; - min-height: 18px; + min-height: 34px; line-height: 1.25; + padding: 2px 4px; + border-left: 3px solid transparent; } .gcode-row.active { background: #242424; color: #202020; + border-left-color: #2ebf63; +} + +.gcode-row[data-line-status="done"] { + background: #eef6ec; + border-left-color: #79a96c; +} + +.gcode-row[data-line-status="running"] { + background: #242424; + border-left-color: #2ebf63; } .gcode-row.active span, -.gcode-row.active code { +.gcode-row.active code, +.gcode-row.active small, +.gcode-row[data-line-status="running"] span, +.gcode-row[data-line-status="running"] code, +.gcode-row[data-line-status="running"] small { color: #f2f2f2; } .gcode-row code { + min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; } +.gcode-row small { + grid-column: 2; + min-width: 0; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + color: #6d695f; + font: 11px/1.2 "Courier New", monospace; +} + .gcode-progress { display: grid; grid-template-columns: 120px 1fr; @@ -723,7 +818,7 @@ button:active { .bottom-controls { grid-area: bottom; display: grid; - grid-template-columns: repeat(15, minmax(48px, 1fr)); + grid-template-columns: repeat(18, minmax(44px, 1fr)); gap: 5px; padding: 6px 8px; border-top: 2px solid var(--border); @@ -746,10 +841,23 @@ button:active { @media (max-width: 1180px) { .gmoccapy-shell { grid-template-columns: - minmax(560px, 1.28fr) - minmax(250px, 0.58fr) - minmax(230px, 0.54fr) - 100px; + minmax(0, 1.18fr) + minmax(0, 0.7fr) + minmax(0, 0.62fr) + 96px; + } + + .titlebar { + gap: 6px; + padding: 4px 8px; + } + + .profile-select-label { + min-width: 160px; + } + + .current-line-indicator strong { + font-size: 16px; } .dro-row strong { @@ -765,6 +873,14 @@ button:active { font-size: 12px; } + .linuxcnc-source-row { + grid-template-columns: minmax(180px, 1fr) auto minmax(140px, 1fr); + } + + .linuxcnc-source-row label { + grid-template-columns: auto minmax(120px, 1fr); + } + .tabs button, .meter-card h2, .override-control h2, @@ -773,3 +889,180 @@ button:active { font-size: 12px; } } + +@media (max-height: 720px) { + .gmoccapy-shell { + grid-template-rows: 40px minmax(0, 1fr) minmax(0, 1fr) minmax(84px, 0.4fr) 58px; + } + + .preview-toolbar button, + .bottom-controls button, + .status-sidebar button { + min-height: 34px; + } + + .gcode-panel { + grid-template-rows: auto auto minmax(0, 1fr) 18px 48px; + } + + .gcode-list { + padding: 4px 6px 2px; + font-size: 12px; + } + + .gcode-row { + min-height: 24px; + } + + .gcode-row small { + display: none; + } + + .bottom-controls { + grid-template-columns: repeat(18, minmax(36px, 1fr)); + } +} + +@media (max-height: 420px) { + .gmoccapy-shell { + grid-template-rows: 24px minmax(24px, 0.14fr) minmax(0, 1.92fr) 0 28px; + } + + .titlebar { + gap: 4px; + padding: 2px 5px; + } + + .title-stack strong { + font-size: 10px; + } + + .title-stack span, + .run-state { + font-size: 8px; + } + + .profile-select-label { + min-width: 96px; + font-size: 8px; + } + + .profile-select-label select { + min-height: 16px; + font-size: 8px; + } + + .current-line-indicator { + padding: 1px 4px; + } + + .current-line-indicator span { + font-size: 8px; + } + + .current-line-indicator strong { + font-size: 9px; + } + + .info-tabs, + .override-panel, + .spindle-coolant-panel { + display: none; + } + + .gcode-panel { + grid-template-rows: auto auto minmax(0, 1fr) 12px; + } + + .gcode-header { + gap: 4px; + padding: 1px 3px; + font-size: 8px; + } + + .linuxcnc-source-row { + gap: 4px; + padding: 1px 3px; + font-size: 8px; + grid-template-columns: minmax(120px, 1fr) auto minmax(72px, 0.82fr); + } + + .linuxcnc-source-row label { + gap: 4px; + grid-template-columns: auto minmax(72px, 1fr); + } + + .linuxcnc-source-row button, + .linuxcnc-source-row select { + min-height: 16px; + font-size: 8px; + } + + .gcode-list { + padding: 2px 4px; + font-size: 8px; + line-height: 1; + } + + .gcode-row { + gap: 4px; + min-height: 8px; + padding: 0 2px; + border-left-width: 2px; + } + + .gcode-row span { + font-size: 8px; + } + + .gcode-row code { + font-size: 8px; + } + + .mdi-panel { + display: none; + } + + .dro-panel { + grid-template-rows: 1fr; + } + + .dro-grid { + grid-template-columns: repeat(6, minmax(0, 1fr)); + grid-template-rows: 1fr; + } + + .dro-row { + grid-template-columns: auto minmax(0, 1fr); + gap: 3px; + padding: 1px 4px; + align-items: center; + } + + .dro-axis { + font-size: 8px; + } + + .dro-mode, + .dro-dtg, + .tcp-strip { + display: none; + } + + .dro-row strong { + font-size: 9px; + line-height: 1; + } + + .bottom-controls { + gap: 3px; + padding: 2px 3px; + } + + .bottom-controls button { + font-size: 8px; + line-height: 1; + min-height: 18px; + padding: 1px 2px; + } +} diff --git a/web-rtcp-5axis-sim-plan/app/src/ui/gmoccapy-shell.js b/web-rtcp-5axis-sim-plan/app/src/ui/gmoccapy-shell.js index 948abb8..e7627c4 100644 --- a/web-rtcp-5axis-sim-plan/app/src/ui/gmoccapy-shell.js +++ b/web-rtcp-5axis-sim-plan/app/src/ui/gmoccapy-shell.js @@ -59,6 +59,7 @@ function render(regions, state, dispatch) { } function renderTitlebar(element, state) { + const currentLine = currentGcodeExecutionLine(state); element.innerHTML = `
@@ -73,6 +74,10 @@ function renderTitlebar(element, state) { `).join("")} +
+ G-code line + ${currentLine} +
${state.runState}
`; element.querySelector('[data-action="select-profile"]').addEventListener("change", (event) => { @@ -192,11 +197,20 @@ function droRow(axis, value, dtg) { } function renderGcode(element, state, dispatch) { + const currentLine = currentGcodeExecutionLine(state); const rows = state.programLines .map((line, index) => { const lineNumber = state.programStartLine + index; + const execution = state.programLineExecution?.[lineNumber] || null; const active = lineNumber === state.activeLine ? " active" : ""; - return `
  • ${lineNumber}${escapeHtml(line)}
  • `; + const status = execution?.status || (lineNumber < state.activeLine ? "done" : "pending"); + return ` +
  • + ${lineNumber} + ${escapeHtml(line)} + ${formatLineExecution(execution, active)} +
  • + `; }) .join(""); const programEndLine = state.programStartLine + Math.max(state.programLines.length - 1, 0); @@ -210,7 +224,7 @@ function renderGcode(element, state, dispatch) {
    ${escapeHtml(state.activeProgram)} ${state.programSource} - Current line ${state.activeLine} + Executing line ${currentLine}