diff --git a/qa/web-rtcp-5axis-site-test/capture-gmoccapy-xyzab-function-cases.mjs b/qa/web-rtcp-5axis-site-test/capture-gmoccapy-xyzab-function-cases.mjs new file mode 100644 index 0000000..5f82267 --- /dev/null +++ b/qa/web-rtcp-5axis-site-test/capture-gmoccapy-xyzab-function-cases.mjs @@ -0,0 +1,436 @@ +import fs from "node:fs/promises"; +import http from "node:http"; +import path from "node:path"; +import { randomUUID } from "node:crypto"; +import puppeteer from "puppeteer-core"; +import { PNG } from "pngjs"; + +const REPO_ROOT = path.resolve("/home/meswork/cnc_wams"); +const QA_ROOT = path.join(REPO_ROOT, "qa/web-rtcp-5axis-site-test"); +const OUTPUT_DIR = path.join(QA_ROOT, "output"); +const SCREENSHOT_DIR = path.join(OUTPUT_DIR, "gmoccapy-xyzab"); +const CHROME_PATH = process.env.CHROME_PATH || process.env.CHROMIUM || "/usr/bin/google-chrome"; +const TARGET_URL = process.env.TARGET_URL || ""; +const APP_URL = process.env.APP_URL || "/web-rtcp-5axis-sim-plan/app/index.html"; +const JOB_ID = process.env.JOB_ID || `xyzab-${new Date().toISOString().replace(/[-:.TZ]/g, "").slice(0, 14)}-${randomUUID().slice(0, 8)}`; +const REPORT_ID = process.env.REPORT_ID || `report-${JOB_ID}`; + +await fs.mkdir(OUTPUT_DIR, { recursive: true }); +await fs.mkdir(SCREENSHOT_DIR, { recursive: true }); + +let server = null; +let targetUrl = TARGET_URL; +if (!targetUrl) { + server = createStaticServer(REPO_ROOT); + await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve)); + const address = server.address(); + if (!address || typeof address === "string") throw new Error("failed to start static server"); + targetUrl = `http://127.0.0.1:${address.port}${APP_URL}`; +} + +const browser = await puppeteer.launch({ + headless: true, + executablePath: CHROME_PATH, + defaultViewport: { width: 1500, height: 1050, deviceScaleFactor: 1 }, + ignoreHTTPSErrors: true, + args: [ + "--ignore-certificate-errors", + "--disable-gpu", + "--enable-webgl", + "--use-angle=swiftshader", + "--enable-unsafe-swiftshader", + "--no-sandbox", + ], +}); + +const page = await browser.newPage(); +const consoleErrors = []; +const pageErrors = []; +page.on("console", (msg) => { + if (msg.type() === "error") consoleErrors.push(msg.text()); +}); +page.on("pageerror", (error) => pageErrors.push(error.message)); + +const report = { + jobId: JOB_ID, + reportId: REPORT_ID, + evidenceScope: "gmoccapy-xyzab-function", + generatedAt: new Date().toISOString(), + targetUrl, + chromePath: CHROME_PATH, + screenshotsDir: SCREENSHOT_DIR, + steps: [], + checks: [], + consoleErrors, + pageErrors, +}; + +try { + await page.goto(report.targetUrl, { waitUntil: "networkidle2", timeout: 60000 }); + await page.waitForSelector('[data-shell="gmoccapy-5axis"]', { timeout: 15000 }); + await page.waitForFunction(() => Boolean(window.webRtcp5AxisSimulation?.getState), { timeout: 15000 }); + await page.waitForFunction(() => document.querySelector("[data-five-axis-canvas]")?.dataset?.threeReady === "true", { timeout: 20000 }); + await waitForState((state) => state.kinematicsRuntimeReadiness?.loaded === true, 30000, "initial runtime ready"); + await captureStep("01-loaded", "Initial gmoccapy shell", "Default shell loaded with icon registry and diagnostics."); + + await page.select('[data-action="select-profile"]', "gmoccapy-xyzab"); + await waitForState((state) => state.machineProfile === "gmoccapy-xyzab", 15000, "gmoccapy XYZAB selected"); + await wait(500); + await captureStep("02-profile-selected", "gmoccapy XYZAB selected", "Reference profile shows XYZAB/trivkins and disables TCP promotion."); + + await click("RUN"); + await waitForState((state) => state.operatorMessage === "run blocked: machine must be on", 5000, "RUN blocked before power"); + await captureStep("03-run-blocked-power", "RUN blocked before power", "RUN remains clickable but reports LinuxCNC/gmoccapy gate reason."); + + await click("power"); + await waitForState((state) => state.machine.powerOn === true, 8000, "power on"); + await click("HOME"); + await waitForState((state) => state.machine.allHomed === true, 8000, "home complete"); + await click("mode-auto"); + await waitForState((state) => state.machine.mode === "auto", 8000, "auto mode"); + await click("RUN"); + await waitForState((state) => isReferenceRunBlockedReason(state.operatorMessage), 5000, "RUN blocked by reference evidence"); + await captureStep("04-run-blocked-reference-evidence", "RUN blocked by reference evidence", "XYZAB passes power/home/auto gates but remains blocked without complete native INI/machine-file/runtime evidence."); + + await click("mode-manual"); + await waitForState((state) => state.machine.mode === "manual", 8000, "manual mode"); + await click("spindle-forward"); + await waitForState((state) => state.spindle.direction === "forward" && state.spindle.enabled === true, 5000, "spindle forward"); + await click("spindle-stop"); + await waitForState((state) => state.spindle.direction === "stop" && state.spindle.enabled === false, 5000, "spindle stop"); + await click("toggle-flood"); + await waitForState((state) => state.coolant.flood === false, 5000, "flood toggled"); + await click("toggle-mist"); + await waitForState((state) => state.coolant.mist === true, 5000, "mist toggled"); + await captureStep("05-controls-active", "Spindle and coolant controls", "Spindle/coolant icons update through task policy guarded store actions."); + + await captureStep("06-hal-diagnostics", "HAL and communication diagnostics", "Info panel exposes native NML/HAL/postgui references and Web runtime boundary."); + addChecks(); + report.status = report.checks.every((check) => check.pass) && pageErrors.length === 0 ? "PASS" : "FAIL"; + + const jsonPath = path.join(OUTPUT_DIR, "gmoccapy-xyzab-function-report.json"); + const pdfPath = path.join(OUTPUT_DIR, "gmoccapy-xyzab-function-report.pdf"); + report.jsonPath = jsonPath; + report.pdfPath = pdfPath; + await fs.writeFile(jsonPath, `${JSON.stringify(report, null, 2)}\n`, "utf8"); + await writePdfReport(pdfPath, report); + + console.log(`gmoccapy_xyzab_function_status=${report.status}`); + console.log(`gmoccapy_xyzab_function_job_id=${report.jobId}`); + console.log(`gmoccapy_xyzab_function_report_id=${report.reportId}`); + console.log(`gmoccapy_xyzab_function_json=${jsonPath}`); + console.log(`gmoccapy_xyzab_function_pdf=${pdfPath}`); + console.log(`gmoccapy_xyzab_function_screenshots=${SCREENSHOT_DIR}`); + if (report.status !== "PASS") process.exitCode = 1; +} finally { + await page.close().catch(() => {}); + await browser.close().catch(() => {}); + if (server) await new Promise((resolve) => server.close(resolve)); +} + +async function captureStep(name, title, description) { + const screenshotPath = path.join(SCREENSHOT_DIR, `${name}.png`); + await page.screenshot({ path: screenshotPath, fullPage: true }); + const [state, dom, pixelStats] = await Promise.all([ + getState(), + getDomEvidence(), + analyzePng(screenshotPath), + ]); + const step = { + name, + title, + description, + screenshotPath, + pixelStats, + state: summarizeState(state), + dom, + }; + report.steps.push(step); + return step; +} + +async function getDomEvidence() { + return page.evaluate(() => { + const text = (selector) => document.querySelector(selector)?.textContent?.trim() || ""; + const button = (action) => { + const element = document.querySelector(`[data-action="${action}"]`); + return { + exists: Boolean(element), + iconName: element?.dataset?.iconName || null, + iconVariant: element?.dataset?.iconVariant || null, + buttonId: element?.dataset?.gmoccapyButtonId || null, + active: element?.dataset?.active || null, + commandReady: element?.dataset?.commandReady || null, + title: element?.getAttribute("title") || "", + }; + }; + return { + buttons: Object.fromEntries([ + "estop", + "power", + "mode-manual", + "mode-auto", + "mode-mdi", + "RUN", + "STOP", + "PAUSE", + "HOME", + "spindle-forward", + "spindle-stop", + "spindle-reverse", + "toggle-flood", + "toggle-mist", + "view-x", + ].map((action) => [action, button(action)])), + profileSummary: text('[data-linuxcnc-boundary="profile-summary"]'), + iniKins: text('[data-linuxcnc-ini="kins"]'), + taskGates: text('[data-linuxcnc-task-policy="gates"]'), + gmoccapyCommBoundary: text('[data-gmoccapy-comm="boundary"]'), + gmoccapyNativeCommand: text('[data-gmoccapy-comm="native-command"]'), + gmoccapyWebPath: text('[data-gmoccapy-comm="web-path"]'), + gmoccapyPostgui: text('[data-gmoccapy-comm="postgui"]'), + gmoccapyHalBoundary: text('[data-gmoccapy-hal="boundary"]'), + gmoccapyHalPostgui: text('[data-gmoccapy-hal="postgui"]'), + operatorMessage: text("[data-operator-message]"), + }; + }); +} + +async function writePdfReport(pdfPath, data) { + const reportPage = await browser.newPage(); + const rows = data.checks.map((item) => ` + + ${escapeHtml(item.name)} + ${item.pass ? "PASS" : "FAIL"} + ${escapeHtml(item.detail)} + + `).join(""); + const steps = data.steps.map((step) => ` +
+

${escapeHtml(step.name)} - ${escapeHtml(step.title)}

+

${escapeHtml(step.description)}

+

Screenshot: ${escapeHtml(step.screenshotPath)}

+

State: ${escapeHtml(JSON.stringify(step.state))}

+
+ `).join(""); + await reportPage.setContent(` + + + + + + +

gmoccapy XYZAB Function Evidence

+
+
Status: ${escapeHtml(data.status)}
+
Job ID: ${escapeHtml(data.jobId)}
+
Report ID: ${escapeHtml(data.reportId)}
+
Target: ${escapeHtml(data.targetUrl)}
+
Generated: ${escapeHtml(data.generatedAt)}
+
Screenshots: ${escapeHtml(data.screenshotsDir)}
+
+

Checks

+ + + ${rows} +
CheckStatusEvidence
+

Steps

+ ${steps} + + `, { waitUntil: "load" }); + await reportPage.pdf({ + path: pdfPath, + format: "A4", + printBackground: true, + margin: { top: "12mm", right: "10mm", bottom: "12mm", left: "10mm" }, + }); + await reportPage.close(); +} + +async function click(action) { + await page.evaluate((selector) => { + const button = document.querySelector(selector); + if (!button) throw new Error(`missing button ${selector}`); + button.click(); + }, `[data-action="${action}"]`); +} + +async function getState() { + return page.evaluate(() => JSON.parse(JSON.stringify(window.webRtcp5AxisSimulation.getState()))); +} + +async function waitForState(predicate, timeoutMs, label) { + const started = Date.now(); + let lastState = null; + while (Date.now() - started < timeoutMs) { + lastState = await getState(); + if (predicate(lastState)) return lastState; + await wait(50); + } + throw new Error(`timeout waiting for ${label}: ${JSON.stringify(summarizeState(lastState || {}))}`); +} + +function addChecks() { + const byName = Object.fromEntries(report.steps.map((step) => [step.name, step])); + const profile = byName["02-profile-selected"]; + const blockedPower = byName["03-run-blocked-power"]; + const blockedReference = byName["04-run-blocked-reference-evidence"]; + const controls = byName["05-controls-active"]; + const diagnostics = byName["06-hal-diagnostics"]; + const buttons = diagnostics?.dom?.buttons || {}; + + report.checks.push( + check("XYZAB profile selected", profile?.state?.machineProfile === "gmoccapy-xyzab" && profile?.state?.coordinates === "XYZAB", JSON.stringify(profile?.state)), + check("Reference profile blocks RTCP promotion", profile?.state?.rtcpState === "off" && profile?.state?.profileTcpCapable === false, JSON.stringify(profile?.state)), + check("RUN blocked before power", blockedPower?.state?.operatorMessage === "run blocked: machine must be on", blockedPower?.state?.operatorMessage), + check("RUN blocked by reference evidence", isReferenceRunBlockedReason(blockedReference?.state?.operatorMessage), blockedReference?.state?.operatorMessage), + check("Core icons rendered", ["estop", "power", "mode-manual", "mode-auto", "RUN", "STOP", "HOME", "toggle-flood", "toggle-mist"].every((action) => buttons[action]?.iconName), JSON.stringify(buttons)), + check("Spindle/coolant state updates", controls?.state?.spindle?.direction === "stop" && controls?.state?.coolant?.mist === true, JSON.stringify(controls?.state)), + check("NML command diagnostic", diagnostics?.dom?.gmoccapyNativeCommand?.includes("NML emcCommand"), diagnostics?.dom?.gmoccapyNativeCommand), + check("Web runtime diagnostic", diagnostics?.dom?.gmoccapyWebPath?.includes("store.dispatch"), diagnostics?.dom?.gmoccapyWebPath), + check("HAL postgui diagnostic", diagnostics?.dom?.gmoccapyHalPostgui?.includes("tool-change-loop"), diagnostics?.dom?.gmoccapyHalPostgui), + check("Screenshots are nonblank", report.steps.every((step) => step.pixelStats.nonBlackRatio > 0.1), report.steps.map((step) => `${step.name}:${step.pixelStats.nonBlackRatio}`).join(", ")), + ); +} + +function summarizeState(state = {}) { + return { + machineProfile: state.machineProfile, + coordinates: state.profile?.traj?.coordinates, + profileTcpCapable: state.profile?.tcpCapable, + profileRtcpProof: state.profile?.rtcpProof, + runState: state.runState, + rtcpState: state.rtcpState, + kinsType: state.kinsType, + machine: { + powerOn: state.machine?.powerOn, + taskState: state.machine?.taskState, + mode: state.machine?.mode, + allHomed: state.machine?.allHomed, + interpState: state.machine?.interpState, + }, + spindle: { + enabled: state.spindle?.enabled, + direction: state.spindle?.direction, + rpm: state.spindle?.rpm, + }, + coolant: { + flood: state.coolant?.flood, + mist: state.coolant?.mist, + }, + taskPolicy: { + canRunAuto: state.linuxCncTaskPolicy?.canRunAuto, + canRunAutoStrict: state.linuxCncTaskPolicy?.canRunAutoStrict, + iniLoaded: state.linuxCncTaskPolicy?.iniLoaded, + machineFileStaged: state.linuxCncTaskPolicy?.machineFileStaged, + taskHalRuntimeReady: state.linuxCncTaskPolicy?.taskHalRuntimeReady, + }, + operatorMessage: state.operatorMessage, + }; +} + +function createStaticServer(rootDir) { + return http.createServer(async (request, response) => { + try { + const requestPath = decodeURIComponent(new URL(request.url || "/", "http://127.0.0.1").pathname); + const relativePath = requestPath === "/" ? "/index.html" : requestPath; + const targetPath = path.resolve(rootDir, `.${relativePath}`); + if (!targetPath.startsWith(rootDir)) { + response.writeHead(403); + response.end("forbidden"); + return; + } + let filePath = targetPath; + let stat = await fs.stat(filePath).catch(() => null); + if (stat?.isDirectory()) { + filePath = path.join(filePath, "index.html"); + stat = await fs.stat(filePath).catch(() => null); + } + if (!stat?.isFile()) { + response.writeHead(404); + response.end("not found"); + return; + } + const body = await fs.readFile(filePath); + response.writeHead(200, { + "Content-Type": contentTypeFor(filePath), + "Content-Length": String(body.byteLength), + "Cache-Control": "no-store", + }); + response.end(body); + } catch (error) { + response.writeHead(500); + response.end(error instanceof Error ? error.message : String(error)); + } + }); +} + +function contentTypeFor(filePath) { + const ext = path.extname(filePath).toLowerCase(); + return { + ".css": "text/css; charset=utf-8", + ".html": "text/html; charset=utf-8", + ".js": "text/javascript; charset=utf-8", + ".json": "application/json; charset=utf-8", + ".mjs": "text/javascript; charset=utf-8", + ".svg": "image/svg+xml", + ".png": "image/png", + ".wasm": "application/wasm", + ".xml": "application/xml; charset=utf-8", + }[ext] || "application/octet-stream"; +} + +async function analyzePng(filePath) { + const png = PNG.sync.read(await fs.readFile(filePath)); + let luminanceSum = 0; + let nonBlack = 0; + for (let index = 0; index < png.data.length; index += 4) { + const luminance = png.data[index] * 0.2126 + png.data[index + 1] * 0.7152 + png.data[index + 2] * 0.0722; + luminanceSum += luminance; + if (luminance > 8) nonBlack += 1; + } + const total = png.width * png.height; + return { + width: png.width, + height: png.height, + averageLuminance: Number((luminanceSum / total).toFixed(2)), + nonBlackRatio: Number((nonBlack / total).toFixed(4)), + }; +} + +function check(name, pass, detail) { + return { name, pass: Boolean(pass), detail: String(detail ?? "-") }; +} + +function isReferenceRunBlockedReason(message) { + return [ + "run blocked: LinuxCNC INI not loaded", + "run blocked: LinuxCNC machine files not staged", + "run blocked: no machine-file G-code opened for task/HAL session", + "run blocked: task/HAL runtime not ready", + ].includes(String(message || "")); +} + +function escapeHtml(value) { + return String(value ?? "") + .replace(/&/g, "&") + .replace(//g, ">") + .replace(/"/g, """) + .replace(/'/g, "'"); +} + +function wait(ms) { + return new Promise((resolve) => setTimeout(resolve, ms)); +} diff --git a/qa/web-rtcp-5axis-site-test/output/gmoccapy-xyzab-function-report.json b/qa/web-rtcp-5axis-site-test/output/gmoccapy-xyzab-function-report.json new file mode 100644 index 0000000..acda5a1 --- /dev/null +++ b/qa/web-rtcp-5axis-site-test/output/gmoccapy-xyzab-function-report.json @@ -0,0 +1,1238 @@ +{ + "jobId": "xyzab-20260626214346-f4b4aa36", + "reportId": "report-xyzab-20260626214346-f4b4aa36", + "evidenceScope": "gmoccapy-xyzab-function", + "generatedAt": "2026-06-26T21:43:46.310Z", + "targetUrl": "http://127.0.0.1:36983/web-rtcp-5axis-sim-plan/app/index.html", + "chromePath": "/usr/bin/google-chrome", + "screenshotsDir": "/home/meswork/cnc_wams/qa/web-rtcp-5axis-site-test/output/gmoccapy-xyzab", + "steps": [ + { + "name": "01-loaded", + "title": "Initial gmoccapy shell", + "description": "Default shell loaded with icon registry and diagnostics.", + "screenshotPath": "/home/meswork/cnc_wams/qa/web-rtcp-5axis-site-test/output/gmoccapy-xyzab/01-loaded.png", + "pixelStats": { + "width": 1500, + "height": 1050, + "averageLuminance": 130.04, + "nonBlackRatio": 0.7823 + }, + "state": { + "machineProfile": "xyzac-trt", + "coordinates": "XYZAC", + "runState": "idle", + "rtcpState": "on", + "kinsType": "tcp-xyzac", + "machine": { + "powerOn": false, + "taskState": "estop-reset", + "mode": "manual", + "allHomed": false, + "interpState": "idle" + }, + "spindle": { + "enabled": true, + "direction": "forward", + "rpm": 1600 + }, + "coolant": { + "flood": true, + "mist": false + }, + "taskPolicy": { + "canRunAuto": false, + "canRunAutoStrict": false, + "iniLoaded": true, + "machineFileStaged": true, + "taskHalRuntimeReady": true + }, + "operatorMessage": "LinuxCNC task/HAL session ready /work/sim/axis/vismach/5axis/table-rotary-tilting/xyzac-trt/demos/boat-xyzac.ngc" + }, + "dom": { + "buttons": { + "estop": { + "exists": true, + "iconName": "main_switch_off", + "iconVariant": "inactive", + "buttonId": "tbtn_estop", + "active": "false", + "commandReady": null, + "title": "Estop the machine / F1" + }, + "power": { + "exists": true, + "iconName": "power_off", + "iconVariant": "inactive", + "buttonId": "tbtn_on", + "active": "false", + "commandReady": null, + "title": "Turn the machine on/off / F2" + }, + "mode-manual": { + "exists": true, + "iconName": "mode_manual_active", + "iconVariant": "active", + "buttonId": "rbt_manual", + "active": "true", + "commandReady": null, + "title": "Enter manual mode" + }, + "mode-auto": { + "exists": true, + "iconName": "mode_auto_inactive", + "iconVariant": "inactive", + "buttonId": "rbt_auto", + "active": "false", + "commandReady": null, + "title": "Enter auto mode" + }, + "mode-mdi": { + "exists": true, + "iconName": "mode_mdi_inactive", + "iconVariant": "inactive", + "buttonId": "rbt_mdi", + "active": "false", + "commandReady": null, + "title": "Enter MDI mode" + }, + "RUN": { + "exists": true, + "iconName": "play", + "iconVariant": "inactive", + "buttonId": "btn_run", + "active": "false", + "commandReady": "false", + "title": "run blocked: machine must be on" + }, + "STOP": { + "exists": true, + "iconName": "stop", + "iconVariant": "inactive", + "buttonId": "btn_stop", + "active": "false", + "commandReady": "true", + "title": "Stop" + }, + "PAUSE": { + "exists": true, + "iconName": "pause", + "iconVariant": "inactive", + "buttonId": "tbtn_pause", + "active": "false", + "commandReady": "false", + "title": "pause blocked: machine must be on" + }, + "HOME": { + "exists": true, + "iconName": "ref_all", + "iconVariant": "inactive", + "buttonId": "btn_homing", + "active": "false", + "commandReady": "false", + "title": "home blocked: machine must be on" + }, + "spindle-forward": { + "exists": true, + "iconName": "spindle_right_on", + "iconVariant": "active", + "buttonId": "rbt_forward", + "active": "true", + "commandReady": "false", + "title": "spindle blocked: machine must be on" + }, + "spindle-stop": { + "exists": true, + "iconName": "spindle_stop", + "iconVariant": "inactive", + "buttonId": "rbt_stop", + "active": "false", + "commandReady": "false", + "title": "spindle blocked: machine must be on" + }, + "spindle-reverse": { + "exists": true, + "iconName": "spindle_left", + "iconVariant": "inactive", + "buttonId": "rbt_reverse", + "active": "false", + "commandReady": "false", + "title": "spindle blocked: machine must be on" + }, + "toggle-flood": { + "exists": true, + "iconName": "coolant_flood_active", + "iconVariant": "active", + "buttonId": "tbtn_flood", + "active": "true", + "commandReady": "false", + "title": "coolant blocked: machine must be on" + }, + "toggle-mist": { + "exists": true, + "iconName": "coolant_mist_inactive", + "iconVariant": "inactive", + "buttonId": "tbtn_mist", + "active": "false", + "commandReady": "false", + "title": "coolant blocked: machine must be on" + }, + "view-x": { + "exists": true, + "iconName": "tool_axis_x", + "iconVariant": "inactive", + "buttonId": "rbt_view_x", + "active": "false", + "commandReady": null, + "title": "View X" + } + }, + "profileSummary": "XYZAC / 5 joints / 10 tools", + "iniKins": "xyzac-trt-kins / XYZAC", + "taskGates": "jog blocked / home blocked / auto blocked / mdi blocked / pause blocked / resume blocked", + "gmoccapyCommBoundary": "native_gmoccapy_nml_hal_reference_web_store_runtime_mapping", + "gmoccapyNativeCommand": "NML command: gmoccapy -> linuxcnc.command() -> NML emcCommand -> milltask", + "gmoccapyWebPath": "button -> store.dispatch -> linuxcnc-task-policy -> runtime/status snapshot -> UI/Three.js", + "gmoccapyPostgui": "halcomp.ready before POSTGUI_HALFILE", + "gmoccapyHalBoundary": "gmoccapy_hal_pin_postgui_reference_web_diagnostic_only", + "gmoccapyHalPostgui": "spindle-abs / spindle-at-speed / tooloffset-x / tooloffset-z / tool-change-loop", + "operatorMessage": "LinuxCNC task/HAL session ready /work/sim/axis/vismach/5axis/table-rotary-tilting/xyzac-trt/demos/boat-xyzac.ngc" + } + }, + { + "name": "02-profile-selected", + "title": "gmoccapy XYZAB selected", + "description": "Reference profile shows XYZAB/trivkins and disables TCP promotion.", + "screenshotPath": "/home/meswork/cnc_wams/qa/web-rtcp-5axis-site-test/output/gmoccapy-xyzab/02-profile-selected.png", + "pixelStats": { + "width": 1500, + "height": 1050, + "averageLuminance": 130.01, + "nonBlackRatio": 0.7815 + }, + "state": { + "machineProfile": "gmoccapy-xyzab", + "coordinates": "XYZAB", + "profileTcpCapable": false, + "profileRtcpProof": false, + "runState": "idle", + "rtcpState": "off", + "kinsType": "identity", + "machine": { + "powerOn": false, + "taskState": "estop-reset", + "mode": "manual", + "allHomed": false, + "interpState": "idle" + }, + "spindle": { + "enabled": true, + "direction": "forward", + "rpm": 1600 + }, + "coolant": { + "flood": true, + "mist": false + }, + "taskPolicy": { + "canRunAuto": false, + "canRunAutoStrict": false, + "iniLoaded": false, + "machineFileStaged": false, + "taskHalRuntimeReady": true + }, + "operatorMessage": "frame source fixture-ui-only" + }, + "dom": { + "buttons": { + "estop": { + "exists": true, + "iconName": "main_switch_off", + "iconVariant": "inactive", + "buttonId": "tbtn_estop", + "active": "false", + "commandReady": null, + "title": "Estop the machine / F1" + }, + "power": { + "exists": true, + "iconName": "power_off", + "iconVariant": "inactive", + "buttonId": "tbtn_on", + "active": "false", + "commandReady": null, + "title": "Turn the machine on/off / F2" + }, + "mode-manual": { + "exists": true, + "iconName": "mode_manual_active", + "iconVariant": "active", + "buttonId": "rbt_manual", + "active": "true", + "commandReady": null, + "title": "Enter manual mode" + }, + "mode-auto": { + "exists": true, + "iconName": "mode_auto_inactive", + "iconVariant": "inactive", + "buttonId": "rbt_auto", + "active": "false", + "commandReady": null, + "title": "Enter auto mode" + }, + "mode-mdi": { + "exists": true, + "iconName": "mode_mdi_inactive", + "iconVariant": "inactive", + "buttonId": "rbt_mdi", + "active": "false", + "commandReady": null, + "title": "Enter MDI mode" + }, + "RUN": { + "exists": true, + "iconName": "play", + "iconVariant": "inactive", + "buttonId": "btn_run", + "active": "false", + "commandReady": "false", + "title": "run blocked: machine must be on" + }, + "STOP": { + "exists": true, + "iconName": "stop", + "iconVariant": "inactive", + "buttonId": "btn_stop", + "active": "false", + "commandReady": "true", + "title": "Stop" + }, + "PAUSE": { + "exists": true, + "iconName": "pause", + "iconVariant": "inactive", + "buttonId": "tbtn_pause", + "active": "false", + "commandReady": "false", + "title": "pause blocked: machine must be on" + }, + "HOME": { + "exists": true, + "iconName": "ref_all", + "iconVariant": "inactive", + "buttonId": "btn_homing", + "active": "false", + "commandReady": "false", + "title": "home blocked: machine must be on" + }, + "spindle-forward": { + "exists": true, + "iconName": "spindle_right_on", + "iconVariant": "active", + "buttonId": "rbt_forward", + "active": "true", + "commandReady": "false", + "title": "spindle blocked: machine must be on" + }, + "spindle-stop": { + "exists": true, + "iconName": "spindle_stop", + "iconVariant": "inactive", + "buttonId": "rbt_stop", + "active": "false", + "commandReady": "false", + "title": "spindle blocked: machine must be on" + }, + "spindle-reverse": { + "exists": true, + "iconName": "spindle_left", + "iconVariant": "inactive", + "buttonId": "rbt_reverse", + "active": "false", + "commandReady": "false", + "title": "spindle blocked: machine must be on" + }, + "toggle-flood": { + "exists": true, + "iconName": "coolant_flood_active", + "iconVariant": "active", + "buttonId": "tbtn_flood", + "active": "true", + "commandReady": "false", + "title": "coolant blocked: machine must be on" + }, + "toggle-mist": { + "exists": true, + "iconName": "coolant_mist_inactive", + "iconVariant": "inactive", + "buttonId": "tbtn_mist", + "active": "false", + "commandReady": "false", + "title": "coolant blocked: machine must be on" + }, + "view-x": { + "exists": true, + "iconName": "tool_axis_x", + "iconVariant": "inactive", + "buttonId": "rbt_view_x", + "active": "false", + "commandReady": null, + "title": "View X" + } + }, + "profileSummary": "XYZAB / 5 joints / 17 tools", + "iniKins": "- / -", + "taskGates": "jog blocked / home blocked / auto blocked / mdi blocked / pause blocked / resume blocked", + "gmoccapyCommBoundary": "native_gmoccapy_nml_hal_reference_web_store_runtime_mapping", + "gmoccapyNativeCommand": "NML command: gmoccapy -> linuxcnc.command() -> NML emcCommand -> milltask", + "gmoccapyWebPath": "button -> store.dispatch -> linuxcnc-task-policy -> runtime/status snapshot -> UI/Three.js", + "gmoccapyPostgui": "halcomp.ready before POSTGUI_HALFILE", + "gmoccapyHalBoundary": "gmoccapy_hal_pin_postgui_reference_web_diagnostic_only", + "gmoccapyHalPostgui": "spindle-abs / spindle-at-speed / tooloffset-x / tooloffset-z / tool-change-loop", + "operatorMessage": "frame source fixture-ui-only" + } + }, + { + "name": "03-run-blocked-power", + "title": "RUN blocked before power", + "description": "RUN remains clickable but reports LinuxCNC/gmoccapy gate reason.", + "screenshotPath": "/home/meswork/cnc_wams/qa/web-rtcp-5axis-site-test/output/gmoccapy-xyzab/03-run-blocked-power.png", + "pixelStats": { + "width": 1500, + "height": 1050, + "averageLuminance": 130.01, + "nonBlackRatio": 0.7815 + }, + "state": { + "machineProfile": "gmoccapy-xyzab", + "coordinates": "XYZAB", + "profileTcpCapable": false, + "profileRtcpProof": false, + "runState": "idle", + "rtcpState": "off", + "kinsType": "identity", + "machine": { + "powerOn": false, + "taskState": "estop-reset", + "mode": "manual", + "allHomed": false, + "interpState": "idle" + }, + "spindle": { + "enabled": true, + "direction": "forward", + "rpm": 1600 + }, + "coolant": { + "flood": true, + "mist": false + }, + "taskPolicy": { + "canRunAuto": false, + "canRunAutoStrict": false, + "iniLoaded": false, + "machineFileStaged": false, + "taskHalRuntimeReady": true + }, + "operatorMessage": "run blocked: machine must be on" + }, + "dom": { + "buttons": { + "estop": { + "exists": true, + "iconName": "main_switch_off", + "iconVariant": "inactive", + "buttonId": "tbtn_estop", + "active": "false", + "commandReady": null, + "title": "Estop the machine / F1" + }, + "power": { + "exists": true, + "iconName": "power_off", + "iconVariant": "inactive", + "buttonId": "tbtn_on", + "active": "false", + "commandReady": null, + "title": "Turn the machine on/off / F2" + }, + "mode-manual": { + "exists": true, + "iconName": "mode_manual_active", + "iconVariant": "active", + "buttonId": "rbt_manual", + "active": "true", + "commandReady": null, + "title": "Enter manual mode" + }, + "mode-auto": { + "exists": true, + "iconName": "mode_auto_inactive", + "iconVariant": "inactive", + "buttonId": "rbt_auto", + "active": "false", + "commandReady": null, + "title": "Enter auto mode" + }, + "mode-mdi": { + "exists": true, + "iconName": "mode_mdi_inactive", + "iconVariant": "inactive", + "buttonId": "rbt_mdi", + "active": "false", + "commandReady": null, + "title": "Enter MDI mode" + }, + "RUN": { + "exists": true, + "iconName": "play", + "iconVariant": "inactive", + "buttonId": "btn_run", + "active": "false", + "commandReady": "false", + "title": "run blocked: machine must be on" + }, + "STOP": { + "exists": true, + "iconName": "stop", + "iconVariant": "inactive", + "buttonId": "btn_stop", + "active": "false", + "commandReady": "true", + "title": "Stop" + }, + "PAUSE": { + "exists": true, + "iconName": "pause", + "iconVariant": "inactive", + "buttonId": "tbtn_pause", + "active": "false", + "commandReady": "false", + "title": "pause blocked: machine must be on" + }, + "HOME": { + "exists": true, + "iconName": "ref_all", + "iconVariant": "inactive", + "buttonId": "btn_homing", + "active": "false", + "commandReady": "false", + "title": "home blocked: machine must be on" + }, + "spindle-forward": { + "exists": true, + "iconName": "spindle_right_on", + "iconVariant": "active", + "buttonId": "rbt_forward", + "active": "true", + "commandReady": "false", + "title": "spindle blocked: machine must be on" + }, + "spindle-stop": { + "exists": true, + "iconName": "spindle_stop", + "iconVariant": "inactive", + "buttonId": "rbt_stop", + "active": "false", + "commandReady": "false", + "title": "spindle blocked: machine must be on" + }, + "spindle-reverse": { + "exists": true, + "iconName": "spindle_left", + "iconVariant": "inactive", + "buttonId": "rbt_reverse", + "active": "false", + "commandReady": "false", + "title": "spindle blocked: machine must be on" + }, + "toggle-flood": { + "exists": true, + "iconName": "coolant_flood_active", + "iconVariant": "active", + "buttonId": "tbtn_flood", + "active": "true", + "commandReady": "false", + "title": "coolant blocked: machine must be on" + }, + "toggle-mist": { + "exists": true, + "iconName": "coolant_mist_inactive", + "iconVariant": "inactive", + "buttonId": "tbtn_mist", + "active": "false", + "commandReady": "false", + "title": "coolant blocked: machine must be on" + }, + "view-x": { + "exists": true, + "iconName": "tool_axis_x", + "iconVariant": "inactive", + "buttonId": "rbt_view_x", + "active": "false", + "commandReady": null, + "title": "View X" + } + }, + "profileSummary": "XYZAB / 5 joints / 17 tools", + "iniKins": "- / -", + "taskGates": "jog blocked / home blocked / auto blocked / mdi blocked / pause blocked / resume blocked", + "gmoccapyCommBoundary": "native_gmoccapy_nml_hal_reference_web_store_runtime_mapping", + "gmoccapyNativeCommand": "NML command: gmoccapy -> linuxcnc.command() -> NML emcCommand -> milltask", + "gmoccapyWebPath": "button -> store.dispatch -> linuxcnc-task-policy -> runtime/status snapshot -> UI/Three.js", + "gmoccapyPostgui": "halcomp.ready before POSTGUI_HALFILE", + "gmoccapyHalBoundary": "gmoccapy_hal_pin_postgui_reference_web_diagnostic_only", + "gmoccapyHalPostgui": "spindle-abs / spindle-at-speed / tooloffset-x / tooloffset-z / tool-change-loop", + "operatorMessage": "run blocked: machine must be on" + } + }, + { + "name": "04-run-blocked-reference-evidence", + "title": "RUN blocked by reference evidence", + "description": "XYZAB passes power/home/auto gates but remains blocked without complete native INI/machine-file/runtime evidence.", + "screenshotPath": "/home/meswork/cnc_wams/qa/web-rtcp-5axis-site-test/output/gmoccapy-xyzab/04-run-blocked-reference-evidence.png", + "pixelStats": { + "width": 1500, + "height": 1050, + "averageLuminance": 130.05, + "nonBlackRatio": 0.7815 + }, + "state": { + "machineProfile": "gmoccapy-xyzab", + "coordinates": "XYZAB", + "profileTcpCapable": false, + "profileRtcpProof": false, + "runState": "idle", + "rtcpState": "off", + "kinsType": "identity", + "machine": { + "powerOn": true, + "taskState": "on", + "mode": "auto", + "allHomed": true, + "interpState": "idle" + }, + "spindle": { + "enabled": true, + "direction": "forward", + "rpm": 1600 + }, + "coolant": { + "flood": true, + "mist": false + }, + "taskPolicy": { + "canRunAuto": true, + "canRunAutoStrict": false, + "iniLoaded": false, + "machineFileStaged": false, + "taskHalRuntimeReady": true + }, + "operatorMessage": "run blocked: LinuxCNC INI not loaded" + }, + "dom": { + "buttons": { + "estop": { + "exists": true, + "iconName": "main_switch_off", + "iconVariant": "inactive", + "buttonId": "tbtn_estop", + "active": "false", + "commandReady": null, + "title": "Estop the machine / F1" + }, + "power": { + "exists": true, + "iconName": "power_on", + "iconVariant": "active", + "buttonId": "tbtn_on", + "active": "true", + "commandReady": null, + "title": "Turn the machine on/off / F2" + }, + "mode-manual": { + "exists": true, + "iconName": "mode_manual_inactive", + "iconVariant": "inactive", + "buttonId": "rbt_manual", + "active": "false", + "commandReady": null, + "title": "Enter manual mode" + }, + "mode-auto": { + "exists": true, + "iconName": "mode_auto_active", + "iconVariant": "active", + "buttonId": "rbt_auto", + "active": "true", + "commandReady": null, + "title": "Enter auto mode" + }, + "mode-mdi": { + "exists": true, + "iconName": "mode_mdi_inactive", + "iconVariant": "inactive", + "buttonId": "rbt_mdi", + "active": "false", + "commandReady": null, + "title": "Enter MDI mode" + }, + "RUN": { + "exists": true, + "iconName": "play", + "iconVariant": "inactive", + "buttonId": "btn_run", + "active": "false", + "commandReady": "false", + "title": "run blocked: LinuxCNC INI not loaded" + }, + "STOP": { + "exists": true, + "iconName": "stop", + "iconVariant": "inactive", + "buttonId": "btn_stop", + "active": "false", + "commandReady": "true", + "title": "Stop" + }, + "PAUSE": { + "exists": true, + "iconName": "pause", + "iconVariant": "inactive", + "buttonId": "tbtn_pause", + "active": "false", + "commandReady": "true", + "title": "Pause" + }, + "HOME": { + "exists": true, + "iconName": "ref_all", + "iconVariant": "active", + "buttonId": "btn_homing", + "active": "true", + "commandReady": "false", + "title": "home blocked: switch to manual mode first" + }, + "spindle-forward": { + "exists": true, + "iconName": "spindle_right_on", + "iconVariant": "active", + "buttonId": "rbt_forward", + "active": "true", + "commandReady": "true", + "title": "Spindle forward" + }, + "spindle-stop": { + "exists": true, + "iconName": "spindle_stop", + "iconVariant": "inactive", + "buttonId": "rbt_stop", + "active": "false", + "commandReady": "true", + "title": "Spindle stop" + }, + "spindle-reverse": { + "exists": true, + "iconName": "spindle_left", + "iconVariant": "inactive", + "buttonId": "rbt_reverse", + "active": "false", + "commandReady": "true", + "title": "Spindle reverse" + }, + "toggle-flood": { + "exists": true, + "iconName": "coolant_flood_active", + "iconVariant": "active", + "buttonId": "tbtn_flood", + "active": "true", + "commandReady": "true", + "title": "Flood coolant" + }, + "toggle-mist": { + "exists": true, + "iconName": "coolant_mist_inactive", + "iconVariant": "inactive", + "buttonId": "tbtn_mist", + "active": "false", + "commandReady": "true", + "title": "Mist coolant" + }, + "view-x": { + "exists": true, + "iconName": "tool_axis_x", + "iconVariant": "inactive", + "buttonId": "rbt_view_x", + "active": "false", + "commandReady": null, + "title": "View X" + } + }, + "profileSummary": "XYZAB / 5 joints / 17 tools", + "iniKins": "- / -", + "taskGates": "jog blocked / home blocked / auto / mdi blocked / pause / resume blocked", + "gmoccapyCommBoundary": "native_gmoccapy_nml_hal_reference_web_store_runtime_mapping", + "gmoccapyNativeCommand": "NML command: gmoccapy -> linuxcnc.command() -> NML emcCommand -> milltask", + "gmoccapyWebPath": "button -> store.dispatch -> linuxcnc-task-policy -> runtime/status snapshot -> UI/Three.js", + "gmoccapyPostgui": "halcomp.ready before POSTGUI_HALFILE", + "gmoccapyHalBoundary": "gmoccapy_hal_pin_postgui_reference_web_diagnostic_only", + "gmoccapyHalPostgui": "spindle-abs / spindle-at-speed / tooloffset-x / tooloffset-z / tool-change-loop", + "operatorMessage": "run blocked: LinuxCNC INI not loaded" + } + }, + { + "name": "05-controls-active", + "title": "Spindle and coolant controls", + "description": "Spindle/coolant icons update through task policy guarded store actions.", + "screenshotPath": "/home/meswork/cnc_wams/qa/web-rtcp-5axis-site-test/output/gmoccapy-xyzab/05-controls-active.png", + "pixelStats": { + "width": 1500, + "height": 1050, + "averageLuminance": 130.04, + "nonBlackRatio": 0.7815 + }, + "state": { + "machineProfile": "gmoccapy-xyzab", + "coordinates": "XYZAB", + "profileTcpCapable": false, + "profileRtcpProof": false, + "runState": "idle", + "rtcpState": "off", + "kinsType": "identity", + "machine": { + "powerOn": true, + "taskState": "on", + "mode": "manual", + "allHomed": true, + "interpState": "idle" + }, + "spindle": { + "enabled": false, + "direction": "stop", + "rpm": 1600 + }, + "coolant": { + "flood": false, + "mist": true + }, + "taskPolicy": { + "canRunAuto": false, + "canRunAutoStrict": false, + "iniLoaded": false, + "machineFileStaged": false, + "taskHalRuntimeReady": true + }, + "operatorMessage": "mist coolant toggled" + }, + "dom": { + "buttons": { + "estop": { + "exists": true, + "iconName": "main_switch_off", + "iconVariant": "inactive", + "buttonId": "tbtn_estop", + "active": "false", + "commandReady": null, + "title": "Estop the machine / F1" + }, + "power": { + "exists": true, + "iconName": "power_on", + "iconVariant": "active", + "buttonId": "tbtn_on", + "active": "true", + "commandReady": null, + "title": "Turn the machine on/off / F2" + }, + "mode-manual": { + "exists": true, + "iconName": "mode_manual_active", + "iconVariant": "active", + "buttonId": "rbt_manual", + "active": "true", + "commandReady": null, + "title": "Enter manual mode" + }, + "mode-auto": { + "exists": true, + "iconName": "mode_auto_inactive", + "iconVariant": "inactive", + "buttonId": "rbt_auto", + "active": "false", + "commandReady": null, + "title": "Enter auto mode" + }, + "mode-mdi": { + "exists": true, + "iconName": "mode_mdi_inactive", + "iconVariant": "inactive", + "buttonId": "rbt_mdi", + "active": "false", + "commandReady": null, + "title": "Enter MDI mode" + }, + "RUN": { + "exists": true, + "iconName": "play", + "iconVariant": "inactive", + "buttonId": "btn_run", + "active": "false", + "commandReady": "false", + "title": "run blocked: switch to auto mode first" + }, + "STOP": { + "exists": true, + "iconName": "stop", + "iconVariant": "inactive", + "buttonId": "btn_stop", + "active": "false", + "commandReady": "true", + "title": "Stop" + }, + "PAUSE": { + "exists": true, + "iconName": "pause", + "iconVariant": "inactive", + "buttonId": "tbtn_pause", + "active": "false", + "commandReady": "false", + "title": "pause blocked: task mode must be auto or MDI" + }, + "HOME": { + "exists": true, + "iconName": "ref_all", + "iconVariant": "active", + "buttonId": "btn_homing", + "active": "true", + "commandReady": "true", + "title": "Home" + }, + "spindle-forward": { + "exists": true, + "iconName": "spindle_right", + "iconVariant": "inactive", + "buttonId": "rbt_forward", + "active": "false", + "commandReady": "true", + "title": "Spindle forward" + }, + "spindle-stop": { + "exists": true, + "iconName": "spindle_stop_on", + "iconVariant": "active", + "buttonId": "rbt_stop", + "active": "true", + "commandReady": "true", + "title": "Spindle stop" + }, + "spindle-reverse": { + "exists": true, + "iconName": "spindle_left", + "iconVariant": "inactive", + "buttonId": "rbt_reverse", + "active": "false", + "commandReady": "true", + "title": "Spindle reverse" + }, + "toggle-flood": { + "exists": true, + "iconName": "coolant_flood_inactive", + "iconVariant": "inactive", + "buttonId": "tbtn_flood", + "active": "false", + "commandReady": "true", + "title": "Flood coolant" + }, + "toggle-mist": { + "exists": true, + "iconName": "coolant_mist_active", + "iconVariant": "active", + "buttonId": "tbtn_mist", + "active": "true", + "commandReady": "true", + "title": "Mist coolant" + }, + "view-x": { + "exists": true, + "iconName": "tool_axis_x", + "iconVariant": "inactive", + "buttonId": "rbt_view_x", + "active": "false", + "commandReady": null, + "title": "View X" + } + }, + "profileSummary": "XYZAB / 5 joints / 17 tools", + "iniKins": "- / -", + "taskGates": "jog / home / auto blocked / mdi blocked / pause blocked / resume blocked", + "gmoccapyCommBoundary": "native_gmoccapy_nml_hal_reference_web_store_runtime_mapping", + "gmoccapyNativeCommand": "NML command: gmoccapy -> linuxcnc.command() -> NML emcCommand -> milltask", + "gmoccapyWebPath": "button -> store.dispatch -> linuxcnc-task-policy -> runtime/status snapshot -> UI/Three.js", + "gmoccapyPostgui": "halcomp.ready before POSTGUI_HALFILE", + "gmoccapyHalBoundary": "gmoccapy_hal_pin_postgui_reference_web_diagnostic_only", + "gmoccapyHalPostgui": "spindle-abs / spindle-at-speed / tooloffset-x / tooloffset-z / tool-change-loop", + "operatorMessage": "mist coolant toggled" + } + }, + { + "name": "06-hal-diagnostics", + "title": "HAL and communication diagnostics", + "description": "Info panel exposes native NML/HAL/postgui references and Web runtime boundary.", + "screenshotPath": "/home/meswork/cnc_wams/qa/web-rtcp-5axis-site-test/output/gmoccapy-xyzab/06-hal-diagnostics.png", + "pixelStats": { + "width": 1500, + "height": 1050, + "averageLuminance": 130.04, + "nonBlackRatio": 0.7815 + }, + "state": { + "machineProfile": "gmoccapy-xyzab", + "coordinates": "XYZAB", + "profileTcpCapable": false, + "profileRtcpProof": false, + "runState": "idle", + "rtcpState": "off", + "kinsType": "identity", + "machine": { + "powerOn": true, + "taskState": "on", + "mode": "manual", + "allHomed": true, + "interpState": "idle" + }, + "spindle": { + "enabled": false, + "direction": "stop", + "rpm": 1600 + }, + "coolant": { + "flood": false, + "mist": true + }, + "taskPolicy": { + "canRunAuto": false, + "canRunAutoStrict": false, + "iniLoaded": false, + "machineFileStaged": false, + "taskHalRuntimeReady": true + }, + "operatorMessage": "mist coolant toggled" + }, + "dom": { + "buttons": { + "estop": { + "exists": true, + "iconName": "main_switch_off", + "iconVariant": "inactive", + "buttonId": "tbtn_estop", + "active": "false", + "commandReady": null, + "title": "Estop the machine / F1" + }, + "power": { + "exists": true, + "iconName": "power_on", + "iconVariant": "active", + "buttonId": "tbtn_on", + "active": "true", + "commandReady": null, + "title": "Turn the machine on/off / F2" + }, + "mode-manual": { + "exists": true, + "iconName": "mode_manual_active", + "iconVariant": "active", + "buttonId": "rbt_manual", + "active": "true", + "commandReady": null, + "title": "Enter manual mode" + }, + "mode-auto": { + "exists": true, + "iconName": "mode_auto_inactive", + "iconVariant": "inactive", + "buttonId": "rbt_auto", + "active": "false", + "commandReady": null, + "title": "Enter auto mode" + }, + "mode-mdi": { + "exists": true, + "iconName": "mode_mdi_inactive", + "iconVariant": "inactive", + "buttonId": "rbt_mdi", + "active": "false", + "commandReady": null, + "title": "Enter MDI mode" + }, + "RUN": { + "exists": true, + "iconName": "play", + "iconVariant": "inactive", + "buttonId": "btn_run", + "active": "false", + "commandReady": "false", + "title": "run blocked: switch to auto mode first" + }, + "STOP": { + "exists": true, + "iconName": "stop", + "iconVariant": "inactive", + "buttonId": "btn_stop", + "active": "false", + "commandReady": "true", + "title": "Stop" + }, + "PAUSE": { + "exists": true, + "iconName": "pause", + "iconVariant": "inactive", + "buttonId": "tbtn_pause", + "active": "false", + "commandReady": "false", + "title": "pause blocked: task mode must be auto or MDI" + }, + "HOME": { + "exists": true, + "iconName": "ref_all", + "iconVariant": "active", + "buttonId": "btn_homing", + "active": "true", + "commandReady": "true", + "title": "Home" + }, + "spindle-forward": { + "exists": true, + "iconName": "spindle_right", + "iconVariant": "inactive", + "buttonId": "rbt_forward", + "active": "false", + "commandReady": "true", + "title": "Spindle forward" + }, + "spindle-stop": { + "exists": true, + "iconName": "spindle_stop_on", + "iconVariant": "active", + "buttonId": "rbt_stop", + "active": "true", + "commandReady": "true", + "title": "Spindle stop" + }, + "spindle-reverse": { + "exists": true, + "iconName": "spindle_left", + "iconVariant": "inactive", + "buttonId": "rbt_reverse", + "active": "false", + "commandReady": "true", + "title": "Spindle reverse" + }, + "toggle-flood": { + "exists": true, + "iconName": "coolant_flood_inactive", + "iconVariant": "inactive", + "buttonId": "tbtn_flood", + "active": "false", + "commandReady": "true", + "title": "Flood coolant" + }, + "toggle-mist": { + "exists": true, + "iconName": "coolant_mist_active", + "iconVariant": "active", + "buttonId": "tbtn_mist", + "active": "true", + "commandReady": "true", + "title": "Mist coolant" + }, + "view-x": { + "exists": true, + "iconName": "tool_axis_x", + "iconVariant": "inactive", + "buttonId": "rbt_view_x", + "active": "false", + "commandReady": null, + "title": "View X" + } + }, + "profileSummary": "XYZAB / 5 joints / 17 tools", + "iniKins": "- / -", + "taskGates": "jog / home / auto blocked / mdi blocked / pause blocked / resume blocked", + "gmoccapyCommBoundary": "native_gmoccapy_nml_hal_reference_web_store_runtime_mapping", + "gmoccapyNativeCommand": "NML command: gmoccapy -> linuxcnc.command() -> NML emcCommand -> milltask", + "gmoccapyWebPath": "button -> store.dispatch -> linuxcnc-task-policy -> runtime/status snapshot -> UI/Three.js", + "gmoccapyPostgui": "halcomp.ready before POSTGUI_HALFILE", + "gmoccapyHalBoundary": "gmoccapy_hal_pin_postgui_reference_web_diagnostic_only", + "gmoccapyHalPostgui": "spindle-abs / spindle-at-speed / tooloffset-x / tooloffset-z / tool-change-loop", + "operatorMessage": "mist coolant toggled" + } + } + ], + "checks": [ + { + "name": "XYZAB profile selected", + "pass": true, + "detail": "{\"machineProfile\":\"gmoccapy-xyzab\",\"coordinates\":\"XYZAB\",\"profileTcpCapable\":false,\"profileRtcpProof\":false,\"runState\":\"idle\",\"rtcpState\":\"off\",\"kinsType\":\"identity\",\"machine\":{\"powerOn\":false,\"taskState\":\"estop-reset\",\"mode\":\"manual\",\"allHomed\":false,\"interpState\":\"idle\"},\"spindle\":{\"enabled\":true,\"direction\":\"forward\",\"rpm\":1600},\"coolant\":{\"flood\":true,\"mist\":false},\"taskPolicy\":{\"canRunAuto\":false,\"canRunAutoStrict\":false,\"iniLoaded\":false,\"machineFileStaged\":false,\"taskHalRuntimeReady\":true},\"operatorMessage\":\"frame source fixture-ui-only\"}" + }, + { + "name": "Reference profile blocks RTCP promotion", + "pass": true, + "detail": "{\"machineProfile\":\"gmoccapy-xyzab\",\"coordinates\":\"XYZAB\",\"profileTcpCapable\":false,\"profileRtcpProof\":false,\"runState\":\"idle\",\"rtcpState\":\"off\",\"kinsType\":\"identity\",\"machine\":{\"powerOn\":false,\"taskState\":\"estop-reset\",\"mode\":\"manual\",\"allHomed\":false,\"interpState\":\"idle\"},\"spindle\":{\"enabled\":true,\"direction\":\"forward\",\"rpm\":1600},\"coolant\":{\"flood\":true,\"mist\":false},\"taskPolicy\":{\"canRunAuto\":false,\"canRunAutoStrict\":false,\"iniLoaded\":false,\"machineFileStaged\":false,\"taskHalRuntimeReady\":true},\"operatorMessage\":\"frame source fixture-ui-only\"}" + }, + { + "name": "RUN blocked before power", + "pass": true, + "detail": "run blocked: machine must be on" + }, + { + "name": "RUN blocked by reference evidence", + "pass": true, + "detail": "run blocked: LinuxCNC INI not loaded" + }, + { + "name": "Core icons rendered", + "pass": true, + "detail": "{\"estop\":{\"exists\":true,\"iconName\":\"main_switch_off\",\"iconVariant\":\"inactive\",\"buttonId\":\"tbtn_estop\",\"active\":\"false\",\"commandReady\":null,\"title\":\"Estop the machine / F1\"},\"power\":{\"exists\":true,\"iconName\":\"power_on\",\"iconVariant\":\"active\",\"buttonId\":\"tbtn_on\",\"active\":\"true\",\"commandReady\":null,\"title\":\"Turn the machine on/off / F2\"},\"mode-manual\":{\"exists\":true,\"iconName\":\"mode_manual_active\",\"iconVariant\":\"active\",\"buttonId\":\"rbt_manual\",\"active\":\"true\",\"commandReady\":null,\"title\":\"Enter manual mode\"},\"mode-auto\":{\"exists\":true,\"iconName\":\"mode_auto_inactive\",\"iconVariant\":\"inactive\",\"buttonId\":\"rbt_auto\",\"active\":\"false\",\"commandReady\":null,\"title\":\"Enter auto mode\"},\"mode-mdi\":{\"exists\":true,\"iconName\":\"mode_mdi_inactive\",\"iconVariant\":\"inactive\",\"buttonId\":\"rbt_mdi\",\"active\":\"false\",\"commandReady\":null,\"title\":\"Enter MDI mode\"},\"RUN\":{\"exists\":true,\"iconName\":\"play\",\"iconVariant\":\"inactive\",\"buttonId\":\"btn_run\",\"active\":\"false\",\"commandReady\":\"false\",\"title\":\"run blocked: switch to auto mode first\"},\"STOP\":{\"exists\":true,\"iconName\":\"stop\",\"iconVariant\":\"inactive\",\"buttonId\":\"btn_stop\",\"active\":\"false\",\"commandReady\":\"true\",\"title\":\"Stop\"},\"PAUSE\":{\"exists\":true,\"iconName\":\"pause\",\"iconVariant\":\"inactive\",\"buttonId\":\"tbtn_pause\",\"active\":\"false\",\"commandReady\":\"false\",\"title\":\"pause blocked: task mode must be auto or MDI\"},\"HOME\":{\"exists\":true,\"iconName\":\"ref_all\",\"iconVariant\":\"active\",\"buttonId\":\"btn_homing\",\"active\":\"true\",\"commandReady\":\"true\",\"title\":\"Home\"},\"spindle-forward\":{\"exists\":true,\"iconName\":\"spindle_right\",\"iconVariant\":\"inactive\",\"buttonId\":\"rbt_forward\",\"active\":\"false\",\"commandReady\":\"true\",\"title\":\"Spindle forward\"},\"spindle-stop\":{\"exists\":true,\"iconName\":\"spindle_stop_on\",\"iconVariant\":\"active\",\"buttonId\":\"rbt_stop\",\"active\":\"true\",\"commandReady\":\"true\",\"title\":\"Spindle stop\"},\"spindle-reverse\":{\"exists\":true,\"iconName\":\"spindle_left\",\"iconVariant\":\"inactive\",\"buttonId\":\"rbt_reverse\",\"active\":\"false\",\"commandReady\":\"true\",\"title\":\"Spindle reverse\"},\"toggle-flood\":{\"exists\":true,\"iconName\":\"coolant_flood_inactive\",\"iconVariant\":\"inactive\",\"buttonId\":\"tbtn_flood\",\"active\":\"false\",\"commandReady\":\"true\",\"title\":\"Flood coolant\"},\"toggle-mist\":{\"exists\":true,\"iconName\":\"coolant_mist_active\",\"iconVariant\":\"active\",\"buttonId\":\"tbtn_mist\",\"active\":\"true\",\"commandReady\":\"true\",\"title\":\"Mist coolant\"},\"view-x\":{\"exists\":true,\"iconName\":\"tool_axis_x\",\"iconVariant\":\"inactive\",\"buttonId\":\"rbt_view_x\",\"active\":\"false\",\"commandReady\":null,\"title\":\"View X\"}}" + }, + { + "name": "Spindle/coolant state updates", + "pass": true, + "detail": "{\"machineProfile\":\"gmoccapy-xyzab\",\"coordinates\":\"XYZAB\",\"profileTcpCapable\":false,\"profileRtcpProof\":false,\"runState\":\"idle\",\"rtcpState\":\"off\",\"kinsType\":\"identity\",\"machine\":{\"powerOn\":true,\"taskState\":\"on\",\"mode\":\"manual\",\"allHomed\":true,\"interpState\":\"idle\"},\"spindle\":{\"enabled\":false,\"direction\":\"stop\",\"rpm\":1600},\"coolant\":{\"flood\":false,\"mist\":true},\"taskPolicy\":{\"canRunAuto\":false,\"canRunAutoStrict\":false,\"iniLoaded\":false,\"machineFileStaged\":false,\"taskHalRuntimeReady\":true},\"operatorMessage\":\"mist coolant toggled\"}" + }, + { + "name": "NML command diagnostic", + "pass": true, + "detail": "NML command: gmoccapy -> linuxcnc.command() -> NML emcCommand -> milltask" + }, + { + "name": "Web runtime diagnostic", + "pass": true, + "detail": "button -> store.dispatch -> linuxcnc-task-policy -> runtime/status snapshot -> UI/Three.js" + }, + { + "name": "HAL postgui diagnostic", + "pass": true, + "detail": "spindle-abs / spindle-at-speed / tooloffset-x / tooloffset-z / tool-change-loop" + }, + { + "name": "Screenshots are nonblank", + "pass": true, + "detail": "01-loaded:0.7823, 02-profile-selected:0.7815, 03-run-blocked-power:0.7815, 04-run-blocked-reference-evidence:0.7815, 05-controls-active:0.7815, 06-hal-diagnostics:0.7815" + } + ], + "consoleErrors": [ + "Failed to load resource: the server responded with a status of 404 (Not Found)", + "Failed to load resource: the server responded with a status of 404 (Not Found)", + "Failed to load resource: the server responded with a status of 404 (Not Found)", + "Failed to load resource: the server responded with a status of 404 (Not Found)", + "Failed to load resource: the server responded with a status of 404 (Not Found)", + "Failed to load resource: the server responded with a status of 404 (Not Found)", + "Failed to load resource: the server responded with a status of 404 (Not Found)" + ], + "pageErrors": [], + "status": "PASS", + "jsonPath": "/home/meswork/cnc_wams/qa/web-rtcp-5axis-site-test/output/gmoccapy-xyzab-function-report.json", + "pdfPath": "/home/meswork/cnc_wams/qa/web-rtcp-5axis-site-test/output/gmoccapy-xyzab-function-report.pdf" +} diff --git a/qa/web-rtcp-5axis-site-test/output/gmoccapy-xyzab-function-report.pdf b/qa/web-rtcp-5axis-site-test/output/gmoccapy-xyzab-function-report.pdf new file mode 100644 index 0000000..8735a8d Binary files /dev/null and b/qa/web-rtcp-5axis-site-test/output/gmoccapy-xyzab-function-report.pdf differ diff --git a/qa/web-rtcp-5axis-site-test/output/gmoccapy-xyzab/01-loaded.png b/qa/web-rtcp-5axis-site-test/output/gmoccapy-xyzab/01-loaded.png new file mode 100644 index 0000000..6086e9b Binary files /dev/null and b/qa/web-rtcp-5axis-site-test/output/gmoccapy-xyzab/01-loaded.png differ diff --git a/qa/web-rtcp-5axis-site-test/output/gmoccapy-xyzab/02-profile-selected.png b/qa/web-rtcp-5axis-site-test/output/gmoccapy-xyzab/02-profile-selected.png new file mode 100644 index 0000000..d6704db Binary files /dev/null and b/qa/web-rtcp-5axis-site-test/output/gmoccapy-xyzab/02-profile-selected.png differ diff --git a/qa/web-rtcp-5axis-site-test/output/gmoccapy-xyzab/03-run-blocked-power.png b/qa/web-rtcp-5axis-site-test/output/gmoccapy-xyzab/03-run-blocked-power.png new file mode 100644 index 0000000..5811adf Binary files /dev/null and b/qa/web-rtcp-5axis-site-test/output/gmoccapy-xyzab/03-run-blocked-power.png differ diff --git a/qa/web-rtcp-5axis-site-test/output/gmoccapy-xyzab/04-run-blocked-reference-evidence.png b/qa/web-rtcp-5axis-site-test/output/gmoccapy-xyzab/04-run-blocked-reference-evidence.png new file mode 100644 index 0000000..ec9df27 Binary files /dev/null and b/qa/web-rtcp-5axis-site-test/output/gmoccapy-xyzab/04-run-blocked-reference-evidence.png differ diff --git a/qa/web-rtcp-5axis-site-test/output/gmoccapy-xyzab/05-controls-active.png b/qa/web-rtcp-5axis-site-test/output/gmoccapy-xyzab/05-controls-active.png new file mode 100644 index 0000000..624f0e1 Binary files /dev/null and b/qa/web-rtcp-5axis-site-test/output/gmoccapy-xyzab/05-controls-active.png differ diff --git a/qa/web-rtcp-5axis-site-test/output/gmoccapy-xyzab/06-hal-diagnostics.png b/qa/web-rtcp-5axis-site-test/output/gmoccapy-xyzab/06-hal-diagnostics.png new file mode 100644 index 0000000..624f0e1 Binary files /dev/null and b/qa/web-rtcp-5axis-site-test/output/gmoccapy-xyzab/06-hal-diagnostics.png differ diff --git a/web-rtcp-5axis-sim-plan/app/package.json b/web-rtcp-5axis-sim-plan/app/package.json index 88a3ac5..927fd85 100644 --- a/web-rtcp-5axis-sim-plan/app/package.json +++ b/web-rtcp-5axis-sim-plan/app/package.json @@ -7,7 +7,7 @@ "build": "node scripts/build-static.mjs", "dev": "python3 -m http.server 4173", "smoke": "bash ../tests/browser/verify_gmoccapy_shell_browser.sh && bash ../tests/browser/verify_gmoccapy_dist_browser.sh", - "smoke:node": "node ../tests/node/verify_linuxcnc_kinematics_runtime.mjs && node ../tests/node/verify_linuxcnc_interpreter_runtime.mjs && node ../tests/node/verify_linuxcnc_ini_runtime.mjs && node ../tests/node/verify_run_preconditions.mjs && node ../tests/node/verify_run_feedback_loop.mjs && node ../tests/node/verify_linuxcnc_task_hal_runtime.mjs && node ../tests/node/verify_native_task_hal_audit.mjs && node ../tests/node/verify_full_linuxcnc_5axis_source.mjs && node ../tests/node/verify_real_linuxcnc_5axis_program_cases.mjs && node ../tests/node/verify_full_execution_boundary.mjs && node ../tests/node/verify_machine_file_staging.mjs && node ../tests/node/verify_five_axis_session.mjs && node ../tests/node/verify_rtcp_store.mjs && node ../tests/node/verify_profile_boundary.mjs && node ../tests/node/verify_linear_unit_conversion.mjs" + "smoke:node": "node ../tests/node/verify_linuxcnc_kinematics_runtime.mjs && node ../tests/node/verify_linuxcnc_interpreter_runtime.mjs && node ../tests/node/verify_linuxcnc_ini_runtime.mjs && node ../tests/node/verify_run_preconditions.mjs && node ../tests/node/verify_run_feedback_loop.mjs && node ../tests/node/verify_linuxcnc_task_hal_runtime.mjs && node ../tests/node/verify_native_task_hal_audit.mjs && node ../tests/node/verify_full_linuxcnc_5axis_source.mjs && node ../tests/node/verify_real_linuxcnc_5axis_program_cases.mjs && node ../tests/node/verify_full_execution_boundary.mjs && node ../tests/node/verify_machine_file_staging.mjs && node ../tests/node/verify_five_axis_session.mjs && node ../tests/node/verify_rtcp_store.mjs && node ../tests/node/verify_profile_boundary.mjs && node ../tests/node/verify_gmoccapy_xyzab_profile.mjs && node ../tests/node/verify_gmoccapy_icon_manifest.mjs && node ../tests/node/verify_gmoccapy_icon_registry.mjs && node ../tests/node/verify_gmoccapy_communication_model.mjs && node ../tests/node/verify_gmoccapy_hal_model.mjs && node ../tests/node/verify_gmoccapy_xyzab_gates.mjs && node ../tests/node/verify_linear_unit_conversion.mjs" }, "dependencies": {}, "devDependencies": {} diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_auto__mode_auto_inactive__48.png b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_auto__mode_auto_inactive__48.png new file mode 100644 index 0000000..1305c0c Binary files /dev/null and b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_auto__mode_auto_inactive__48.png differ diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_auto_on__mode_auto_active__48.png b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_auto_on__mode_auto_active__48.png new file mode 100644 index 0000000..1305c0c Binary files /dev/null and b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_auto_on__mode_auto_active__48.png differ diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_back_file_load__back_to_app__48.svg b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_back_file_load__back_to_app__48.svg new file mode 100644 index 0000000..d3cce96 --- /dev/null +++ b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_back_file_load__back_to_app__48.svg @@ -0,0 +1,230 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + Jakub Steiner + + + http://jimmac.musichall.cz + + Edit Undo + + + edit + undo + revert + + + + + + + + + + + + + + + + + diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_back_tool__back_to_app__48.svg b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_back_tool__back_to_app__48.svg new file mode 100644 index 0000000..d3cce96 --- /dev/null +++ b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_back_tool__back_to_app__48.svg @@ -0,0 +1,230 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + Jakub Steiner + + + http://jimmac.musichall.cz + + Edit Undo + + + edit + undo + revert + + + + + + + + + + + + + + + + + diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_close__logout__48.png b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_close__logout__48.png new file mode 100644 index 0000000..f2b7e3d Binary files /dev/null and b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_close__logout__48.png differ diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_continuous__jog_continuous__24.png b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_continuous__jog_continuous__24.png new file mode 100644 index 0000000..2a825a5 Binary files /dev/null and b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_continuous__jog_continuous__24.png differ diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_coolant_off__coolant_flood_inactive__48.png b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_coolant_off__coolant_flood_inactive__48.png new file mode 100644 index 0000000..02d3e87 Binary files /dev/null and b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_coolant_off__coolant_flood_inactive__48.png differ diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_coolant_on__coolant_flood_active__48.png b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_coolant_on__coolant_flood_active__48.png new file mode 100644 index 0000000..66c138c Binary files /dev/null and b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_coolant_on__coolant_flood_active__48.png differ diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_dimensions__dimensions__24.png b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_dimensions__dimensions__24.png new file mode 100644 index 0000000..025648d Binary files /dev/null and b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_dimensions__dimensions__24.png differ diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_dir_up__chevron_up__32.svg b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_dir_up__chevron_up__32.svg new file mode 100644 index 0000000..54263df --- /dev/null +++ b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_dir_up__chevron_up__32.svg @@ -0,0 +1,196 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + Jakub Steiner + + + http://jimmac.musichall.cz + + Go Up + + + go + higher + up + arrow + pointer + > + + + + + Andreas Nilsson + + + + + + + + + + + + + + + + + diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_down__chevron_down__24.svg b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_down__chevron_down__24.svg new file mode 100644 index 0000000..efbaa1e --- /dev/null +++ b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_down__chevron_down__24.svg @@ -0,0 +1,200 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + Jakub Steiner + + + http://jimmac.musichall.cz + + Go Up + + + go + higher + up + arrow + pointer + > + + + + + Andreas Nilsson + + + + + + + + + + + + + + + + + diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_edit-redo__edit_redo__32.png b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_edit-redo__edit_redo__32.png new file mode 100644 index 0000000..3eb7b05 Binary files /dev/null and b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_edit-redo__edit_redo__32.png differ diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_edit-undo__edit_undo__32.png b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_edit-undo__edit_undo__32.png new file mode 100644 index 0000000..61b2ce9 Binary files /dev/null and b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_edit-undo__edit_undo__32.png differ diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_edit_comment__comment__32.png b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_edit_comment__comment__32.png new file mode 100644 index 0000000..4acca0a Binary files /dev/null and b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_edit_comment__comment__32.png differ diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_edit_menu_calculator__calculator_open__32.png b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_edit_menu_calculator__calculator_open__32.png new file mode 100644 index 0000000..e0bf102 Binary files /dev/null and b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_edit_menu_calculator__calculator_open__32.png differ diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_edit_menu_close__back_to_app__48.svg b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_edit_menu_close__back_to_app__48.svg new file mode 100644 index 0000000..d3cce96 --- /dev/null +++ b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_edit_menu_close__back_to_app__48.svg @@ -0,0 +1,230 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + Jakub Steiner + + + http://jimmac.musichall.cz + + Edit Undo + + + edit + undo + revert + + + + + + + + + + + + + + + + + diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_edit_menu_keyboard__keyboard__32.png b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_edit_menu_keyboard__keyboard__32.png new file mode 100644 index 0000000..7522263 Binary files /dev/null and b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_edit_menu_keyboard__keyboard__32.png differ diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_edit_menu_keyboard_hide__keyboard_hide__32.png b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_edit_menu_keyboard_hide__keyboard_hide__32.png new file mode 100644 index 0000000..1c23d0f Binary files /dev/null and b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_edit_menu_keyboard_hide__keyboard_hide__32.png differ diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_edit_menu_new__new_document__32.svg b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_edit_menu_new__new_document__32.svg new file mode 100644 index 0000000..1bfdb16 --- /dev/null +++ b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_edit_menu_new__new_document__32.svg @@ -0,0 +1,448 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + New Document + + + Jakub Steiner + + + http://jimmac.musichall.cz + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_edit_menu_reload__refresh__32.png b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_edit_menu_reload__refresh__32.png new file mode 100644 index 0000000..1b1ab55 Binary files /dev/null and b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_edit_menu_reload__refresh__32.png differ diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_edit_menu_save__save__32.png b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_edit_menu_save__save__32.png new file mode 100644 index 0000000..98b49a0 Binary files /dev/null and b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_edit_menu_save__save__32.png differ diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_edit_menu_save_as__save_as__32.png b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_edit_menu_save_as__save_as__32.png new file mode 100644 index 0000000..b82ba95 Binary files /dev/null and b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_edit_menu_save_as__save_as__32.png differ diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_editor__edit_code__32.png b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_editor__edit_code__32.png new file mode 100644 index 0000000..81a1d30 Binary files /dev/null and b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_editor__edit_code__32.png differ diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_emergency__main_switch_on__48.png b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_emergency__main_switch_on__48.png new file mode 100644 index 0000000..3661dcc Binary files /dev/null and b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_emergency__main_switch_on__48.png differ diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_emergency_off__main_switch_off__48.png b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_emergency_off__main_switch_off__48.png new file mode 100644 index 0000000..597330a Binary files /dev/null and b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_emergency_off__main_switch_off__48.png differ diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_fullsize_preview0_close__fullscreen_close__48.png b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_fullsize_preview0_close__fullscreen_close__48.png new file mode 100644 index 0000000..c4bf484 Binary files /dev/null and b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_fullsize_preview0_close__fullscreen_close__48.png differ diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_fullsize_preview0_open__fullscreen_open__48.png b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_fullsize_preview0_open__fullscreen_open__48.png new file mode 100644 index 0000000..c4bf484 Binary files /dev/null and b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_fullsize_preview0_open__fullscreen_open__48.png differ diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_fullsize_preview1_close__fullscreen_close__48.png b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_fullsize_preview1_close__fullscreen_close__48.png new file mode 100644 index 0000000..c4bf484 Binary files /dev/null and b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_fullsize_preview1_close__fullscreen_close__48.png differ diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_fullsize_preview1_open__fullscreen_open__48.png b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_fullsize_preview1_open__fullscreen_open__48.png new file mode 100644 index 0000000..c4bf484 Binary files /dev/null and b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_fullsize_preview1_open__fullscreen_open__48.png differ diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_home__home_folder__32.svg b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_home__home_folder__32.svg new file mode 100644 index 0000000..4f16958 --- /dev/null +++ b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_home__home_folder__32.svg @@ -0,0 +1,445 @@ + +image/svg+xmlGo HomeJakub Steinerhttp://jimmac.musichall.czhomereturngodefaultuserdirectoryTuomas Kuosmanen + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_index_tool__mill_tool_set_num__48.svg b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_index_tool__mill_tool_set_num__48.svg new file mode 100644 index 0000000..7c1c2cd --- /dev/null +++ b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_index_tool__mill_tool_set_num__48.svg @@ -0,0 +1,83 @@ + + + + + + + + image/svg+xml + + + + + + + + + + + M61Q ? + diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_jump_to__user_defined_folder__32.svg b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_jump_to__user_defined_folder__32.svg new file mode 100644 index 0000000..4832fe9 --- /dev/null +++ b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_jump_to__user_defined_folder__32.svg @@ -0,0 +1,204 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + Jakub Steiner + + + http://jimmac.musichall.cz + + Go Jump + + + go + jump + seek + arrow + pointer + + + + + + + + + + + + + + + + diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_machine_off__power_off__48.png b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_machine_off__power_off__48.png new file mode 100644 index 0000000..127c9e9 Binary files /dev/null and b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_machine_off__power_off__48.png differ diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_machine_on__power_on__48.png b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_machine_on__power_on__48.png new file mode 100644 index 0000000..cf3b9b1 Binary files /dev/null and b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_machine_on__power_on__48.png differ diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_macro_menu_calculator__calculator_open__32.png b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_macro_menu_calculator__calculator_open__32.png new file mode 100644 index 0000000..e0bf102 Binary files /dev/null and b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_macro_menu_calculator__calculator_open__32.png differ diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_macro_menu_keyboard__keyboard__32.png b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_macro_menu_keyboard__keyboard__32.png new file mode 100644 index 0000000..7522263 Binary files /dev/null and b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_macro_menu_keyboard__keyboard__32.png differ diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_macro_menu_keyboard_hide__keyboard_hide__32.png b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_macro_menu_keyboard_hide__keyboard_hide__32.png new file mode 100644 index 0000000..1c23d0f Binary files /dev/null and b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_macro_menu_keyboard_hide__keyboard_hide__32.png differ diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_macro_menu_stop__stop__32.png b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_macro_menu_stop__stop__32.png new file mode 100644 index 0000000..22d1e99 Binary files /dev/null and b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_macro_menu_stop__stop__32.png differ diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_manual__mode_manual_inactive__48.png b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_manual__mode_manual_inactive__48.png new file mode 100644 index 0000000..ca80ef1 Binary files /dev/null and b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_manual__mode_manual_inactive__48.png differ diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_manual_on__mode_manual_active__48.png b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_manual_on__mode_manual_active__48.png new file mode 100644 index 0000000..ca80ef1 Binary files /dev/null and b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_manual_on__mode_manual_active__48.png differ diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_mdi__mode_mdi_inactive__48.png b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_mdi__mode_mdi_inactive__48.png new file mode 100644 index 0000000..faede08 Binary files /dev/null and b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_mdi__mode_mdi_inactive__48.png differ diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_mdi_on__mode_mdi_active__48.png b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_mdi_on__mode_mdi_active__48.png new file mode 100644 index 0000000..faede08 Binary files /dev/null and b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_mdi_on__mode_mdi_active__48.png differ diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_mist_off__coolant_mist_inactive__48.png b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_mist_off__coolant_mist_inactive__48.png new file mode 100644 index 0000000..982ae72 Binary files /dev/null and b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_mist_off__coolant_mist_inactive__48.png differ diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_mist_on__coolant_mist_active__48.png b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_mist_on__coolant_mist_active__48.png new file mode 100644 index 0000000..9e57d5a Binary files /dev/null and b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_mist_on__coolant_mist_active__48.png differ diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_offset_calculator__calculator_open__32.png b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_offset_calculator__calculator_open__32.png new file mode 100644 index 0000000..e0bf102 Binary files /dev/null and b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_offset_calculator__calculator_open__32.png differ diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_open__open_file__32.svg b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_open__open_file__32.svg new file mode 100644 index 0000000..55e6177 --- /dev/null +++ b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_open__open_file__32.svg @@ -0,0 +1,535 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + Folder Icon Accept + 2005-01-31 + + + Jakub Steiner + + + + http://jimmac.musichall.cz + Active state - when files are being dragged to. + + + Novell, Inc. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_pause__pause__32.png b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_pause__pause__32.png new file mode 100644 index 0000000..b34c592 Binary files /dev/null and b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_pause__pause__32.png differ diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_pause_active__pause_active__32.png b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_pause_active__pause_active__32.png new file mode 100644 index 0000000..8c3e971 Binary files /dev/null and b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_pause_active__pause_active__32.png differ diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_rabbit_jog__jog_speed_fast__32.png b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_rabbit_jog__jog_speed_fast__32.png new file mode 100644 index 0000000..927226d Binary files /dev/null and b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_rabbit_jog__jog_speed_fast__32.png differ diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_ref_a__ref_a__48.png b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_ref_a__ref_a__48.png new file mode 100644 index 0000000..abe43a5 Binary files /dev/null and b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_ref_a__ref_a__48.png differ diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_ref_all__ref_all__48.png b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_ref_all__ref_all__48.png new file mode 100644 index 0000000..d0f386f Binary files /dev/null and b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_ref_all__ref_all__48.png differ diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_ref_b__ref_b__48.png b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_ref_b__ref_b__48.png new file mode 100644 index 0000000..019725e Binary files /dev/null and b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_ref_b__ref_b__48.png differ diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_ref_menu__ref_all__48.png b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_ref_menu__ref_all__48.png new file mode 100644 index 0000000..d0f386f Binary files /dev/null and b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_ref_menu__ref_all__48.png differ diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_ref_menu_close__back_to_app__48.svg b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_ref_menu_close__back_to_app__48.svg new file mode 100644 index 0000000..d3cce96 --- /dev/null +++ b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_ref_menu_close__back_to_app__48.svg @@ -0,0 +1,230 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + Jakub Steiner + + + http://jimmac.musichall.cz + + Edit Undo + + + edit + undo + revert + + + + + + + + + + + + + + + + + diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_ref_paginate_next__chevron_right__32.svg b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_ref_paginate_next__chevron_right__32.svg new file mode 100644 index 0000000..41e5990 --- /dev/null +++ b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_ref_paginate_next__chevron_right__32.svg @@ -0,0 +1,192 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + Jakub Steiner + + + http://jimmac.musichall.cz + + Go Next + + + go + next + right + arrow + pointer + > + + + + + + + + + + + + + + + + + diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_ref_paginate_prev__chevron_left__32.svg b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_ref_paginate_prev__chevron_left__32.svg new file mode 100644 index 0000000..d5381de --- /dev/null +++ b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_ref_paginate_prev__chevron_left__32.svg @@ -0,0 +1,854 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + Jakub Steiner + + + http://jimmac.musichall.cz + + Go Previous + + + go + previous + left + arrow + pointer + < + + + + + + + + + + + + + + + + + diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_ref_x__ref_x__48.png b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_ref_x__ref_x__48.png new file mode 100644 index 0000000..931a889 Binary files /dev/null and b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_ref_x__ref_x__48.png differ diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_ref_y__ref_y__48.png b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_ref_y__ref_y__48.png new file mode 100644 index 0000000..4d929bc Binary files /dev/null and b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_ref_y__ref_y__48.png differ diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_ref_z__ref_z__48.png b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_ref_z__ref_z__48.png new file mode 100644 index 0000000..aeabddf Binary files /dev/null and b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_ref_z__ref_z__48.png differ diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_refresh_dir__refresh__32.png b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_refresh_dir__refresh__32.png new file mode 100644 index 0000000..1b1ab55 Binary files /dev/null and b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_refresh_dir__refresh__32.png differ diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_reload1__refresh__32.png b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_reload1__refresh__32.png new file mode 100644 index 0000000..1b1ab55 Binary files /dev/null and b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_reload1__refresh__32.png differ diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_run__play__32.png b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_run__play__32.png new file mode 100644 index 0000000..0103eb3 Binary files /dev/null and b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_run__play__32.png differ diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_run_from__run_from_line__48.png b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_run_from__run_from_line__48.png new file mode 100644 index 0000000..0b4ce9f Binary files /dev/null and b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_run_from__run_from_line__48.png differ diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_sel_next__chevron_right__32.svg b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_sel_next__chevron_right__32.svg new file mode 100644 index 0000000..41e5990 --- /dev/null +++ b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_sel_next__chevron_right__32.svg @@ -0,0 +1,192 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + Jakub Steiner + + + http://jimmac.musichall.cz + + Go Next + + + go + next + right + arrow + pointer + > + + + + + + + + + + + + + + + + + diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_sel_prev__chevron_left__32.svg b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_sel_prev__chevron_left__32.svg new file mode 100644 index 0000000..d5381de --- /dev/null +++ b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_sel_prev__chevron_left__32.svg @@ -0,0 +1,854 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + Jakub Steiner + + + http://jimmac.musichall.cz + + Go Previous + + + go + previous + left + arrow + pointer + < + + + + + + + + + + + + + + + + + diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_select__select_file__32.png b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_select__select_file__32.png new file mode 100644 index 0000000..1ed6d98 Binary files /dev/null and b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_select__select_file__32.png differ diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_settings__mode_settings_inactive__48.png b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_settings__mode_settings_inactive__48.png new file mode 100644 index 0000000..69f9caf Binary files /dev/null and b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_settings__mode_settings_inactive__48.png differ diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_settings_on__mode_settings_active__48.png b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_settings_on__mode_settings_active__48.png new file mode 100644 index 0000000..69f9caf Binary files /dev/null and b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_settings_on__mode_settings_active__48.png differ diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_skip_optional_active__skip_optional_active__32.png b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_skip_optional_active__skip_optional_active__32.png new file mode 100644 index 0000000..98143ac Binary files /dev/null and b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_skip_optional_active__skip_optional_active__32.png differ diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_skip_optional_inactive__skip_optional_inactive__32.png b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_skip_optional_inactive__skip_optional_inactive__32.png new file mode 100644 index 0000000..a850d4a Binary files /dev/null and b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_skip_optional_inactive__skip_optional_inactive__32.png differ diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_spindle_forward__spindle_right__48.png b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_spindle_forward__spindle_right__48.png new file mode 100644 index 0000000..f1dd415 Binary files /dev/null and b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_spindle_forward__spindle_right__48.png differ diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_spindle_forward_on__spindle_right_on__48.png b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_spindle_forward_on__spindle_right_on__48.png new file mode 100644 index 0000000..0f251b3 Binary files /dev/null and b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_spindle_forward_on__spindle_right_on__48.png differ diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_spindle_reverse__spindle_left__48.png b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_spindle_reverse__spindle_left__48.png new file mode 100644 index 0000000..27909b4 Binary files /dev/null and b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_spindle_reverse__spindle_left__48.png differ diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_spindle_reverse_on__spindle_left_on__48.png b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_spindle_reverse_on__spindle_left_on__48.png new file mode 100644 index 0000000..db65ddb Binary files /dev/null and b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_spindle_reverse_on__spindle_left_on__48.png differ diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_spindle_stop__spindle_stop__48.png b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_spindle_stop__spindle_stop__48.png new file mode 100644 index 0000000..9091d78 Binary files /dev/null and b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_spindle_stop__spindle_stop__48.png differ diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_spindle_stop_on__spindle_stop_on__48.png b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_spindle_stop_on__spindle_stop_on__48.png new file mode 100644 index 0000000..eb3fde2 Binary files /dev/null and b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_spindle_stop_on__spindle_stop_on__48.png differ diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_split_view__split_view__32.png b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_split_view__split_view__32.png new file mode 100644 index 0000000..4b99265 Binary files /dev/null and b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_split_view__split_view__32.png differ diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_step__step__32.png b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_step__step__32.png new file mode 100644 index 0000000..a3dd9c5 Binary files /dev/null and b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_step__step__32.png differ diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_stop__stop__32.png b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_stop__stop__32.png new file mode 100644 index 0000000..22d1e99 Binary files /dev/null and b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_stop__stop__32.png differ diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_tool_add__add__32.png b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_tool_add__add__32.png new file mode 100644 index 0000000..1098f03 Binary files /dev/null and b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_tool_add__add__32.png differ diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_tool_by_no__mill_tool_change_num__48.svg b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_tool_by_no__mill_tool_change_num__48.svg new file mode 100644 index 0000000..81d2dd3 --- /dev/null +++ b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_tool_by_no__mill_tool_change_num__48.svg @@ -0,0 +1,33 @@ + + + + + + + T ?M6 + diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_tool_calculator__calculator_open__32.png b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_tool_calculator__calculator_open__32.png new file mode 100644 index 0000000..e0bf102 Binary files /dev/null and b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_tool_calculator__calculator_open__32.png differ diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_tool_clear__clear__24.png b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_tool_clear__clear__24.png new file mode 100644 index 0000000..65ca514 Binary files /dev/null and b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_tool_clear__clear__24.png differ diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_tool_delete__delete__32.png b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_tool_delete__delete__32.png new file mode 100644 index 0000000..34eb0ee Binary files /dev/null and b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_tool_delete__delete__32.png differ diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_tool_path__toolpath__24.png b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_tool_path__toolpath__24.png new file mode 100644 index 0000000..5eac0ae Binary files /dev/null and b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_tool_path__toolpath__24.png differ diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_tool_reload__refresh__32.png b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_tool_reload__refresh__32.png new file mode 100644 index 0000000..1b1ab55 Binary files /dev/null and b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_tool_reload__refresh__32.png differ diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_tool_save__save__32.png b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_tool_save__save__32.png new file mode 100644 index 0000000..98b49a0 Binary files /dev/null and b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_tool_save__save__32.png differ diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_toolchange__mill_tool_change__48.png b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_toolchange__mill_tool_change__48.png new file mode 100644 index 0000000..8953f04 Binary files /dev/null and b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_toolchange__mill_tool_change__48.png differ diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_tools__hsk_mill_tool__48.png b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_tools__hsk_mill_tool__48.png new file mode 100644 index 0000000..4453583 Binary files /dev/null and b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_tools__hsk_mill_tool__48.png differ diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_touch_a__touch_a__48.png b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_touch_a__touch_a__48.png new file mode 100644 index 0000000..dd7ed9e Binary files /dev/null and b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_touch_a__touch_a__48.png differ diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_touch_b__touch_b__48.png b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_touch_b__touch_b__48.png new file mode 100644 index 0000000..fd6ea00 Binary files /dev/null and b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_touch_b__touch_b__48.png differ diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_touch_menu_close__back_to_app__48.svg b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_touch_menu_close__back_to_app__48.svg new file mode 100644 index 0000000..d3cce96 --- /dev/null +++ b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_touch_menu_close__back_to_app__48.svg @@ -0,0 +1,230 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + Jakub Steiner + + + http://jimmac.musichall.cz + + Edit Undo + + + edit + undo + revert + + + + + + + + + + + + + + + + + diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_touch_off__touch_off__48.png b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_touch_off__touch_off__48.png new file mode 100644 index 0000000..cad6d9e Binary files /dev/null and b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_touch_off__touch_off__48.png differ diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_touch_paginate_next__chevron_right__32.svg b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_touch_paginate_next__chevron_right__32.svg new file mode 100644 index 0000000..41e5990 --- /dev/null +++ b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_touch_paginate_next__chevron_right__32.svg @@ -0,0 +1,192 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + Jakub Steiner + + + http://jimmac.musichall.cz + + Go Next + + + go + next + right + arrow + pointer + > + + + + + + + + + + + + + + + + + diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_touch_paginate_prev__chevron_left__32.svg b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_touch_paginate_prev__chevron_left__32.svg new file mode 100644 index 0000000..d5381de --- /dev/null +++ b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_touch_paginate_prev__chevron_left__32.svg @@ -0,0 +1,854 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + Jakub Steiner + + + http://jimmac.musichall.cz + + Go Previous + + + go + previous + left + arrow + pointer + < + + + + + + + + + + + + + + + + + diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_touch_x__touch_x__48.png b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_touch_x__touch_x__48.png new file mode 100644 index 0000000..4ad968c Binary files /dev/null and b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_touch_x__touch_x__48.png differ diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_touch_y__touch_y__48.png b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_touch_y__touch_y__48.png new file mode 100644 index 0000000..858ecc2 Binary files /dev/null and b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_touch_y__touch_y__48.png differ diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_touch_z__touch_z__48.png b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_touch_z__touch_z__48.png new file mode 100644 index 0000000..3c5bb69 Binary files /dev/null and b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_touch_z__touch_z__48.png differ diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_turtle_jog__jog_speed_slow__32.png b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_turtle_jog__jog_speed_slow__32.png new file mode 100644 index 0000000..847ee1a Binary files /dev/null and b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_turtle_jog__jog_speed_slow__32.png differ diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_unref_all__unref_all__48.png b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_unref_all__unref_all__48.png new file mode 100644 index 0000000..6e7b6a1 Binary files /dev/null and b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_unref_all__unref_all__48.png differ diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_up__chevron_up__24.svg b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_up__chevron_up__24.svg new file mode 100644 index 0000000..54263df --- /dev/null +++ b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_up__chevron_up__24.svg @@ -0,0 +1,196 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + Jakub Steiner + + + http://jimmac.musichall.cz + + Go Up + + + go + higher + up + arrow + pointer + > + + + + + Andreas Nilsson + + + + + + + + + + + + + + + + + diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_user_tabs__mode_user_tabs_inactive__48.png b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_user_tabs__mode_user_tabs_inactive__48.png new file mode 100644 index 0000000..531e086 Binary files /dev/null and b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_user_tabs__mode_user_tabs_inactive__48.png differ diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_user_tabs_on__mode_user_tabs_active__48.png b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_user_tabs_on__mode_user_tabs_active__48.png new file mode 100644 index 0000000..531e086 Binary files /dev/null and b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_user_tabs_on__mode_user_tabs_active__48.png differ diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_view_p__tool_axis_p__24.png b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_view_p__tool_axis_p__24.png new file mode 100644 index 0000000..5b1a892 Binary files /dev/null and b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_view_p__tool_axis_p__24.png differ diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_view_x__tool_axis_x__24.png b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_view_x__tool_axis_x__24.png new file mode 100644 index 0000000..563205b Binary files /dev/null and b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_view_x__tool_axis_x__24.png differ diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_view_y2__tool_axis_y_inv__24.png b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_view_y2__tool_axis_y_inv__24.png new file mode 100644 index 0000000..a211b7e Binary files /dev/null and b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_view_y2__tool_axis_y_inv__24.png differ diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_view_y__tool_axis_y__24.png b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_view_y__tool_axis_y__24.png new file mode 100644 index 0000000..3c885f2 Binary files /dev/null and b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_view_y__tool_axis_y__24.png differ diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_view_z__tool_axis_z__24.png b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_view_z__tool_axis_z__24.png new file mode 100644 index 0000000..31a7911 Binary files /dev/null and b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_view_z__tool_axis_z__24.png differ diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_zoom_in__zoom_in__24.png b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_zoom_in__zoom_in__24.png new file mode 100644 index 0000000..73083ae Binary files /dev/null and b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_zoom_in__zoom_in__24.png differ diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_zoom_out__zoom_out__24.png b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_zoom_out__zoom_out__24.png new file mode 100644 index 0000000..8f1bcfd Binary files /dev/null and b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/img_zoom_out__zoom_out__24.png differ diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/macro_0__macro_image.png b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/macro_0__macro_image.png new file mode 100644 index 0000000..df4866b Binary files /dev/null and b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/macro_0__macro_image.png differ diff --git a/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/macro_4__macro_image.png b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/macro_4__macro_image.png new file mode 100644 index 0000000..6239dc6 Binary files /dev/null and b/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/macro_4__macro_image.png differ diff --git a/web-rtcp-5axis-sim-plan/app/src/profiles/gmoccapy-xyzab.js b/web-rtcp-5axis-sim-plan/app/src/profiles/gmoccapy-xyzab.js new file mode 100644 index 0000000..048b333 --- /dev/null +++ b/web-rtcp-5axis-sim-plan/app/src/profiles/gmoccapy-xyzab.js @@ -0,0 +1,332 @@ +import { getSourceReferencesForProfile } from "./source-reference-map.js"; + +const sourceReferenceObjects = getSourceReferencesForProfile("gmoccapy-xyzab"); + +export const gmoccapyXyzabPanelSchema = { + id: "gmoccapy-xyzab-hal-component", + profileId: "gmoccapy-xyzab", + title: "gmoccapy HAL component", + sourceXmlPath: "linuxcnc/share/gmoccapy/gmoccapy.glade", + postguiHalPath: "linuxcnc/configs/sim/gmoccapy/gmoccapy_postgui.hal", + boundary: "gmoccapy_hal_component_reference_only", + promotionAllowed: false, + groups: [ + { + id: "task-mode-actions", + type: "gmoccapy-button-bank", + label: "Task and mode controls", + controls: [ + { + id: "tbtn-estop", + type: "button", + text: "ESTOP", + halpin: "gmoccapy.h-button.button-0", + halNet: "gmoccapy-h-button-0", + target: "gmoccapy.command.STATE_ESTOP", + nativeCommand: "STATE_ESTOP / STATE_ESTOP_RESET", + webAction: { type: "ESTOP" }, + }, + { + id: "tbtn-on", + type: "button", + text: "POWER", + halpin: "gmoccapy.h-button.button-1", + halNet: "gmoccapy-h-button-1", + target: "gmoccapy.command.STATE_ON", + nativeCommand: "STATE_ON / STATE_OFF", + webAction: { type: "TOGGLE_POWER" }, + }, + { + id: "rbt-manual", + type: "button", + text: "MANUAL", + halpin: "gmoccapy.v-button.button-0", + halNet: "gmoccapy-v-button-0", + target: "gmoccapy.command.MODE_MANUAL", + nativeCommand: "MODE_MANUAL", + webAction: { type: "SET_MODE", mode: "manual" }, + }, + { + id: "rbt-mdi", + type: "button", + text: "MDI", + halpin: "gmoccapy.v-button.button-1", + halNet: "gmoccapy-v-button-1", + target: "gmoccapy.command.MODE_MDI", + nativeCommand: "MODE_MDI", + webAction: { type: "SET_MODE", mode: "mdi" }, + }, + { + id: "rbt-auto", + type: "button", + text: "AUTO", + halpin: "gmoccapy.v-button.button-2", + halNet: "gmoccapy-v-button-2", + target: "gmoccapy.command.MODE_AUTO", + nativeCommand: "MODE_AUTO", + webAction: { type: "SET_MODE", mode: "auto" }, + }, + ], + }, + { + id: "postgui-display-pins", + type: "postgui-hal", + label: "POSTGUI_HALFILE pins", + controls: [ + { + id: "spindle-feedback-bar", + type: "hal-display", + text: "spindle feedback", + halpin: "gmoccapy.spindle_feedback_bar", + halNet: "spindle-abs", + target: "gmoccapy.spindle_feedback_bar", + }, + { + id: "spindle-at-speed-led", + type: "hal-display", + text: "spindle at speed", + halpin: "gmoccapy.spindle_at_speed_led", + halNet: "spindle-at-speed", + target: "gmoccapy.spindle_at_speed_led", + }, + { + id: "tooloffset-x", + type: "hal-display", + text: "tooloffset X", + halpin: "gmoccapy.tooloffset-x", + halNet: "tooloffset-x", + target: "gmoccapy.tooloffset-x", + }, + { + id: "tooloffset-z", + type: "hal-display", + text: "tooloffset Z", + halpin: "gmoccapy.tooloffset-z", + halNet: "tooloffset-z", + target: "gmoccapy.tooloffset-z", + }, + ], + }, + ], +}; + +export const gmoccapyXyzabProfile = { + id: "gmoccapy-xyzab", + title: "gmoccapy XYZAB trivkins reference", + iniPath: "linuxcnc/configs/sim/gmoccapy/gmoccapy_XYZAB.ini", + pyvcpXmlPath: null, + postguiHalPath: "linuxcnc/configs/sim/gmoccapy/gmoccapy_postgui.hal", + generatedHalPath: null, + toolTablePath: "linuxcnc/configs/sim/gmoccapy/tool.tbl", + machineName: "gmoccapy XYZAB", + display: { + geometry: "XYZAB", + display: "gmoccapy", + cycleTimeMs: 100, + jogAxes: ["X", "Y", "Z", "A", "B"], + programPrefix: "../../nc_files/", + positionOffset: "RELATIVE", + positionFeedback: "ACTUAL", + maxFeedOverride: 1.5, + maxSpindleOverride: 1.2, + minSpindleOverride: 0.5, + increments: ["1.000 mm", "0.100 mm", "0.010 mm", "0.001 mm", "1.2345 in"], + }, + rs274ngc: { + startupCode: "G17 G21 G40 G43H0 G54 G64P0.005 G80 G90 G94 G97 M5 M9", + subroutinePath: "./macros", + halPinVars: false, + parameterFile: "sim.var", + }, + python: { + pathPrepend: "./python", + topLevel: "./python/toplevel.py", + logLevel: 0, + }, + coordinates: ["X", "Y", "Z", "A", "B"], + joints: ["joint.0", "joint.1", "joint.2", "joint.3", "joint.4"], + kinematics: "trivkins coordinates=xyzab", + kinematicsModuleId: "gmoccapy-xyzab-trivkins-reference", + kinematicsParameters: { + sparm: "coordinates=xyzab", + defaultSwitchkinsType: 0, + tcpCapable: false, + rtcpProof: false, + switchkinsTypes: [ + { value: 0, label: "XYZAB trivkins", mdiCommand: null, webKinsType: "identity" }, + ], + }, + remaps: [ + { + code: "M6", + modalGroup: 6, + prolog: "change_prolog", + ngc: "change_g43", + epilog: "change_epilog", + path: "linuxcnc/configs/sim/gmoccapy/macros/change_g43.ngc", + boundary: "linuxcnc_interpreter_remap_reference", + }, + { + code: "M61", + modalGroup: 6, + prolog: "settool_prolog", + ngc: "settool_g43", + epilog: "settool_epilog", + path: "linuxcnc/configs/sim/gmoccapy/macros/settool_g43.ngc", + boundary: "linuxcnc_interpreter_remap_reference", + }, + ], + hal: { + halui: true, + halFiles: [ + "core_sim_XYZAB.hal", + "spindle_sim.hal", + "simulated_home.hal", + ], + postguiHalFiles: ["gmoccapy_postgui.hal"], + postguiRequiresHalcompReady: true, + halcmd: { + loadrt: [ + "trivkins coordinates=xyzab", + "motmod num_joints=5 unlock_joints_mask=16", + "ddt names=ddt_x,ddt_xv,ddt_y,ddt_yv,ddt_z,ddt_zv", + "hypot names=vel_xy,vel_xyz", + ], + loadusr: ["milltask", "halui", "gmoccapy"], + feedbackNets: [ + { signal: "Xpos", source: "joint.0.motor-pos-cmd", target: "joint.0.motor-pos-fb" }, + { signal: "Ypos", source: "joint.1.motor-pos-cmd", target: "joint.1.motor-pos-fb" }, + { signal: "Zpos", source: "joint.2.motor-pos-cmd", target: "joint.2.motor-pos-fb" }, + { signal: "Apos", source: "joint.3.motor-pos-cmd", target: "joint.3.motor-pos-fb" }, + { signal: "Bpos", source: "joint.4.motor-pos-cmd", target: "joint.4.motor-pos-fb" }, + ], + offsetNets: [ + { signal: "tooloffset-x", source: "motion.tooloffset.x", target: "gmoccapy.tooloffset-x" }, + { signal: "tooloffset-z", source: "motion.tooloffset.z", target: "gmoccapy.tooloffset-z" }, + ], + simulationLoops: [ + { signal: "estop-loop", source: "iocontrol.0.user-enable-out", target: "iocontrol.0.emc-enable-in" }, + { signal: "tool-prep-loop", source: "iocontrol.0.tool-prepare", target: "iocontrol.0.tool-prepared" }, + { signal: "tool-change-loop", source: "iocontrol.0.tool-change", target: "iocontrol.0.tool-changed" }, + ], + spindleFeedback: [ + { signal: "spindle-speed-cmd", source: "spindle.0.speed-out", target: "limit_speed.in" }, + { signal: "spindle-speed-limited", source: "limit_speed.out", target: "sim_encoder_0.speed" }, + { signal: "spindle-at-speed", source: "near_speed.out", target: "spindle.0.at-speed" }, + { signal: "spindle-abs", source: "abs_spindle_feedback.out", target: "gmoccapy.spindle_feedback_bar" }, + ], + }, + }, + nativeRuntime: { + linuxcncsvr: true, + task: "milltask", + emcmot: "motmod", + halui: "halui", + display: "gmoccapy -ini", + displayCycleTimeMs: 100, + taskCycleTimeSeconds: 0.001, + basePeriodNs: 100000, + servoPeriodNs: 1000000, + nmlChannels: ["emcCommand", "emcStatus", "emcError"], + }, + homing: { + noForceHoming: false, + noForceHomingIniValue: 0, + homeSequenceRequired: true, + simulatedHomeSwitches: [ + { axis: "X", position: 1 }, + { axis: "Y", position: 0.5 }, + { axis: "Z", position: 2 }, + ], + }, + halui: { + mdiCommands: [], + }, + traj: { + coordinates: "XYZAB", + linearUnits: "mm", + angularUnits: "degree", + defaultLinearVelocity: 9, + maxLinearVelocity: 234, + defaultLinearAcceleration: 200, + maxLinearAcceleration: 200, + noForceHoming: false, + }, + axisLimits: { + X: { min: 0, max: 600, maxVelocity: 166, maxAcceleration: 200 }, + Y: { min: 0, max: 400, maxVelocity: 166, maxAcceleration: 200 }, + Z: { min: -400, max: 4, maxVelocity: 166, maxAcceleration: 200 }, + A: { min: -36000, max: 36000, maxVelocity: 90, maxAcceleration: 1200 }, + B: { min: -36000, max: 36000, maxVelocity: 90, maxAcceleration: 1200 }, + }, + jointConfig: [ + { id: 0, axis: "X", type: "LINEAR", home: 0, homeOffset: 0, homeSequence: 1, min: 0, max: 600, maxVelocity: 166, maxAcceleration: 200 }, + { id: 1, axis: "Y", type: "LINEAR", home: 0, homeOffset: 0, homeSequence: 1, min: 0, max: 400, maxVelocity: 166, maxAcceleration: 200 }, + { id: 2, axis: "Z", type: "LINEAR", home: 0, homeOffset: 1, homeSequence: 0, min: -400, max: 4, maxVelocity: 166, maxAcceleration: 200 }, + { id: 3, axis: "A", type: "ANGULAR", home: 0, homeOffset: 0, homeSequence: 1, min: -36000, max: 36000, maxVelocity: 90, maxAcceleration: 1200 }, + { id: 4, axis: "B", type: "ANGULAR", home: 0, homeOffset: 45, homeSequence: 1, min: -36000, max: 36000, maxVelocity: 90, maxAcceleration: 1200 }, + ], + halPins: [ + "gmoccapy.h-button.button-0", + "gmoccapy.v-button.button-0", + "gmoccapy.jog.axis.jog-x-plus", + "gmoccapy.jog.axis.jog-b-minus", + "gmoccapy.feed.feed-override.counts", + "gmoccapy.spindle.spindle-override.counts", + "gmoccapy.rapid.rapid-override.direct-value", + "gmoccapy.tooloffset-x", + "gmoccapy.tooloffset-z", + "gmoccapy.toolchange-change", + "gmoccapy.toolchange-changed", + "gmoccapy.program.length", + "gmoccapy.program.current-line", + "gmoccapy.program.progress", + "gmoccapy.spindle_feedback_bar", + "gmoccapy.spindle_at_speed_led", + "gmoccapy.error", + ], + offsets: { + toolOffsetX: 0, + toolOffsetZ: 0, + }, + sourceReferences: sourceReferenceObjects.map((reference) => reference.path), + sourceReferenceObjects, + panelSchema: gmoccapyXyzabPanelSchema, + toolTable: { + toolCount: 17, + tools: [ + { tool: 1, pocket: 101, zOffset: -12.7129, diameter: 1, comment: "3/4 roughing" }, + { tool: 2, pocket: 2, zOffset: -0.01, diameter: 2, comment: "3/4 2 flute" }, + { tool: 3, pocket: 3, zOffset: 33.3877, diameter: 3, comment: "2-1/4 face mill" }, + { tool: 4, pocket: 4, zOffset: -10.1737, diameter: 4, comment: "3/8 4fl carbide" }, + { tool: 5, pocket: 5, zOffset: -1.15, diameter: 5, comment: "long ER40 collet chuck" }, + { tool: 6, pocket: 6, zOffset: -5.1252, diameter: 7, comment: "tool 6" }, + { tool: 7, pocket: 7, zOffset: -1.07, diameter: 7, comment: "big albrecht drill chuck .25 drill" }, + { tool: 8, pocket: 8, zOffset: -1.16, diameter: 8, comment: "V engraving tool" }, + { tool: 9, pocket: 9, zOffset: -1.14, diameter: 9, comment: "90 deg 3/8 mill-drill" }, + { tool: 10, pocket: 10, zOffset: -1.13, diameter: 10, comment: "other big jacobs chuck" }, + { tool: 11, pocket: 11, zOffset: -0.09, diameter: 11, comment: "1/8 2fl end mill" }, + { tool: 12, pocket: 12, zOffset: -1.12, diameter: 12, comment: "1/2 2fl long em" }, + { tool: 13, pocket: 13, zOffset: -0.02, diameter: 13, comment: "Tool 13" }, + { tool: 14, pocket: 14, zOffset: -0.04, diameter: 14, comment: "Tool 14" }, + { tool: 15, pocket: 15, zOffset: -0.1, diameter: 15, comment: "little albrecht chuck spot drill" }, + { tool: 16, pocket: 16, zOffset: -0.03, diameter: 16, comment: "little jacobs chuck" }, + { tool: 18, pocket: 1, zOffset: -1.18, diameter: 18, comment: "big jacobs chuck" }, + ], + }, + macros: [ + "i_am_lost", + "halo_world", + "jog_around", + "increment xinc yinc", + "go_to_position X-pos Y-pos Z-pos", + ], + samplePrograms: [ + "linuxcnc/nc_files/3D_Chips.ngc", + ], + semanticBoundary: "gmoccapy_xyzab_trivkins_reference_only_not_rtcp_proof", + linuxCncKinematicsReady: false, + tcpCapable: false, + rtcpProof: false, + promotionAllowed: false, +}; diff --git a/web-rtcp-5axis-sim-plan/app/src/profiles/index.js b/web-rtcp-5axis-sim-plan/app/src/profiles/index.js index 2e98e18..565cba3 100644 --- a/web-rtcp-5axis-sim-plan/app/src/profiles/index.js +++ b/web-rtcp-5axis-sim-plan/app/src/profiles/index.js @@ -1,7 +1,8 @@ import { xyzacTrtProfile } from "./xyzac-trt.js"; import { xyzbcTrtProfile } from "./xyzbc-trt.js"; +import { gmoccapyXyzabProfile } from "./gmoccapy-xyzab.js"; -export const fiveAxisProfiles = [xyzacTrtProfile, xyzbcTrtProfile]; +export const fiveAxisProfiles = [xyzacTrtProfile, xyzbcTrtProfile, gmoccapyXyzabProfile]; export function getFiveAxisProfile(profileId = "xyzac-trt") { const profile = fiveAxisProfiles.find((entry) => entry.id === profileId); diff --git a/web-rtcp-5axis-sim-plan/app/src/profiles/source-reference-map.js b/web-rtcp-5axis-sim-plan/app/src/profiles/source-reference-map.js index bfceda3..7b89e09 100644 --- a/web-rtcp-5axis-sim-plan/app/src/profiles/source-reference-map.js +++ b/web-rtcp-5axis-sim-plan/app/src/profiles/source-reference-map.js @@ -127,6 +127,86 @@ export const linuxCncSourceReferenceMap = [ boundary: "linuxcnc_program_reference", usage: "representative XYZBC switchkins demonstration program", }, + { + id: "gmoccapy-xyzab-ini", + profileId: "gmoccapy-xyzab", + kind: "ini", + path: "linuxcnc/configs/sim/gmoccapy/gmoccapy_XYZAB.ini", + boundary: "linuxcnc_gmoccapy_config_reference", + usage: "gmoccapy XYZAB DISPLAY/TASK/TRAJ/KINS/HAL reference; trivkins only", + }, + { + id: "gmoccapy-xyzab-core-hal", + profileId: "gmoccapy-xyzab", + kind: "halfile", + path: "linuxcnc/configs/sim/gmoccapy/core_sim_XYZAB.hal", + boundary: "native_hal_reference", + usage: "trivkins/motmod loading, XYZAB command-to-feedback loopback, estop/tool/coolant nets", + }, + { + id: "gmoccapy-xyzab-spindle-hal", + profileId: "gmoccapy-xyzab", + kind: "halfile", + path: "linuxcnc/configs/sim/gmoccapy/spindle_sim.hal", + boundary: "native_hal_reference", + usage: "spindle speed limiting, encoder simulation, speed-in and at-speed feedback", + }, + { + id: "gmoccapy-xyzab-home-hal", + profileId: "gmoccapy-xyzab", + kind: "halfile", + path: "linuxcnc/configs/sim/gmoccapy/simulated_home.hal", + boundary: "native_hal_reference", + usage: "simulated X/Y/Z home switch positions", + }, + { + id: "gmoccapy-postgui-hal", + profileId: "gmoccapy-xyzab", + kind: "postgui_hal", + path: "linuxcnc/configs/sim/gmoccapy/gmoccapy_postgui.hal", + boundary: "postgui_hal_reference", + usage: "gmoccapy.* pins connected after halcomp.ready(); spindle feedback and tooloffset display", + }, + { + id: "gmoccapy-trivkins-source", + profileId: "gmoccapy-xyzab", + kind: "kinematics_source", + path: "linuxcnc/src/emc/kinematics/trivkins.c", + boundary: "linuxcnc_source_reference_only_not_rtcp_proof", + usage: "trivial XYZAB joint/axis mapping source reference", + }, + { + id: "gmoccapy-python-gui", + profileId: "gmoccapy-xyzab", + kind: "python_gui", + path: "linuxcnc/src/emc/usr_intf/gmoccapy/gmoccapy.py", + boundary: "native_gui_reference_not_browser_runtime", + usage: "native command/stat/error_channel and gmoccapy HAL component reference", + }, + { + id: "gmoccapy-glade", + profileId: "gmoccapy-xyzab", + kind: "glade_ui", + path: "linuxcnc/share/gmoccapy/gmoccapy.glade", + boundary: "ui_reference_not_browser_runtime", + usage: "button/control layout and gladevcp action reference", + }, + { + id: "gmoccapy-button-icon-manifest", + profileId: "gmoccapy-xyzab", + kind: "icon_manifest", + path: "web-rtcp-5axis-sim-plan/app/src/ui-reference/gmoccapy-button-icons.json", + boundary: "button_icon_asset_reference_only", + usage: "project-local manifest generated from working3 button_icon_inventory.csv", + }, + { + id: "gmoccapy-xyzab-reference-doc", + profileId: "gmoccapy-xyzab", + kind: "documentation", + path: "web-rtcp-5axis-sim-plan/docs/gmoccapy-xyzab-reference.md", + boundary: "documentation_reference", + usage: "summarizes native startup, NML/HAL/postgui, gate, and icon asset boundaries", + }, ]; export function getSourceReferencesForProfile(profileId) { diff --git a/web-rtcp-5axis-sim-plan/app/src/runtime/gmoccapy-communication-model.js b/web-rtcp-5axis-sim-plan/app/src/runtime/gmoccapy-communication-model.js new file mode 100644 index 0000000..a183d76 --- /dev/null +++ b/web-rtcp-5axis-sim-plan/app/src/runtime/gmoccapy-communication-model.js @@ -0,0 +1,169 @@ +export const gmoccapyCommunicationModel = { + apiName: "web-rtcp-5axis-gmoccapy-communication-model", + profileId: "gmoccapy-xyzab", + nativeConfigPath: "linuxcnc/configs/sim/gmoccapy/gmoccapy_XYZAB.ini", + cycleTimeMs: 100, + semanticBoundary: "native_gmoccapy_nml_hal_reference_web_store_runtime_mapping", + nativePaths: { + command: { + label: "NML command", + path: ["gmoccapy", "linuxcnc.command()", "NML emcCommand", "milltask"], + notes: "GUI commands are written to the NML command buffer and consumed by milltask.", + }, + status: { + label: "NML status/error", + path: ["milltask", "NML emcStatus/emcError", "linuxcnc.stat()", "linuxcnc.error_channel()", "gmoccapy"], + notes: "gmoccapy polls status and error channels at DISPLAY CYCLE_TIME.", + }, + hal: { + label: "HAL shared memory", + path: ["gmoccapy.* pins", "HAL shared memory", "halui/iocontrol/motmod/spindle_sim"], + notes: "postgui HAL connects gmoccapy pins after halcomp.ready().", + }, + remap: { + label: "Interpreter REMAP", + path: ["milltask", "RS274NGC", "Python remap prolog/ngc/epilog"], + notes: "M6/M61 remap executes on the task/interpreter side, not inside the GUI event loop.", + }, + }, + webPath: { + label: "Web simulation", + path: ["button", "store.dispatch", "linuxcnc-task-policy", "runtime/status snapshot", "UI/Three.js"], + notes: "The browser does not attach to native NML buffers or HAL shared memory.", + }, + startupStages: [ + { order: 1, id: "parse-ini", nativeStep: "linuxcnc script parses gmoccapy_XYZAB.ini", webEquivalent: "profile/source map selection" }, + { order: 2, id: "linuxcncsvr", nativeStep: "linuxcncsvr -ini ", webEquivalent: "not connected; reference only" }, + { order: 3, id: "realtime-hal", nativeStep: "start realtime/RTAPI/HAL", webEquivalent: "task/HAL runtime simulation boundary where available" }, + { order: 4, id: "milltask", nativeStep: "halcmd loadusr -Wn inihal milltask -ini ", webEquivalent: "store task policy and optional task/HAL runtime" }, + { order: 5, id: "halui", nativeStep: "halcmd loadusr -Wn halui halui -ini ", webEquivalent: "HALUI pins listed as reference diagnostics" }, + { order: 6, id: "halfiles", nativeStep: "run core_sim_XYZAB.hal, spindle_sim.hal, simulated_home.hal", webEquivalent: "HAL model diagnostics" }, + { order: 7, id: "hal-start", nativeStep: "halcmd start", webEquivalent: "not a browser realtime thread" }, + { order: 8, id: "gmoccapy", nativeStep: "gmoccapy -ini ", webEquivalent: "gmoccapy Web shell" }, + { order: 9, id: "postgui", nativeStep: "halcomp.ready(), then gmoccapy_postgui.hal", webEquivalent: "postgui model shown after gmoccapy pins exist" }, + ], + actionMappings: [ + { + actionId: "estop", + webAction: "ESTOP", + nativeCommand: "command.state(STATE_ESTOP)", + nativeStatus: "task_state STATE_ESTOP", + gate: "always available as abortive safety action", + }, + { + actionId: "estop-reset", + webAction: "RESET", + nativeCommand: "command.state(STATE_ESTOP_RESET)", + nativeStatus: "task_state STATE_ESTOP_RESET", + gate: "allowed from estop", + }, + { + actionId: "power-on", + webAction: "TOGGLE_POWER", + nativeCommand: "command.state(STATE_ON)", + nativeStatus: "task_state STATE_ON", + gate: "blocked while STATE_ESTOP", + }, + { + actionId: "mode-manual", + webAction: "SET_MODE manual", + nativeCommand: "command.mode(MODE_MANUAL)", + nativeStatus: "task_mode MODE_MANUAL", + gate: "blocked when AUTO interpreter is not idle", + }, + { + actionId: "mode-mdi", + webAction: "SET_MODE mdi", + nativeCommand: "command.mode(MODE_MDI)", + nativeStatus: "task_mode MODE_MDI", + gate: "machine on and homed when NO_FORCE_HOMING=0", + }, + { + actionId: "mode-auto", + webAction: "SET_MODE auto", + nativeCommand: "command.mode(MODE_AUTO)", + nativeStatus: "task_mode MODE_AUTO", + gate: "machine on and homed when NO_FORCE_HOMING=0", + }, + { + actionId: "jog", + webAction: "JOG", + nativeCommand: "command.jog(JOG_CONTINUOUS/JOG_INCREMENT/JOG_STOP)", + nativeStatus: "motion/joint feedback", + gate: "machine on, manual mode, not running", + }, + { + actionId: "home", + webAction: "HOME", + nativeCommand: "command.home(-1) or command.home(joint)", + nativeStatus: "all-homed", + gate: "machine on, manual mode, no conflicting homing command", + }, + { + actionId: "mdi", + webAction: "RUN_MDI", + nativeCommand: "command.mdi(command)", + nativeStatus: "interp reading/idle", + gate: "machine on, MDI mode, homed when NO_FORCE_HOMING=0", + }, + { + actionId: "auto-run", + webAction: "RUN", + nativeCommand: "command.auto(AUTO_RUN, start_line)", + nativeStatus: "interp reading/waiting/idle", + gate: "INI loaded, program loaded, machine on, homed, AUTO, interpreter idle, runtime ready", + }, + { + actionId: "auto-pause", + webAction: "PAUSE", + nativeCommand: "command.auto(AUTO_PAUSE)", + nativeStatus: "interp paused", + gate: "AUTO or MDI with machine on", + }, + { + actionId: "auto-resume", + webAction: "RESUME", + nativeCommand: "command.auto(AUTO_RESUME)", + nativeStatus: "interp reading", + gate: "interpreter paused", + }, + { + actionId: "abort", + webAction: "STOP/ABORT", + nativeCommand: "command.abort()", + nativeStatus: "interp idle after abort", + gate: "available across most states", + }, + { + actionId: "spindle", + webAction: "spindle controls", + nativeCommand: "command.spindle(direction, rpm)", + nativeStatus: "spindle.0.forward/reverse/speed-out/speed-in", + gate: "blocked in estop/off and restricted during interpreter reading/waiting", + }, + { + actionId: "coolant", + webAction: "TOGGLE_COOLANT", + nativeCommand: "command.flood()/command.mist()", + nativeStatus: "iocontrol.0.coolant-flood/mist", + gate: "blocked in estop/off", + }, + ], +}; + +export function createGmoccapyCommunicationSummary(model = gmoccapyCommunicationModel) { + return { + apiName: `${model.apiName}-summary`, + profileId: model.profileId, + nativeConfigPath: model.nativeConfigPath, + nativePathCount: Object.keys(model.nativePaths).length, + startupStageCount: model.startupStages.length, + actionCount: model.actionMappings.length, + postguiAfterHalcompReady: model.startupStages.findIndex((stage) => stage.id === "postgui") > + model.startupStages.findIndex((stage) => stage.id === "gmoccapy"), + hasNativeNmlCommandPath: model.nativePaths.command.path.includes("NML emcCommand"), + hasNativeHalPath: model.nativePaths.hal.path.includes("HAL shared memory"), + hasWebStorePath: model.webPath.path.includes("store.dispatch"), + semanticBoundary: model.semanticBoundary, + }; +} diff --git a/web-rtcp-5axis-sim-plan/app/src/runtime/gmoccapy-hal-model.js b/web-rtcp-5axis-sim-plan/app/src/runtime/gmoccapy-hal-model.js new file mode 100644 index 0000000..7136eef --- /dev/null +++ b/web-rtcp-5axis-sim-plan/app/src/runtime/gmoccapy-hal-model.js @@ -0,0 +1,280 @@ +export const gmoccapyHalModel = { + apiName: "web-rtcp-5axis-gmoccapy-hal-model", + profileId: "gmoccapy-xyzab", + nativeConfigPath: "linuxcnc/configs/sim/gmoccapy/gmoccapy_XYZAB.ini", + halFiles: [ + { + path: "linuxcnc/configs/sim/gmoccapy/core_sim_XYZAB.hal", + stage: "HALFILE", + role: "trivkins and motmod simulation loopback", + semanticBoundary: "native_hal_reference", + }, + { + path: "linuxcnc/configs/sim/gmoccapy/spindle_sim.hal", + stage: "HALFILE", + role: "spindle speed encoder and at-speed simulation", + semanticBoundary: "native_hal_reference", + }, + { + path: "linuxcnc/configs/sim/gmoccapy/simulated_home.hal", + stage: "HALFILE", + role: "simulated X/Y/Z home switches", + semanticBoundary: "native_hal_reference", + }, + { + path: "linuxcnc/configs/sim/gmoccapy/gmoccapy_postgui.hal", + stage: "POSTGUI_HALFILE", + role: "connections that require gmoccapy.* pins", + requiresHalcompReady: true, + semanticBoundary: "native_postgui_hal_reference", + }, + ], + nativePins: [ + { + group: "hard-buttons", + pins: [ + "gmoccapy.h-button.button-0", + "gmoccapy.h-button.button-1", + "gmoccapy.h-button.button-2", + "gmoccapy.h-button.button-3", + "gmoccapy.h-button.button-4", + "gmoccapy.h-button.button-5", + "gmoccapy.h-button.button-6", + "gmoccapy.h-button.button-7", + "gmoccapy.h-button.button-8", + "gmoccapy.h-button.button-9", + "gmoccapy.v-button.button-0", + "gmoccapy.v-button.button-1", + "gmoccapy.v-button.button-2", + "gmoccapy.v-button.button-3", + "gmoccapy.v-button.button-4", + "gmoccapy.v-button.button-5", + "gmoccapy.v-button.button-6", + ], + webSource: "current visible Web button set", + semanticBoundary: "native_hardware_button_pin_reference", + }, + { + group: "jog", + pins: [ + "gmoccapy.jog.axis.jog-x-plus", + "gmoccapy.jog.axis.jog-x-minus", + "gmoccapy.jog.axis.jog-y-plus", + "gmoccapy.jog.axis.jog-y-minus", + "gmoccapy.jog.axis.jog-z-plus", + "gmoccapy.jog.axis.jog-z-minus", + "gmoccapy.jog.axis.jog-a-plus", + "gmoccapy.jog.axis.jog-a-minus", + "gmoccapy.jog.axis.jog-b-plus", + "gmoccapy.jog.axis.jog-b-minus", + "gmoccapy.jog.jog-inc-0", + "gmoccapy.jog.jog-increment", + ], + webSource: "JOG dispatch and machine.jogIncrement", + semanticBoundary: "native_jog_pin_reference_web_task_policy_gate", + }, + { + group: "override", + pins: [ + "gmoccapy.feed.feed-override.counts", + "gmoccapy.feed.feed-override.direct-value", + "gmoccapy.spindle.spindle-override.counts", + "gmoccapy.spindle.spindle-override.direct-value", + "gmoccapy.jog.jog-velocity.counts", + "gmoccapy.jog.jog-velocity.direct-value", + "gmoccapy.rapid.rapid-override.counts", + "gmoccapy.rapid.rapid-override.direct-value", + ], + webSource: "feed/spindle override state", + semanticBoundary: "native_override_pin_reference_web_state_mapping", + }, + { + group: "tool", + pins: [ + "gmoccapy.tooloffset-x", + "gmoccapy.tooloffset-z", + "gmoccapy.tool-diameter", + "gmoccapy.toolchange-change", + "gmoccapy.toolchange-changed", + "gmoccapy.toolchange-number", + ], + webSource: "toolPreview and tool-change diagnostics", + semanticBoundary: "native_tool_pin_reference_simulated_tool_loop", + }, + { + group: "program", + pins: [ + "gmoccapy.program.length", + "gmoccapy.program.current-line", + "gmoccapy.program.progress", + ], + webSource: "programLines, activeLine, programRuntimeFeedback", + semanticBoundary: "native_program_pin_reference_web_execution_status", + }, + { + group: "message", + pins: [ + "gmoccapy.error", + "gmoccapy.delete-message", + "gmoccapy.warning-confirm", + ], + webSource: "operatorMessage and browser diagnostics", + semanticBoundary: "native_message_pin_reference_web_operator_message", + }, + { + group: "spindle-postgui", + pins: [ + "gmoccapy.spindle_feedback_bar", + "gmoccapy.spindle_at_speed_led", + ], + webSource: "spindle rpm/status panel", + semanticBoundary: "postgui_spindle_feedback_reference", + }, + ], + coreNets: [ + { + signal: "Xpos", + source: "joint.0.motor-pos-cmd", + target: "joint.0.motor-pos-fb", + role: "X command-to-feedback simulation loop", + }, + { + signal: "Ypos", + source: "joint.1.motor-pos-cmd", + target: "joint.1.motor-pos-fb", + role: "Y command-to-feedback simulation loop", + }, + { + signal: "Zpos", + source: "joint.2.motor-pos-cmd", + target: "joint.2.motor-pos-fb", + role: "Z command-to-feedback simulation loop", + }, + { + signal: "Apos", + source: "joint.3.motor-pos-cmd", + target: "joint.3.motor-pos-fb", + role: "A command-to-feedback simulation loop", + }, + { + signal: "Bpos", + source: "joint.4.motor-pos-cmd", + target: "joint.4.motor-pos-fb", + role: "B command-to-feedback simulation loop", + }, + { + signal: "estop-loop", + source: "iocontrol.0.user-enable-out", + target: "iocontrol.0.emc-enable-in", + role: "simulated estop enable loop", + }, + { + signal: "tool-prep-loop", + source: "iocontrol.0.tool-prepare", + target: "iocontrol.0.tool-prepared", + role: "simulated tool prepare completion", + }, + { + signal: "tool-change-loop", + source: "iocontrol.0.tool-change", + target: "iocontrol.0.tool-changed", + role: "simulated automatic tool-change completion", + }, + { + signal: "flood", + source: "iocontrol.0.coolant-flood", + target: "gmoccapy coolant display via status", + role: "coolant flood state", + }, + { + signal: "mist", + source: "iocontrol.0.coolant-mist", + target: "gmoccapy coolant display via status", + role: "coolant mist state", + }, + ], + spindleNets: [ + { + signal: "spindle-speed-cmd", + source: "spindle.0.speed-out", + target: "limit_speed.in", + role: "commanded spindle speed", + }, + { + signal: "spindle-speed-limited", + source: "limit_speed.out", + target: "sim_encoder_0.speed", + role: "simulated spindle inertia", + }, + { + signal: "spindle-pos", + source: "encoder_0.position", + target: "spindle.0.revs", + role: "encoder feedback position", + }, + { + signal: "spindle-at-speed", + source: "near_speed.out", + target: "spindle.0.at-speed", + role: "at-speed comparator result", + }, + ], + postguiNets: [ + { + signal: "spindle-abs", + source: "abs_spindle_feedback.out", + target: "gmoccapy.spindle_feedback_bar", + requiresHalcompReady: true, + role: "spindle feedback bar", + }, + { + signal: "spindle-at-speed", + source: "spindle.0.at-speed", + target: "gmoccapy.spindle_at_speed_led", + requiresHalcompReady: true, + role: "spindle at-speed LED", + }, + { + signal: "tooloffset-x", + source: "motion.tooloffset.x", + target: "gmoccapy.tooloffset-x", + requiresHalcompReady: true, + role: "tool X offset display", + }, + { + signal: "tooloffset-z", + source: "motion.tooloffset.z", + target: "gmoccapy.tooloffset-z", + requiresHalcompReady: true, + role: "tool Z offset display", + }, + { + signal: "tool-change-loop", + source: "iocontrol.0.tool-change", + target: "iocontrol.0.tool-changed", + requiresHalcompReady: true, + simulationLoop: true, + role: "automatic simulated tool-change completion", + }, + ], + semanticBoundary: "gmoccapy_hal_pin_postgui_reference_web_diagnostic_only", +}; + +export function createGmoccapyHalSummary(model = gmoccapyHalModel) { + const pinCount = model.nativePins.reduce((total, group) => total + group.pins.length, 0); + const postguiFile = model.halFiles.find((file) => file.stage === "POSTGUI_HALFILE"); + return { + apiName: `${model.apiName}-summary`, + profileId: model.profileId, + halFileCount: model.halFiles.length, + nativePinGroupCount: model.nativePins.length, + nativePinCount: pinCount, + coreNetCount: model.coreNets.length, + spindleNetCount: model.spindleNets.length, + postguiNetCount: model.postguiNets.length, + postguiRequiresHalcompReady: Boolean(postguiFile?.requiresHalcompReady) && + model.postguiNets.every((net) => net.requiresHalcompReady), + hasToolChangeSimulationLoop: model.postguiNets.some((net) => net.simulationLoop), + semanticBoundary: model.semanticBoundary, + }; +} diff --git a/web-rtcp-5axis-sim-plan/app/src/runtime/rtcp-frame.js b/web-rtcp-5axis-sim-plan/app/src/runtime/rtcp-frame.js index 83c1189..653651b 100644 --- a/web-rtcp-5axis-sim-plan/app/src/runtime/rtcp-frame.js +++ b/web-rtcp-5axis-sim-plan/app/src/runtime/rtcp-frame.js @@ -54,7 +54,7 @@ export function buildRtcpFrame({ rtcpEnabled, rtcpState: rtcpEnabled ? "on" : "off", axisPose: pose, - jointPose: buildJointPose(pose), + jointPose: buildJointPose(pose, profile), tcpPose, toolAxisVector, compensation, @@ -140,18 +140,16 @@ function normalizeAxisPose(axisPose) { }; } -function buildJointPose(pose) { - return [ - { joint: 0, axis: "X", value: pose.x }, - { joint: 1, axis: "Y", value: pose.y }, - { joint: 2, axis: "Z", value: pose.z }, - { joint: 3, axis: "A", value: pose.a }, - { joint: 4, axis: "C", value: pose.c }, - ]; +function buildJointPose(pose, profile = xyzacTrtProfile) { + return axesForProfile(profile).map((axis, joint) => ({ + joint, + axis, + value: pose[axis.toLowerCase()] ?? 0, + })); } function buildJointPoseFromLinuxCncJoints(joints, fallbackPose, profile = xyzacTrtProfile) { - const axes = profile?.traj?.coordinates === "XYZBC" ? ["X", "Y", "Z", "B", "C"] : ["X", "Y", "Z", "A", "C"]; + const axes = axesForProfile(profile); const fallbackValues = axes.map((axis) => fallbackPose[axis.toLowerCase()] ?? 0); return axes.map((axis, joint) => ({ joint, @@ -160,6 +158,13 @@ function buildJointPoseFromLinuxCncJoints(joints, fallbackPose, profile = xyzacT })); } +function axesForProfile(profile = xyzacTrtProfile) { + const coordinates = profile?.coordinates?.length + ? profile.coordinates + : String(profile?.traj?.coordinates || "XYZAC").split(""); + return coordinates.map((axis) => String(axis).toUpperCase()).filter(Boolean); +} + function normalizeLinuxCncPose(pose = {}) { return { x: Number(pose.x ?? pose.tran?.x ?? 0), diff --git a/web-rtcp-5axis-sim-plan/app/src/state/linuxcnc-task-policy.js b/web-rtcp-5axis-sim-plan/app/src/state/linuxcnc-task-policy.js index 617020d..03d40d8 100644 --- a/web-rtcp-5axis-sim-plan/app/src/state/linuxcnc-task-policy.js +++ b/web-rtcp-5axis-sim-plan/app/src/state/linuxcnc-task-policy.js @@ -56,24 +56,55 @@ export function createLinuxCncTaskPolicyStatus(state) { const interpState = normalizeLinuxCncInterpState(state.machine, state.runState); const allHomed = Boolean(state.machine.allHomed); const noForceHoming = Boolean(state.machine.noForceHoming); + const machineFileStaging = state.machineFileStaging || {}; + const profileId = state.profile?.id || state.machineProfile || null; + const taskHalReadiness = state.taskHalRuntimeReadiness || {}; + const taskHalRuntimeReady = Boolean( + state.taskHalRuntime?.loaded && + taskHalReadiness.taskRuntimeReady === true && + taskHalReadiness.motionRuntimeReady === true && + taskHalReadiness.halRuntimeReady === true, + ); + const iniLoaded = state.iniConfigReadiness?.loaded === true && state.iniConfigReadiness?.ready === true; + const machineFileStaged = machineFileStaging.status === "staged" && Boolean(machineFileStaging.save?.files?.length); + const machineFileOpened = profileId === "gmoccapy-xyzab" + ? Boolean(machineFileStaging.selectedGcodeSourceRel) + : Boolean(machineFileStaging.selectedGcodeSourceRel || state.activeProgram); + const interpIdle = interpState === "idle"; + const running = taskMode === "auto" && + (state.runState === "running" || interpState === "reading" || interpState === "waiting"); + const referenceOnly = state.profile?.tcpCapable === false || state.profile?.promotionAllowed === false; return { ...LINUXCNC_TASK_POLICY, taskState, taskMode, interpState, + runState: state.runState || "idle", allHomed, noForceHoming, + iniLoaded, + machineFileStaged, + machineFileOpened, + taskHalRuntimeReady, + interpIdle, + referenceOnly, + profileId, powerOn: taskState === "on", estopActive: taskState === "estop", canMove: taskState === "on", - canJog: taskState === "on" && taskMode === "manual", - canHome: taskState === "on" && taskMode === "manual", + canJog: taskState === "on" && taskMode === "manual" && !running, + canHome: taskState === "on" && taskMode === "manual" && !running, canRunAuto: taskState === "on" && taskMode === "auto" && (allHomed || noForceHoming), + canRunAutoStrict: taskState === "on" && taskMode === "auto" && (allHomed || noForceHoming) && + interpIdle && iniLoaded && machineFileStaged && machineFileOpened && taskHalRuntimeReady, canExecuteMdi: taskState === "on" && taskMode === "mdi" && (allHomed || noForceHoming), canPause: taskState === "on" && (taskMode === "auto" || taskMode === "mdi"), canResume: taskState === "on" && (taskMode === "auto" || taskMode === "mdi") && interpState === "paused", canAbort: true, + canSpindle: taskState === "on", + canCoolant: taskState === "on", + canOverride: taskState === "on", canLeaveAuto: taskMode !== "auto" || interpState === "idle", }; } @@ -94,15 +125,26 @@ export function gateLinuxCncTaskAction(state, action) { case "JOG": if (status.taskState !== "on") return block(status, "jog blocked: machine must be on"); if (status.taskMode !== "manual") return block(status, "jog blocked: switch to manual mode first"); + if (status.taskMode === "auto" && + (status.runState === "running" || status.interpState === "reading" || status.interpState === "waiting")) { + return block(status, "jog blocked: interpreter must be idle"); + } return allow(status); case "HOME": if (status.taskState !== "on") return block(status, "home blocked: machine must be on"); if (status.taskMode !== "manual") return block(status, "home blocked: switch to manual mode first"); + if (status.taskMode === "auto" && + (status.runState === "running" || status.interpState === "reading" || status.interpState === "waiting")) { + return block(status, "home blocked: interpreter must be idle"); + } return allow(status); case "RUN_MDI": if (status.taskState !== "on") return block(status, "MDI blocked: machine must be on"); if (status.taskMode !== "mdi") return block(status, "MDI blocked: switch to MDI mode first"); if (!status.allHomed && !status.noForceHoming) return block(status, "MDI blocked: home machine first"); + if (status.interpState === "reading" || status.interpState === "waiting") { + return block(status, "MDI blocked: interpreter must be idle"); + } return allow(status); case "RUN": case "STEP": @@ -111,6 +153,10 @@ export function gateLinuxCncTaskAction(state, action) { if (status.taskMode !== "auto") return block(status, `${type.toLowerCase()} blocked: switch to auto mode first`); if (!status.allHomed && !status.noForceHoming) return block(status, `${type.toLowerCase()} blocked: home machine first`); if (type === "RUN" && status.interpState === "paused") return block(status, "run blocked: resume paused program first"); + if (type === "RUN" && status.profileId === "gmoccapy-xyzab") { + const strictGate = gateGmoccapyXyzabRun(status); + if (!strictGate.allowed) return strictGate; + } return allow(status); case "PAUSE": if (status.taskState !== "on") return block(status, "pause blocked: machine must be on"); @@ -128,11 +174,42 @@ export function gateLinuxCncTaskAction(state, action) { case "STOP": case "ABORT": return allow(status); + case "SET_SPINDLE_DIRECTION": + case "SPINDLE": + return gateSpindle(status, typeof action === "object" ? action.direction : undefined); + case "TOGGLE_COOLANT": + case "COOLANT": + if (status.taskState !== "on") return block(status, "coolant blocked: machine must be on"); + return allow(status); + case "ADJUST_OVERRIDE": + case "ADJUST_SPINDLE_OVERRIDE": + case "OVERRIDE": + if (status.taskState !== "on") return block(status, "override blocked: machine must be on"); + return allow(status); default: return allow(status); } } +function gateGmoccapyXyzabRun(status) { + if (!status.iniLoaded) return block(status, "run blocked: LinuxCNC INI not loaded"); + if (!status.machineFileStaged) return block(status, "run blocked: LinuxCNC machine files not staged"); + if (!status.machineFileOpened) return block(status, "run blocked: no machine-file G-code opened for task/HAL session"); + if (!status.interpIdle) return block(status, "run blocked: interpreter must be idle"); + if (!status.taskHalRuntimeReady) return block(status, "run blocked: task/HAL runtime not ready"); + return allow(status); +} + +function gateSpindle(status, direction = "stop") { + if (status.taskState !== "on") return block(status, "spindle blocked: machine must be on"); + const requested = String(direction || "stop").toLowerCase(); + if ((requested === "forward" || requested === "reverse") && + (status.interpState === "reading" || status.interpState === "waiting")) { + return block(status, "spindle blocked: interpreter is running"); + } + return allow(status); +} + function gateMode(status, requestedMode) { const targetMode = normalizeLinuxCncTaskMode(requestedMode); if (!LINUXCNC_TASK_MODES.has(targetMode)) { 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 4ac057b..6b62ded 100644 --- a/web-rtcp-5axis-sim-plan/app/src/state/store.js +++ b/web-rtcp-5axis-sim-plan/app/src/state/store.js @@ -224,6 +224,7 @@ const initialState = { rpm: 1600, override: 100, enabled: true, + direction: "forward", }, coolant: { flood: true, @@ -985,7 +986,7 @@ export function createSimulationStore(seed = {}) { runState: turningOff ? "powered-off" : "idle", feed: turningOff ? { ...state.feed, currentVelocity: 0 } : state.feed, coolant: turningOff ? { ...state.coolant, flood: false, mist: false } : state.coolant, - spindle: turningOff ? { ...state.spindle, enabled: false } : state.spindle, + spindle: turningOff ? { ...state.spindle, enabled: false, direction: "stop" } : state.spindle, operatorMessage: turningOff ? "task/HAL machine power off" : "task/HAL machine power on", }); runTaskHalCommandSequence([ @@ -1006,7 +1007,7 @@ export function createSimulationStore(seed = {}) { runState: turningOff ? "powered-off" : "idle", feed: turningOff ? { ...state.feed, currentVelocity: 0 } : state.feed, coolant: turningOff ? { ...state.coolant, flood: false, mist: false } : state.coolant, - spindle: turningOff ? { ...state.spindle, enabled: false } : state.spindle, + spindle: turningOff ? { ...state.spindle, enabled: false, direction: "stop" } : state.spindle, operatorMessage: turningOff ? "machine power off" : "machine power on", }); } @@ -1035,6 +1036,7 @@ export function createSimulationStore(seed = {}) { spindle: { ...state.spindle, enabled: false, + direction: "stop", }, operatorMessage: "emergency stop active", }); @@ -1060,6 +1062,7 @@ export function createSimulationStore(seed = {}) { spindle: { ...state.spindle, enabled: false, + direction: "stop", }, operatorMessage: "estop reset; machine off", }); @@ -1285,6 +1288,24 @@ export function createSimulationStore(seed = {}) { }); } break; + case "SET_SPINDLE_DIRECTION": + { + const gate = gateLinuxCncTaskAction(state, action); + if (!gate.allowed) { + setState({ operatorMessage: gate.operatorMessage }); + break; + } + const direction = normalizeSpindleDirection(action.direction); + setState({ + spindle: { + ...state.spindle, + enabled: direction !== "stop", + direction, + }, + operatorMessage: direction === "stop" ? "spindle stopped" : `spindle ${direction}`, + }); + } + break; case "PAUSE": { const gate = gateLinuxCncTaskAction(state, action); @@ -1486,9 +1507,17 @@ export function createSimulationStore(seed = {}) { }); break; case "SET_RTCP": + if (action.enabled && !profileSupportsTcp(state.profile)) { + setState({ + kinsType: "identity", + rtcpState: "off", + operatorMessage: `RTCP blocked: ${state.profile.id} is ${state.profile.kinematics} reference only`, + }); + break; + } setState({ kinsType: action.enabled - ? (state.profile.kinematicsParameters.switchkinsTypes.find((type) => type.value === 1)?.webKinsType || "tcp-xyzac") + ? tcpKinsTypeForProfile(state.profile) : "identity", rtcpState: action.enabled ? "on" : "off", }); @@ -1526,6 +1555,14 @@ export function createSimulationStore(seed = {}) { }); break; case "SET_KINS_TYPE": + if (String(action.kinsType || "").startsWith("tcp-") && !profileSupportsTcp(state.profile)) { + setState({ + kinsType: "identity", + rtcpState: "off", + operatorMessage: `kinematics ${action.kinsType} blocked: ${state.profile.id} is not TCP capable`, + }); + break; + } setState({ kinsType: action.kinsType, rtcpState: action.kinsType.startsWith("tcp-") ? "on" : "off", @@ -1533,6 +1570,12 @@ export function createSimulationStore(seed = {}) { }); break; case "ADJUST_OVERRIDE": + { + const gate = gateLinuxCncTaskAction(state, action); + if (!gate.allowed) { + setState({ operatorMessage: gate.operatorMessage }); + break; + } setState({ feed: { ...state.feed, @@ -1544,8 +1587,15 @@ export function createSimulationStore(seed = {}) { }, operatorMessage: `${action.target} override adjusted`, }); + } break; case "ADJUST_SPINDLE_OVERRIDE": + { + const gate = gateLinuxCncTaskAction(state, action); + if (!gate.allowed) { + setState({ operatorMessage: gate.operatorMessage }); + break; + } setState({ spindle: { ...state.spindle, @@ -1553,8 +1603,15 @@ export function createSimulationStore(seed = {}) { }, operatorMessage: "spindle override adjusted", }); + } break; case "TOGGLE_COOLANT": + { + const gate = gateLinuxCncTaskAction(state, action); + if (!gate.allowed) { + setState({ operatorMessage: gate.operatorMessage }); + break; + } setState({ coolant: { ...state.coolant, @@ -1562,6 +1619,7 @@ export function createSimulationStore(seed = {}) { }, operatorMessage: `${action.kind} coolant toggled`, }); + } break; case "RELOAD_PROGRAM": setState({ @@ -1875,11 +1933,13 @@ export function createSimulationStore(seed = {}) { allHomed: true, }, }); - const tcpKinsType = state.profile.kinematicsParameters.switchkinsTypes.find((type) => type.value === 1)?.webKinsType || "tcp-xyzac"; - dispatch({ type: "SET_KINS_TYPE", kinsType: tcpKinsType }); + const tcpKinsType = tcpKinsTypeForProfile(state.profile); + if (tcpKinsType) { + dispatch({ type: "SET_KINS_TYPE", kinsType: tcpKinsType }); + } return state; } - const tcpKinsType = state.profile.kinematicsParameters.switchkinsTypes.find((type) => type.value === 1)?.webKinsType || "tcp-xyzac"; + const tcpKinsType = tcpKinsTypeForProfile(state.profile); setState({ machine: { ...state.machine, @@ -1893,9 +1953,11 @@ export function createSimulationStore(seed = {}) { taskPaused: false, }, runState: "idle", - kinsType: tcpKinsType, - rtcpState: "on", - operatorMessage: "RUN ready: power on, homed, auto mode", + kinsType: tcpKinsType || "identity", + rtcpState: tcpKinsType ? "on" : "off", + operatorMessage: tcpKinsType + ? "RUN ready: power on, homed, auto mode" + : "RUN ready: power on, homed, auto mode; TCP unavailable for this reference profile", }); return state; }; @@ -2737,7 +2799,17 @@ function createIniConfigReadiness(iniConfig) { function normalizeKinsTypeForProfile(kinsType, profile) { if (kinsType !== "tcp-xyzac" && kinsType !== "tcp-xyzbc") return kinsType; - return profile.kinematicsParameters.switchkinsTypes.find((type) => type.value === 1)?.webKinsType || kinsType; + return tcpKinsTypeForProfile(profile) || "identity"; +} + +function profileSupportsTcp(profile) { + return Boolean(profile?.tcpCapable !== false && tcpKinsTypeForProfile(profile)); +} + +function tcpKinsTypeForProfile(profile) { + return profile?.kinematicsParameters?.switchkinsTypes + ?.find((type) => type.value === 1 && String(type.webKinsType || "").startsWith("tcp-")) + ?.webKinsType || null; } function clampAxisPoseToProfile(axisPose, profile = defaultProfile) { @@ -2821,6 +2893,7 @@ function executeMdiCommand(state, rawCommand) { ...state.spindle, rpm: parsed.spindleRpm ?? state.spindle.rpm, enabled: parsed.spindleEnabled ?? state.spindle.enabled, + direction: parsed.spindleDirection ?? state.spindle.direction, } : state.spindle, coolant: parsed.coolantPatch @@ -2850,6 +2923,7 @@ function parseMdiCommand(command) { feedRate: null, spindleRpm: null, spindleEnabled: null, + spindleDirection: null, coolantPatch: null, distanceMode: null, motionCode: null, @@ -2888,8 +2962,10 @@ function parseMdiCommand(command) { function applyMdiMCode(parsed, value) { if (value === 3 || value === 4) { parsed.spindleEnabled = true; + parsed.spindleDirection = value === 4 ? "reverse" : "forward"; } else if (value === 5) { parsed.spindleEnabled = false; + parsed.spindleDirection = "stop"; } else if (value === 7) { parsed.coolantPatch = { ...(parsed.coolantPatch || {}), mist: true }; } else if (value === 8) { @@ -2905,9 +2981,14 @@ function applyMdiMCode(parsed, value) { } } +function normalizeSpindleDirection(direction) { + const value = String(direction || "stop").toLowerCase(); + return value === "forward" || value === "reverse" ? value : "stop"; +} + function resolveMdiKinsType(state, kinsType) { if (kinsType !== "tcp") return kinsType; - return state.profile.kinematicsParameters.switchkinsTypes.find((type) => type.value === 1)?.webKinsType || "tcp-xyzac"; + return tcpKinsTypeForProfile(state.profile); } function hasMdiAxisWords(parsed) { 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 7af2f0a..902ac1c 100644 --- a/web-rtcp-5axis-sim-plan/app/src/styles/gmoccapy.css +++ b/web-rtcp-5axis-sim-plan/app/src/styles/gmoccapy.css @@ -49,6 +49,45 @@ button:active { transform: translateY(1px); } +button[data-icon-name] { + display: grid; + grid-template-rows: minmax(18px, 1fr) auto; + place-items: center; + gap: 2px; + min-width: 0; + overflow: hidden; +} + +button[data-icon-name] img, +.gmoccapy-icon-fallback { + display: block; + width: min(26px, 78%); + height: min(26px, 78%); + object-fit: contain; + pointer-events: none; +} + +button[data-icon-name] span { + max-width: 100%; + min-width: 0; + overflow: hidden; + font-size: inherit; + line-height: 1; + text-align: center; + text-overflow: ellipsis; + white-space: nowrap; +} + +.gmoccapy-icon-fallback { + display: grid; + place-items: center; + border: 1px solid #938d84; + background: #f5f2ea; + color: #38332e; + font-size: 9px; + font-weight: 700; +} + .profile-select-label { display: grid; gap: 1px; @@ -282,6 +321,11 @@ button:active { font-weight: 700; } +.preview-toolbar button[data-icon-name] img { + width: min(24px, 80%); + height: min(24px, 80%); +} + .dro-panel { grid-area: dro; display: grid; @@ -601,6 +645,11 @@ button:active { line-height: 1.1; } +.sidebar-button[data-icon-name] img { + width: min(34px, 82%); + height: min(34px, 82%); +} + .sidebar-button.estop { color: #c30000; } @@ -809,6 +858,27 @@ button:active { border: 1px solid #898989; } +.spindle-direction { + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); + gap: 3px; + min-width: 0; +} + +.spindle-direction button, +.cooling button { + min-width: 0; + min-height: 38px; + padding: 2px; + font-size: 10px; +} + +.spindle-direction button[data-active="true"], +.cooling button[data-active="true"] { + border-color: #278b37; + background: #39ef37; +} + .spindle-range i { display: block; height: 100%; @@ -834,6 +904,11 @@ button:active { white-space: normal; } +.bottom-controls button[data-icon-name] img { + width: min(24px, 82%); + height: min(24px, 82%); +} + .program-file-input { display: none; } @@ -1065,4 +1140,18 @@ button:active { min-height: 18px; padding: 1px 2px; } + + button[data-icon-name] { + grid-template-rows: 1fr; + } + + button[data-icon-name] img, + .gmoccapy-icon-fallback { + width: 12px; + height: 12px; + } + + button[data-icon-name] span { + display: none; + } } diff --git a/web-rtcp-5axis-sim-plan/app/src/ui-reference/gmoccapy-button-icons.json b/web-rtcp-5axis-sim-plan/app/src/ui-reference/gmoccapy-button-icons.json new file mode 100644 index 0000000..150a647 --- /dev/null +++ b/web-rtcp-5axis-sim-plan/app/src/ui-reference/gmoccapy-button-icons.json @@ -0,0 +1,4051 @@ +{ + "schema": "web-rtcp-5axis-gmoccapy-button-icons-v1", + "generatedFrom": { + "csv": "work/working3/gmoccapy_button_icons/button_icon_inventory.csv", + "iconDirectory": "work/working3/gmoccapy_button_icons/files" + }, + "semanticBoundary": "gmoccapy_button_icon_asset_reference_only_not_control_semantics", + "rowCount": 211, + "copiedIconCount": 112, + "entries": [ + { + "category": "右侧主状态栏", + "source": "运行时状态", + "buttonId": "rbt_auto", + "label": "Auto 已选中", + "tooltip": "", + "imageId": "img_auto_on", + "imageRole": "Auto active 图标", + "stateOrVariant": "active", + "iconName": "mode_auto_active", + "requestedSize": 48, + "sourceType": "theme-exact-png", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/48x48/actions/mode_auto_active.png", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_auto_on__mode_auto_active__48.png", + "projectAsset": "app/src/assets/gmoccapy-icons/img_auto_on__mode_auto_active__48.png", + "signals": [], + "notes": "on_rbt_auto_toggled" + }, + { + "category": "右侧主状态栏", + "source": "Glade 静态", + "buttonId": "rbt_auto", + "label": "", + "tooltip": "enter auto mode to run programs", + "imageId": "img_auto", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "mode_auto_inactive", + "requestedSize": 48, + "sourceType": "theme-exact-png", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/48x48/actions/mode_auto_inactive.png", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_auto__mode_auto_inactive__48.png", + "projectAsset": "app/src/assets/gmoccapy-icons/img_auto__mode_auto_inactive__48.png", + "signals": [ + "pressed:on_rbt_auto_pressed", + "toggled:on_rbt_auto_toggled" + ], + "notes": "" + }, + { + "category": "右侧主状态栏", + "source": "运行时状态", + "buttonId": "rbt_manual", + "label": "手动已选中", + "tooltip": "", + "imageId": "img_manual_on", + "imageRole": "手动模式 active 图标", + "stateOrVariant": "active", + "iconName": "mode_manual_active", + "requestedSize": 48, + "sourceType": "theme-exact-png", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/48x48/actions/mode_manual_active.png", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_manual_on__mode_manual_active__48.png", + "projectAsset": "app/src/assets/gmoccapy-icons/img_manual_on__mode_manual_active__48.png", + "signals": [], + "notes": "on_rbt_manual_toggled" + }, + { + "category": "右侧主状态栏", + "source": "Glade 静态", + "buttonId": "rbt_manual", + "label": "", + "tooltip": "enter manual mode to jog axis by hand or touch off / [F3]", + "imageId": "img_manual", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "mode_manual_inactive", + "requestedSize": 48, + "sourceType": "theme-exact-png", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/48x48/actions/mode_manual_inactive.png", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_manual__mode_manual_inactive__48.png", + "projectAsset": "app/src/assets/gmoccapy-icons/img_manual__mode_manual_inactive__48.png", + "signals": [ + "pressed:on_rbt_manual_pressed", + "toggled:on_rbt_manual_toggled" + ], + "notes": "" + }, + { + "category": "右侧主状态栏", + "source": "运行时状态", + "buttonId": "rbt_mdi", + "label": "MDI 已选中", + "tooltip": "", + "imageId": "img_mdi_on", + "imageRole": "MDI active 图标", + "stateOrVariant": "active", + "iconName": "mode_mdi_active", + "requestedSize": 48, + "sourceType": "theme-exact-png", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/48x48/actions/mode_mdi_active.png", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_mdi_on__mode_mdi_active__48.png", + "projectAsset": "app/src/assets/gmoccapy-icons/img_mdi_on__mode_mdi_active__48.png", + "signals": [], + "notes": "on_rbt_mdi_toggled" + }, + { + "category": "右侧主状态栏", + "source": "Glade 静态", + "buttonId": "rbt_mdi", + "label": "", + "tooltip": "enter MDI mode to launch G-code commands / [F5]", + "imageId": "img_mdi", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "mode_mdi_inactive", + "requestedSize": 48, + "sourceType": "theme-exact-png", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/48x48/actions/mode_mdi_inactive.png", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_mdi__mode_mdi_inactive__48.png", + "projectAsset": "app/src/assets/gmoccapy-icons/img_mdi__mode_mdi_inactive__48.png", + "signals": [ + "pressed:on_rbt_mdi_pressed", + "toggled:on_rbt_mdi_toggled" + ], + "notes": "" + }, + { + "category": "右侧主状态栏", + "source": "运行时状态", + "buttonId": "tbtn_estop", + "label": "急停复位/非急停", + "tooltip": "", + "imageId": "img_emergency_off", + "imageRole": "急停复位态图标", + "stateOrVariant": "STATE_ESTOP_RESET", + "iconName": "main_switch_off", + "requestedSize": 48, + "sourceType": "theme-exact-png", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/48x48/actions/main_switch_off.png", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_emergency_off__main_switch_off__48.png", + "projectAsset": "app/src/assets/gmoccapy-icons/img_emergency_off__main_switch_off__48.png", + "signals": [], + "notes": "on_hal_status_state_estop_reset" + }, + { + "category": "右侧主状态栏", + "source": "Glade 静态", + "buttonId": "tbtn_estop", + "label": "", + "tooltip": "Estop the machine / [F1]", + "imageId": "img_emergency", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "main_switch_on", + "requestedSize": 48, + "sourceType": "theme-exact-png", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/48x48/actions/main_switch_on.png", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_emergency__main_switch_on__48.png", + "projectAsset": "app/src/assets/gmoccapy-icons/img_emergency__main_switch_on__48.png", + "signals": [ + "toggled:on_tbtn_estop_toggled" + ], + "notes": "" + }, + { + "category": "右侧主状态栏", + "source": "运行时状态", + "buttonId": "tbtn_on", + "label": "上电", + "tooltip": "", + "imageId": "img_machine_on", + "imageRole": "机器 ON 图标", + "stateOrVariant": "STATE_ON", + "iconName": "power_on", + "requestedSize": 48, + "sourceType": "theme-exact-png", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/48x48/actions/power_on.png", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_machine_on__power_on__48.png", + "projectAsset": "app/src/assets/gmoccapy-icons/img_machine_on__power_on__48.png", + "signals": [], + "notes": "on_hal_status_state_on" + }, + { + "category": "右侧主状态栏", + "source": "Glade 静态", + "buttonId": "tbtn_on", + "label": "", + "tooltip": "Turn the machine on/off / [F2]", + "imageId": "img_machine_off", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "power_off", + "requestedSize": 48, + "sourceType": "theme-exact-png", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/48x48/actions/power_off.png", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_machine_off__power_off__48.png", + "projectAsset": "app/src/assets/gmoccapy-icons/img_machine_off__power_off__48.png", + "signals": [ + "toggled:on_tbtn_on_toggled" + ], + "notes": "" + }, + { + "category": "右侧主状态栏", + "source": "运行时状态", + "buttonId": "tbtn_setup", + "label": "设置页已进入", + "tooltip": "", + "imageId": "img_settings_on", + "imageRole": "设置页 active 图标", + "stateOrVariant": "active/unlocked", + "iconName": "mode_settings_active", + "requestedSize": 48, + "sourceType": "theme-exact-png", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/48x48/actions/mode_settings_active.png", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_settings_on__mode_settings_active__48.png", + "projectAsset": "app/src/assets/gmoccapy-icons/img_settings_on__mode_settings_active__48.png", + "signals": [], + "notes": "on_tbtn_setup_toggled" + }, + { + "category": "右侧主状态栏", + "source": "Glade 静态", + "buttonId": "tbtn_setup", + "label": "", + "tooltip": "Enter the settings page, the default code is \"123\"", + "imageId": "img_settings", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "mode_settings_inactive", + "requestedSize": 48, + "sourceType": "theme-exact-png", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/48x48/actions/mode_settings_inactive.png", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_settings__mode_settings_inactive__48.png", + "projectAsset": "app/src/assets/gmoccapy-icons/img_settings__mode_settings_inactive__48.png", + "signals": [ + "toggled:on_tbtn_setup_toggled" + ], + "notes": "" + }, + { + "category": "右侧主状态栏", + "source": "运行时状态", + "buttonId": "tbtn_user_tabs", + "label": "用户页已显示", + "tooltip": "", + "imageId": "img_user_tabs_on", + "imageRole": "用户页 active 图标", + "stateOrVariant": "active", + "iconName": "mode_user_tabs_active", + "requestedSize": 48, + "sourceType": "theme-exact-png", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/48x48/actions/mode_user_tabs_active.png", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_user_tabs_on__mode_user_tabs_active__48.png", + "projectAsset": "app/src/assets/gmoccapy-icons/img_user_tabs_on__mode_user_tabs_active__48.png", + "signals": [], + "notes": "on_tbtn_user_tabs_toggled" + }, + { + "category": "右侧主状态栏", + "source": "Glade 静态", + "buttonId": "tbtn_user_tabs", + "label": "", + "tooltip": "show user tabs", + "imageId": "img_user_tabs", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "mode_user_tabs_inactive", + "requestedSize": 48, + "sourceType": "theme-exact-png", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/48x48/actions/mode_user_tabs_inactive.png", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_user_tabs__mode_user_tabs_inactive__48.png", + "projectAsset": "app/src/assets/gmoccapy-icons/img_user_tabs__mode_user_tabs_inactive__48.png", + "signals": [ + "toggled:on_tbtn_user_tabs_toggled" + ], + "notes": "" + }, + { + "category": "底部主按钮栏", + "source": "Glade 静态", + "buttonId": "btn_exit", + "label": "", + "tooltip": "Close gmoccapy / leave the program", + "imageId": "img_close", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "logout", + "requestedSize": 48, + "sourceType": "theme-exact-png", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/48x48/actions/logout.png", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_close__logout__48.png", + "projectAsset": "app/src/assets/gmoccapy-icons/img_close__logout__48.png", + "signals": [ + "clicked:on_btn_exit_clicked" + ], + "notes": "" + }, + { + "category": "底部主按钮栏", + "source": "Glade 静态", + "buttonId": "btn_homing", + "label": "", + "tooltip": "open homing button list", + "imageId": "img_ref_menu", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "ref_all", + "requestedSize": 48, + "sourceType": "theme-exact-png", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/48x48/actions/ref_all.png", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_ref_menu__ref_all__48.png", + "projectAsset": "app/src/assets/gmoccapy-icons/img_ref_menu__ref_all__48.png", + "signals": [ + "clicked:on_btn_homing_clicked" + ], + "notes": "" + }, + { + "category": "底部主按钮栏", + "source": "Glade 静态", + "buttonId": "btn_tool", + "label": "", + "tooltip": "Open the tooleditor page", + "imageId": "img_tools", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "hsk_mill_tool", + "requestedSize": 48, + "sourceType": "theme-exact-png", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/48x48/actions/hsk_mill_tool.png", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_tools__hsk_mill_tool__48.png", + "projectAsset": "app/src/assets/gmoccapy-icons/img_tools__hsk_mill_tool__48.png", + "signals": [ + "clicked:on_btn_tool_clicked" + ], + "notes": "" + }, + { + "category": "底部主按钮栏", + "source": "Glade 静态", + "buttonId": "btn_touch", + "label": "", + "tooltip": "open touch off button list", + "imageId": "img_touch_off", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "touch_off", + "requestedSize": 48, + "sourceType": "theme-exact-png", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/48x48/actions/touch_off.png", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_touch_off__touch_off__48.png", + "projectAsset": "app/src/assets/gmoccapy-icons/img_touch_off__touch_off__48.png", + "signals": [ + "clicked:on_btn_touch_clicked" + ], + "notes": "" + }, + { + "category": "底部主按钮栏", + "source": "运行时状态", + "buttonId": "tbtn_fullsize_preview0", + "label": "退出大预览", + "tooltip": "", + "imageId": "img_fullsize_preview0_close", + "imageRole": "大预览关闭图标", + "stateOrVariant": "fullscreen active", + "iconName": "fullscreen_close", + "requestedSize": 48, + "sourceType": "theme-exact-png", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/48x48/actions/fullscreen_close.png", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_fullsize_preview0_close__fullscreen_close__48.png", + "projectAsset": "app/src/assets/gmoccapy-icons/img_fullsize_preview0_close__fullscreen_close__48.png", + "signals": [], + "notes": "on_tbtn_fullsize_preview_toggled" + }, + { + "category": "底部主按钮栏", + "source": "Glade 静态", + "buttonId": "tbtn_fullsize_preview0", + "label": "", + "tooltip": "make the preview as large as possible", + "imageId": "img_fullsize_preview0_open", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "fullscreen_open", + "requestedSize": 48, + "sourceType": "theme-exact-png", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/48x48/actions/fullscreen_open.png", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_fullsize_preview0_open__fullscreen_open__48.png", + "projectAsset": "app/src/assets/gmoccapy-icons/img_fullsize_preview0_open__fullscreen_open__48.png", + "signals": [ + "toggled:on_tbtn_fullsize_preview_toggled" + ], + "notes": "" + }, + { + "category": "底部主按钮栏", + "source": "Glade 静态", + "buttonId": "tbtn_switch_mode", + "label": "World / Mode", + "tooltip": "Switch motion mode between Joint and World mode / F12 or $ key does the same", + "imageId": "", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "", + "requestedSize": null, + "sourceType": "none", + "sourcePath": "", + "copiedFile": null, + "projectAsset": null, + "signals": [ + "toggled:on_tbtn_switch_mode_toggled" + ], + "notes": "" + }, + { + "category": "Auto 程序运行栏", + "source": "Glade 静态", + "buttonId": "btn_edit", + "label": "", + "tooltip": "Edit the loaded program", + "imageId": "img_editor", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "edit_code", + "requestedSize": 32, + "sourceType": "theme-nearest-png", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/48x48/actions/edit_code.png", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_editor__edit_code__32.png", + "projectAsset": "app/src/assets/gmoccapy-icons/img_editor__edit_code__32.png", + "signals": [ + "clicked:on_btn_edit_clicked" + ], + "notes": "" + }, + { + "category": "Auto 程序运行栏", + "source": "Glade 静态", + "buttonId": "btn_from_line", + "label": "", + "tooltip": "run the program from a certain line, attention, that is dangerous, because the previous lines will not checked!", + "imageId": "img_run_from", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "run_from_line", + "requestedSize": 48, + "sourceType": "theme-exact-png", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/48x48/actions/run_from_line.png", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_run_from__run_from_line__48.png", + "projectAsset": "app/src/assets/gmoccapy-icons/img_run_from__run_from_line__48.png", + "signals": [ + "clicked:on_btn_from_line_clicked" + ], + "notes": "" + }, + { + "category": "Auto 程序运行栏", + "source": "Glade 静态", + "buttonId": "btn_load", + "label": "", + "tooltip": "Load a new program", + "imageId": "img_open", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "open_file", + "requestedSize": 32, + "sourceType": "theme-svg", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/scalable/actions/open_file.svg", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_open__open_file__32.svg", + "projectAsset": "app/src/assets/gmoccapy-icons/img_open__open_file__32.svg", + "signals": [ + "clicked:on_btn_load_clicked" + ], + "notes": "" + }, + { + "category": "Auto 程序运行栏", + "source": "Glade 静态", + "buttonId": "btn_reload", + "label": "", + "tooltip": "Reload file", + "imageId": "img_reload1", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "refresh", + "requestedSize": 32, + "sourceType": "theme-nearest-png", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/48x48/actions/refresh.png", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_reload1__refresh__32.png", + "projectAsset": "app/src/assets/gmoccapy-icons/img_reload1__refresh__32.png", + "signals": [], + "notes": "" + }, + { + "category": "Auto 程序运行栏", + "source": "Glade 静态", + "buttonId": "btn_run", + "label": "", + "tooltip": "Run the loaded program", + "imageId": "img_run", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "play", + "requestedSize": 32, + "sourceType": "theme-nearest-png", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/48x48/actions/play.png", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_run__play__32.png", + "projectAsset": "app/src/assets/gmoccapy-icons/img_run__play__32.png", + "signals": [ + "clicked:on_btn_run_clicked" + ], + "notes": "" + }, + { + "category": "Auto 程序运行栏", + "source": "Glade 静态", + "buttonId": "btn_step", + "label": "", + "tooltip": "Run the loaded program step by step", + "imageId": "img_step", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "step", + "requestedSize": 32, + "sourceType": "theme-nearest-png", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/48x48/actions/step.png", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_step__step__32.png", + "projectAsset": "app/src/assets/gmoccapy-icons/img_step__step__32.png", + "signals": [], + "notes": "" + }, + { + "category": "Auto 程序运行栏", + "source": "Glade 静态", + "buttonId": "btn_stop", + "label": "", + "tooltip": "Stop the running program", + "imageId": "img_stop", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "stop", + "requestedSize": 32, + "sourceType": "theme-nearest-png", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/48x48/actions/stop.png", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_stop__stop__32.png", + "projectAsset": "app/src/assets/gmoccapy-icons/img_stop__stop__32.png", + "signals": [ + "clicked:on_btn_stop_clicked" + ], + "notes": "" + }, + { + "category": "Auto 程序运行栏", + "source": "运行时状态", + "buttonId": "tbtn_fullsize_preview1", + "label": "退出大预览", + "tooltip": "", + "imageId": "img_fullsize_preview1_close", + "imageRole": "大预览关闭图标", + "stateOrVariant": "fullscreen active", + "iconName": "fullscreen_close", + "requestedSize": 48, + "sourceType": "theme-exact-png", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/48x48/actions/fullscreen_close.png", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_fullsize_preview1_close__fullscreen_close__48.png", + "projectAsset": "app/src/assets/gmoccapy-icons/img_fullsize_preview1_close__fullscreen_close__48.png", + "signals": [], + "notes": "on_tbtn_fullsize_preview_toggled" + }, + { + "category": "Auto 程序运行栏", + "source": "Glade 静态", + "buttonId": "tbtn_fullsize_preview1", + "label": "", + "tooltip": "Show full screen preview", + "imageId": "img_fullsize_preview1_open", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "fullscreen_open", + "requestedSize": 48, + "sourceType": "theme-exact-png", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/48x48/actions/fullscreen_open.png", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_fullsize_preview1_open__fullscreen_open__48.png", + "projectAsset": "app/src/assets/gmoccapy-icons/img_fullsize_preview1_open__fullscreen_open__48.png", + "signals": [ + "toggled:on_tbtn_fullsize_preview_toggled" + ], + "notes": "" + }, + { + "category": "Auto 程序运行栏", + "source": "运行时状态", + "buttonId": "tbtn_optional_blocks", + "label": "跳过可选段", + "tooltip": "", + "imageId": "img_skip_optional_active", + "imageRole": "可选段跳过 active 图标", + "stateOrVariant": "block delete active", + "iconName": "skip_optional_active", + "requestedSize": 32, + "sourceType": "theme-exact-png", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/32x32/actions/skip_optional_active.png", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_skip_optional_active__skip_optional_active__32.png", + "projectAsset": "app/src/assets/gmoccapy-icons/img_skip_optional_active__skip_optional_active__32.png", + "signals": [], + "notes": "on_tbtn_optional_blocks_toggled" + }, + { + "category": "Auto 程序运行栏", + "source": "Glade 静态", + "buttonId": "tbtn_optional_blocks", + "label": "", + "tooltip": "Machine or not the optional blocks of the program. If the button is pressed, the optional blocks will not be machined. The button will indicate this by a yellow background.", + "imageId": "img_skip_optional_inactive", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "skip_optional_inactive", + "requestedSize": 32, + "sourceType": "theme-exact-png", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/32x32/actions/skip_optional_inactive.png", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_skip_optional_inactive__skip_optional_inactive__32.png", + "projectAsset": "app/src/assets/gmoccapy-icons/img_skip_optional_inactive__skip_optional_inactive__32.png", + "signals": [ + "toggled:on_tbtn_optional_blocks_toggled" + ], + "notes": "" + }, + { + "category": "Auto 程序运行栏", + "source": "运行时状态", + "buttonId": "tbtn_pause", + "label": "暂停中", + "tooltip": "", + "imageId": "img_pause_active", + "imageRole": "暂停 active 图标", + "stateOrVariant": "paused", + "iconName": "pause_active", + "requestedSize": 32, + "sourceType": "theme-nearest-png", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/48x48/actions/pause_active.png", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_pause_active__pause_active__32.png", + "projectAsset": "app/src/assets/gmoccapy-icons/img_pause_active__pause_active__32.png", + "signals": [], + "notes": "on_tbtn_pause_toggled" + }, + { + "category": "Auto 程序运行栏", + "source": "Glade 静态", + "buttonId": "tbtn_pause", + "label": "", + "tooltip": "Pause the running program", + "imageId": "img_pause", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "pause", + "requestedSize": 32, + "sourceType": "theme-nearest-png", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/48x48/actions/pause.png", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_pause__pause__32.png", + "projectAsset": "app/src/assets/gmoccapy-icons/img_pause__pause__32.png", + "signals": [ + "toggled:on_tbtn_pause_toggled" + ], + "notes": "" + }, + { + "category": "MDI/宏按钮栏", + "source": "Python 动态", + "buttonId": "calculator", + "label": "计算器", + "tooltip": "Press to display the calculator", + "imageId": "img_macro_menu_calculator", + "imageRole": "动态按钮图标", + "stateOrVariant": "默认", + "iconName": "calculator_open", + "requestedSize": 32, + "sourceType": "theme-exact-png", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/32x32/actions/calculator_open.png", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_macro_menu_calculator__calculator_open__32.png", + "projectAsset": "app/src/assets/gmoccapy-icons/img_macro_menu_calculator__calculator_open__32.png", + "signals": [], + "notes": "_make_macro_button" + }, + { + "category": "MDI/宏按钮栏", + "source": "运行时状态", + "buttonId": "keyboard", + "label": "隐藏虚拟键盘", + "tooltip": "", + "imageId": "img_macro_menu_keyboard_hide", + "imageRole": "宏栏键盘隐藏图标", + "stateOrVariant": "keyboard shown", + "iconName": "keyboard_hide", + "requestedSize": 32, + "sourceType": "theme-nearest-png", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/48x48/actions/keyboard_hide.png", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_macro_menu_keyboard_hide__keyboard_hide__32.png", + "projectAsset": "app/src/assets/gmoccapy-icons/img_macro_menu_keyboard_hide__keyboard_hide__32.png", + "signals": [], + "notes": "on_ntb_info_switch_page" + }, + { + "category": "MDI/宏按钮栏", + "source": "运行时状态", + "buttonId": "keyboard", + "label": "中止运行宏/程序", + "tooltip": "", + "imageId": "img_macro_menu_stop", + "imageRole": "宏栏停止图标", + "stateOrVariant": "program/macro running or no keyboard", + "iconName": "stop", + "requestedSize": 32, + "sourceType": "theme-nearest-png", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/48x48/actions/stop.png", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_macro_menu_stop__stop__32.png", + "projectAsset": "app/src/assets/gmoccapy-icons/img_macro_menu_stop__stop__32.png", + "signals": [], + "notes": "on_hal_status_interp_run/_no_virt_keyboard" + }, + { + "category": "MDI/宏按钮栏", + "source": "Python 动态", + "buttonId": "keyboard", + "label": "虚拟键盘", + "tooltip": "Press to display the virtual keyboard", + "imageId": "img_macro_menu_keyboard", + "imageRole": "动态按钮图标", + "stateOrVariant": "默认", + "iconName": "keyboard", + "requestedSize": 32, + "sourceType": "theme-nearest-png", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/48x48/actions/keyboard.png", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_macro_menu_keyboard__keyboard__32.png", + "projectAsset": "app/src/assets/gmoccapy-icons/img_macro_menu_keyboard__keyboard__32.png", + "signals": [], + "notes": "_make_macro_button" + }, + { + "category": "MDI/宏按钮栏", + "source": "Python 动态宏", + "buttonId": "macro_0", + "label": "i_am_lost", + "tooltip": "Press to run macro i_am_lost", + "imageId": "", + "imageRole": "无图标", + "stateOrVariant": "默认", + "iconName": "", + "requestedSize": null, + "sourceType": "macro-custom-file", + "sourcePath": "linuxcnc/configs/sim/gmoccapy/macros/images/i_am_lost.png", + "copiedFile": "work/working3/gmoccapy_button_icons/files/macro_0__macro_image.png", + "projectAsset": "app/src/assets/gmoccapy-icons/macro_0__macro_image.png", + "signals": [], + "notes": "宏文件 IMAGE 自定义图片: /home/meswork/cnc_wams/linuxcnc/configs/sim/gmoccapy/macros/images/i_am_lost.png" + }, + { + "category": "MDI/宏按钮栏", + "source": "Python 动态宏", + "buttonId": "macro_1", + "label": "halo_world", + "tooltip": "Press to run macro halo_world", + "imageId": "", + "imageRole": "无图标", + "stateOrVariant": "默认", + "iconName": "", + "requestedSize": null, + "sourceType": "none", + "sourcePath": "", + "copiedFile": null, + "projectAsset": null, + "signals": [], + "notes": "宏按钮使用文字,无图标" + }, + { + "category": "MDI/宏按钮栏", + "source": "Python 动态宏", + "buttonId": "macro_2", + "label": "jog_around", + "tooltip": "Press to run macro jog_around", + "imageId": "", + "imageRole": "无图标", + "stateOrVariant": "默认", + "iconName": "", + "requestedSize": null, + "sourceType": "none", + "sourcePath": "", + "copiedFile": null, + "projectAsset": null, + "signals": [], + "notes": "宏按钮使用文字,无图标" + }, + { + "category": "MDI/宏按钮栏", + "source": "Python 动态宏", + "buttonId": "macro_3", + "label": "increment", + "tooltip": "Press to run macro increment xinc yinc", + "imageId": "", + "imageRole": "无图标", + "stateOrVariant": "默认", + "iconName": "", + "requestedSize": null, + "sourceType": "none", + "sourcePath": "", + "copiedFile": null, + "projectAsset": null, + "signals": [], + "notes": "宏按钮使用文字,无图标" + }, + { + "category": "MDI/宏按钮栏", + "source": "Python 动态宏", + "buttonId": "macro_4", + "label": "go_to_position", + "tooltip": "Press to run macro go_to_position X-pos Y-pos Z-pos", + "imageId": "", + "imageRole": "无图标", + "stateOrVariant": "默认", + "iconName": "", + "requestedSize": null, + "sourceType": "macro-custom-file", + "sourcePath": "linuxcnc/configs/sim/gmoccapy/macros/images/goto_x_y_z.png", + "copiedFile": "work/working3/gmoccapy_button_icons/files/macro_4__macro_image.png", + "projectAsset": "app/src/assets/gmoccapy-icons/macro_4__macro_image.png", + "signals": [], + "notes": "宏文件 IMAGE 自定义图片: /home/meswork/cnc_wams/linuxcnc/configs/sim/gmoccapy/macros/images/goto_x_y_z.png" + }, + { + "category": "MDI/宏按钮栏", + "source": "Python 动态", + "buttonId": "next_button", + "label": "下一组宏按钮", + "tooltip": "Press to display next macro button", + "imageId": "img_macro_paginate_next", + "imageRole": "动态按钮图标", + "stateOrVariant": "默认", + "iconName": "go-next", + "requestedSize": null, + "sourceType": "gtk-icon-name-not-copied", + "sourcePath": "GTK/system icon theme", + "copiedFile": null, + "projectAsset": null, + "signals": [], + "notes": "当前宏数 5,小于 7,默认隐藏; 未在 gmoccapy classic 主题中固定解析,运行时由 GTK/system icon theme 决定" + }, + { + "category": "MDI/宏按钮栏", + "source": "Python 动态", + "buttonId": "previous_button", + "label": "上一组宏按钮", + "tooltip": "Press to display previous macro button", + "imageId": "img_macro_paginate_prev", + "imageRole": "动态按钮图标", + "stateOrVariant": "默认", + "iconName": "go-previous", + "requestedSize": null, + "sourceType": "gtk-icon-name-not-copied", + "sourcePath": "GTK/system icon theme", + "copiedFile": null, + "projectAsset": null, + "signals": [], + "notes": "当前宏数 5,小于 7,默认隐藏; 未在 gmoccapy classic 主题中固定解析,运行时由 GTK/system icon theme 决定" + }, + { + "category": "回零按钮栏", + "source": "Python 动态", + "buttonId": "home_axis_a", + "label": "回零 A 轴", + "tooltip": "Press to home axis A", + "imageId": "img_ref_a", + "imageRole": "动态按钮图标", + "stateOrVariant": "默认", + "iconName": "ref_a", + "requestedSize": 48, + "sourceType": "theme-exact-png", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/48x48/actions/ref_a.png", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_ref_a__ref_a__48.png", + "projectAsset": "app/src/assets/gmoccapy-icons/img_ref_a__ref_a__48.png", + "signals": [], + "notes": "当前 XYZAB 生成" + }, + { + "category": "回零按钮栏", + "source": "Python 动态", + "buttonId": "home_axis_b", + "label": "回零 B 轴", + "tooltip": "Press to home axis B", + "imageId": "img_ref_b", + "imageRole": "动态按钮图标", + "stateOrVariant": "默认", + "iconName": "ref_b", + "requestedSize": 48, + "sourceType": "theme-exact-png", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/48x48/actions/ref_b.png", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_ref_b__ref_b__48.png", + "projectAsset": "app/src/assets/gmoccapy-icons/img_ref_b__ref_b__48.png", + "signals": [], + "notes": "当前 XYZAB 生成" + }, + { + "category": "回零按钮栏", + "source": "Python 动态", + "buttonId": "home_axis_x", + "label": "回零 X 轴", + "tooltip": "Press to home axis X", + "imageId": "img_ref_x", + "imageRole": "动态按钮图标", + "stateOrVariant": "默认", + "iconName": "ref_x", + "requestedSize": 48, + "sourceType": "theme-exact-png", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/48x48/actions/ref_x.png", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_ref_x__ref_x__48.png", + "projectAsset": "app/src/assets/gmoccapy-icons/img_ref_x__ref_x__48.png", + "signals": [], + "notes": "当前 XYZAB 生成" + }, + { + "category": "回零按钮栏", + "source": "Python 动态", + "buttonId": "home_axis_y", + "label": "回零 Y 轴", + "tooltip": "Press to home axis Y", + "imageId": "img_ref_y", + "imageRole": "动态按钮图标", + "stateOrVariant": "默认", + "iconName": "ref_y", + "requestedSize": 48, + "sourceType": "theme-exact-png", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/48x48/actions/ref_y.png", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_ref_y__ref_y__48.png", + "projectAsset": "app/src/assets/gmoccapy-icons/img_ref_y__ref_y__48.png", + "signals": [], + "notes": "当前 XYZAB 生成" + }, + { + "category": "回零按钮栏", + "source": "Python 动态", + "buttonId": "home_axis_z", + "label": "回零 Z 轴", + "tooltip": "Press to home axis Z", + "imageId": "img_ref_z", + "imageRole": "动态按钮图标", + "stateOrVariant": "默认", + "iconName": "ref_z", + "requestedSize": 48, + "sourceType": "theme-exact-png", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/48x48/actions/ref_z.png", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_ref_z__ref_z__48.png", + "projectAsset": "app/src/assets/gmoccapy-icons/img_ref_z__ref_z__48.png", + "signals": [], + "notes": "当前 XYZAB 生成" + }, + { + "category": "回零按钮栏", + "source": "Python 动态", + "buttonId": "home_back", + "label": "返回主按钮栏", + "tooltip": "Press to return to main button list", + "imageId": "img_ref_menu_close", + "imageRole": "动态按钮图标", + "stateOrVariant": "默认", + "iconName": "back_to_app", + "requestedSize": 48, + "sourceType": "theme-svg", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/scalable/actions/back_to_app.svg", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_ref_menu_close__back_to_app__48.svg", + "projectAsset": "app/src/assets/gmoccapy-icons/img_ref_menu_close__back_to_app__48.svg", + "signals": [], + "notes": "_make_ref_axis_button" + }, + { + "category": "回零按钮栏", + "source": "Python 动态", + "buttonId": "next_button", + "label": "下一组回零按钮", + "tooltip": "Press to display next homing button", + "imageId": "img_ref_paginate_next", + "imageRole": "动态按钮图标", + "stateOrVariant": "默认", + "iconName": "chevron_right", + "requestedSize": 32, + "sourceType": "theme-svg", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/scalable/actions/chevron_right.svg", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_ref_paginate_next__chevron_right__32.svg", + "projectAsset": "app/src/assets/gmoccapy-icons/img_ref_paginate_next__chevron_right__32.svg", + "signals": [], + "notes": "仅轴数大于 7 时显示" + }, + { + "category": "回零按钮栏", + "source": "Python 动态", + "buttonId": "previous_button", + "label": "上一组回零按钮", + "tooltip": "Press to display previous homing button", + "imageId": "img_ref_paginate_prev", + "imageRole": "动态按钮图标", + "stateOrVariant": "默认", + "iconName": "chevron_left", + "requestedSize": 32, + "sourceType": "theme-svg", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/scalable/actions/chevron_left.svg", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_ref_paginate_prev__chevron_left__32.svg", + "projectAsset": "app/src/assets/gmoccapy-icons/img_ref_paginate_prev__chevron_left__32.svg", + "signals": [], + "notes": "仅轴数大于 7 时显示" + }, + { + "category": "回零按钮栏", + "source": "Python 动态", + "buttonId": "ref_all", + "label": "回零全部轴", + "tooltip": "Press to home all axes", + "imageId": "img_ref_all", + "imageRole": "动态按钮图标", + "stateOrVariant": "默认", + "iconName": "ref_all", + "requestedSize": 48, + "sourceType": "theme-exact-png", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/48x48/actions/ref_all.png", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_ref_all__ref_all__48.png", + "projectAsset": "app/src/assets/gmoccapy-icons/img_ref_all__ref_all__48.png", + "signals": [], + "notes": "_make_ref_axis_button" + }, + { + "category": "回零按钮栏", + "source": "Python 动态", + "buttonId": "unref_all", + "label": "取消全部回零", + "tooltip": "Press to unhome all axes", + "imageId": "img_unref_all", + "imageRole": "动态按钮图标", + "stateOrVariant": "默认", + "iconName": "unref_all", + "requestedSize": 48, + "sourceType": "theme-exact-png", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/48x48/actions/unref_all.png", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_unref_all__unref_all__48.png", + "projectAsset": "app/src/assets/gmoccapy-icons/img_unref_all__unref_all__48.png", + "signals": [], + "notes": "_make_ref_axis_button" + }, + { + "category": "对刀/坐标设定按钮栏", + "source": "Python 动态", + "buttonId": "block_height", + "label": "Block Height", + "tooltip": "Press to enter new value for block height", + "imageId": "", + "imageRole": "无图标", + "stateOrVariant": "默认", + "iconName": "", + "requestedSize": null, + "sourceType": "none", + "sourcePath": "", + "copiedFile": null, + "projectAsset": null, + "signals": [], + "notes": "仅 [TOOLSENSOR] 有效时出现;本配置默认不出现" + }, + { + "category": "对刀/坐标设定按钮栏", + "source": "Python 动态", + "buttonId": "next_button", + "label": "下一组 Touch Off 按钮", + "tooltip": "Press to display next homing button", + "imageId": "img_touch_paginate_next", + "imageRole": "动态按钮图标", + "stateOrVariant": "默认", + "iconName": "chevron_right", + "requestedSize": 32, + "sourceType": "theme-svg", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/scalable/actions/chevron_right.svg", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_touch_paginate_next__chevron_right__32.svg", + "projectAsset": "app/src/assets/gmoccapy-icons/img_touch_paginate_next__chevron_right__32.svg", + "signals": [], + "notes": "仅按钮过多时显示" + }, + { + "category": "对刀/坐标设定按钮栏", + "source": "Python 动态", + "buttonId": "previous_button", + "label": "上一组 Touch Off 按钮", + "tooltip": "Press to display previous homing button", + "imageId": "img_touch_paginate_prev", + "imageRole": "动态按钮图标", + "stateOrVariant": "默认", + "iconName": "chevron_left", + "requestedSize": 32, + "sourceType": "theme-svg", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/scalable/actions/chevron_left.svg", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_touch_paginate_prev__chevron_left__32.svg", + "projectAsset": "app/src/assets/gmoccapy-icons/img_touch_paginate_prev__chevron_left__32.svg", + "signals": [], + "notes": "仅轴数大于 8 时显示" + }, + { + "category": "对刀/坐标设定按钮栏", + "source": "Python 动态", + "buttonId": "touch_a", + "label": "A 轴 Touch Off", + "tooltip": "Press to set touch off value for axis A", + "imageId": "img_touch_a", + "imageRole": "动态按钮图标", + "stateOrVariant": "默认", + "iconName": "touch_a", + "requestedSize": 48, + "sourceType": "theme-exact-png", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/48x48/actions/touch_a.png", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_touch_a__touch_a__48.png", + "projectAsset": "app/src/assets/gmoccapy-icons/img_touch_a__touch_a__48.png", + "signals": [], + "notes": "当前 XYZAB 生成" + }, + { + "category": "对刀/坐标设定按钮栏", + "source": "Python 动态", + "buttonId": "touch_b", + "label": "B 轴 Touch Off", + "tooltip": "Press to set touch off value for axis B", + "imageId": "img_touch_b", + "imageRole": "动态按钮图标", + "stateOrVariant": "默认", + "iconName": "touch_b", + "requestedSize": 48, + "sourceType": "theme-exact-png", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/48x48/actions/touch_b.png", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_touch_b__touch_b__48.png", + "projectAsset": "app/src/assets/gmoccapy-icons/img_touch_b__touch_b__48.png", + "signals": [], + "notes": "当前 XYZAB 生成" + }, + { + "category": "对刀/坐标设定按钮栏", + "source": "Python 动态", + "buttonId": "touch_back", + "label": "返回主按钮栏", + "tooltip": "Press to return to main button list", + "imageId": "img_touch_menu_close", + "imageRole": "动态按钮图标", + "stateOrVariant": "默认", + "iconName": "back_to_app", + "requestedSize": 48, + "sourceType": "theme-svg", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/scalable/actions/back_to_app.svg", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_touch_menu_close__back_to_app__48.svg", + "projectAsset": "app/src/assets/gmoccapy-icons/img_touch_menu_close__back_to_app__48.svg", + "signals": [], + "notes": "_make_touch_button" + }, + { + "category": "对刀/坐标设定按钮栏", + "source": "Python 动态", + "buttonId": "touch_x", + "label": "X 轴 Touch Off", + "tooltip": "Press to set touch off value for axis X", + "imageId": "img_touch_x", + "imageRole": "动态按钮图标", + "stateOrVariant": "默认", + "iconName": "touch_x", + "requestedSize": 48, + "sourceType": "theme-exact-png", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/48x48/actions/touch_x.png", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_touch_x__touch_x__48.png", + "projectAsset": "app/src/assets/gmoccapy-icons/img_touch_x__touch_x__48.png", + "signals": [], + "notes": "当前 XYZAB 生成" + }, + { + "category": "对刀/坐标设定按钮栏", + "source": "Python 动态", + "buttonId": "touch_y", + "label": "Y 轴 Touch Off", + "tooltip": "Press to set touch off value for axis Y", + "imageId": "img_touch_y", + "imageRole": "动态按钮图标", + "stateOrVariant": "默认", + "iconName": "touch_y", + "requestedSize": 48, + "sourceType": "theme-exact-png", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/48x48/actions/touch_y.png", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_touch_y__touch_y__48.png", + "projectAsset": "app/src/assets/gmoccapy-icons/img_touch_y__touch_y__48.png", + "signals": [], + "notes": "当前 XYZAB 生成" + }, + { + "category": "对刀/坐标设定按钮栏", + "source": "Python 动态", + "buttonId": "touch_z", + "label": "Z 轴 Touch Off", + "tooltip": "Press to set touch off value for axis Z", + "imageId": "img_touch_z", + "imageRole": "动态按钮图标", + "stateOrVariant": "默认", + "iconName": "touch_z", + "requestedSize": 48, + "sourceType": "theme-exact-png", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/48x48/actions/touch_z.png", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_touch_z__touch_z__48.png", + "projectAsset": "app/src/assets/gmoccapy-icons/img_touch_z__touch_z__48.png", + "signals": [], + "notes": "当前 XYZAB 生成" + }, + { + "category": "手动/Jog 面板", + "source": "Glade 静态", + "buttonId": "chk_ignore_limits", + "label": "Ignore limits", + "tooltip": "", + "imageId": "", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "", + "requestedSize": null, + "sourceType": "none", + "sourcePath": "", + "copiedFile": null, + "projectAsset": null, + "signals": [ + "toggled:on_chk_ignore_limits_toggled" + ], + "notes": "" + }, + { + "category": "手动/Jog 面板", + "source": "运行时状态", + "buttonId": "tbtn_turtle_jog", + "label": "慢速 Jog", + "tooltip": "", + "imageId": "img_turtle_jog", + "imageRole": "慢速 Jog 图标", + "stateOrVariant": "active", + "iconName": "jog_speed_slow", + "requestedSize": 32, + "sourceType": "theme-exact-png", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/32x32/actions/jog_speed_slow.png", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_turtle_jog__jog_speed_slow__32.png", + "projectAsset": "app/src/assets/gmoccapy-icons/img_turtle_jog__jog_speed_slow__32.png", + "signals": [], + "notes": "on_tbtn_turtle_jog_toggled" + }, + { + "category": "手动/Jog 面板", + "source": "运行时状态", + "buttonId": "tbtn_turtle_jog", + "label": "快速 Jog", + "tooltip": "", + "imageId": "img_rabbit_jog", + "imageRole": "快速 Jog 图标", + "stateOrVariant": "inactive", + "iconName": "jog_speed_fast", + "requestedSize": 32, + "sourceType": "theme-exact-png", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/32x32/actions/jog_speed_fast.png", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_rabbit_jog__jog_speed_fast__32.png", + "projectAsset": "app/src/assets/gmoccapy-icons/img_rabbit_jog__jog_speed_fast__32.png", + "signals": [], + "notes": "on_tbtn_turtle_jog_toggled" + }, + { + "category": "手动/Jog 面板", + "source": "Glade 静态", + "buttonId": "tbtn_turtle_jog", + "label": "", + "tooltip": "", + "imageId": "img_rabbit_jog", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "jog_speed_fast", + "requestedSize": 32, + "sourceType": "theme-exact-png", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/32x32/actions/jog_speed_fast.png", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_rabbit_jog__jog_speed_fast__32.png", + "projectAsset": "app/src/assets/gmoccapy-icons/img_rabbit_jog__jog_speed_fast__32.png", + "signals": [ + "toggled:on_tbtn_turtle_jog_toggled" + ], + "notes": "" + }, + { + "category": "Jog 增量选择栏", + "source": "Python 动态", + "buttonId": "rbt_0", + "label": "Continuous", + "tooltip": "Continuous jog", + "imageId": "img_continuous", + "imageRole": "动态按钮图标", + "stateOrVariant": "默认", + "iconName": "jog_continuous", + "requestedSize": 24, + "sourceType": "theme-exact-png", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/24x24/actions/jog_continuous.png", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_continuous__jog_continuous__24.png", + "projectAsset": "app/src/assets/gmoccapy-icons/img_continuous__jog_continuous__24.png", + "signals": [], + "notes": "连续 Jog 唯一带图标" + }, + { + "category": "Jog 增量选择栏", + "source": "Python 动态", + "buttonId": "rbt_1", + "label": "1.000 mm", + "tooltip": "", + "imageId": "", + "imageRole": "无图标", + "stateOrVariant": "默认", + "iconName": "", + "requestedSize": null, + "sourceType": "none", + "sourcePath": "", + "copiedFile": null, + "projectAsset": null, + "signals": [], + "notes": "增量按钮使用文字,无图标" + }, + { + "category": "Jog 增量选择栏", + "source": "Python 动态", + "buttonId": "rbt_2", + "label": "0.100 mm", + "tooltip": "", + "imageId": "", + "imageRole": "无图标", + "stateOrVariant": "默认", + "iconName": "", + "requestedSize": null, + "sourceType": "none", + "sourcePath": "", + "copiedFile": null, + "projectAsset": null, + "signals": [], + "notes": "增量按钮使用文字,无图标" + }, + { + "category": "Jog 增量选择栏", + "source": "Python 动态", + "buttonId": "rbt_3", + "label": "0.010 mm", + "tooltip": "", + "imageId": "", + "imageRole": "无图标", + "stateOrVariant": "默认", + "iconName": "", + "requestedSize": null, + "sourceType": "none", + "sourcePath": "", + "copiedFile": null, + "projectAsset": null, + "signals": [], + "notes": "增量按钮使用文字,无图标" + }, + { + "category": "Jog 增量选择栏", + "source": "Python 动态", + "buttonId": "rbt_4", + "label": "0.001 mm", + "tooltip": "", + "imageId": "", + "imageRole": "无图标", + "stateOrVariant": "默认", + "iconName": "", + "requestedSize": null, + "sourceType": "none", + "sourcePath": "", + "copiedFile": null, + "projectAsset": null, + "signals": [], + "notes": "增量按钮使用文字,无图标" + }, + { + "category": "Jog 增量选择栏", + "source": "Python 动态", + "buttonId": "rbt_5", + "label": "1.2345 in", + "tooltip": "", + "imageId": "", + "imageRole": "无图标", + "stateOrVariant": "默认", + "iconName": "", + "requestedSize": null, + "sourceType": "none", + "sourcePath": "", + "copiedFile": null, + "projectAsset": null, + "signals": [], + "notes": "增量按钮使用文字,无图标" + }, + { + "category": "Jog 轴按钮", + "source": "Python 动态", + "buttonId": "a+", + "label": "A+", + "tooltip": "Press to jog axis A", + "imageId": "", + "imageRole": "无图标", + "stateOrVariant": "默认", + "iconName": "", + "requestedSize": null, + "sourceType": "none", + "sourcePath": "", + "copiedFile": null, + "projectAsset": null, + "signals": [], + "notes": "轴 Jog 按钮使用文字,无图标" + }, + { + "category": "Jog 轴按钮", + "source": "Python 动态", + "buttonId": "a-", + "label": "A-", + "tooltip": "Press to jog axis A", + "imageId": "", + "imageRole": "无图标", + "stateOrVariant": "默认", + "iconName": "", + "requestedSize": null, + "sourceType": "none", + "sourcePath": "", + "copiedFile": null, + "projectAsset": null, + "signals": [], + "notes": "轴 Jog 按钮使用文字,无图标" + }, + { + "category": "Jog 轴按钮", + "source": "Python 动态", + "buttonId": "b+", + "label": "B+", + "tooltip": "Press to jog axis B", + "imageId": "", + "imageRole": "无图标", + "stateOrVariant": "默认", + "iconName": "", + "requestedSize": null, + "sourceType": "none", + "sourcePath": "", + "copiedFile": null, + "projectAsset": null, + "signals": [], + "notes": "轴 Jog 按钮使用文字,无图标" + }, + { + "category": "Jog 轴按钮", + "source": "Python 动态", + "buttonId": "b-", + "label": "B-", + "tooltip": "Press to jog axis B", + "imageId": "", + "imageRole": "无图标", + "stateOrVariant": "默认", + "iconName": "", + "requestedSize": null, + "sourceType": "none", + "sourcePath": "", + "copiedFile": null, + "projectAsset": null, + "signals": [], + "notes": "轴 Jog 按钮使用文字,无图标" + }, + { + "category": "Jog 轴按钮", + "source": "Python 动态", + "buttonId": "x+", + "label": "X+", + "tooltip": "Press to jog axis X", + "imageId": "", + "imageRole": "无图标", + "stateOrVariant": "默认", + "iconName": "", + "requestedSize": null, + "sourceType": "none", + "sourcePath": "", + "copiedFile": null, + "projectAsset": null, + "signals": [], + "notes": "轴 Jog 按钮使用文字,无图标" + }, + { + "category": "Jog 轴按钮", + "source": "Python 动态", + "buttonId": "x-", + "label": "X-", + "tooltip": "Press to jog axis X", + "imageId": "", + "imageRole": "无图标", + "stateOrVariant": "默认", + "iconName": "", + "requestedSize": null, + "sourceType": "none", + "sourcePath": "", + "copiedFile": null, + "projectAsset": null, + "signals": [], + "notes": "轴 Jog 按钮使用文字,无图标" + }, + { + "category": "Jog 轴按钮", + "source": "Python 动态", + "buttonId": "y+", + "label": "Y+", + "tooltip": "Press to jog axis Y", + "imageId": "", + "imageRole": "无图标", + "stateOrVariant": "默认", + "iconName": "", + "requestedSize": null, + "sourceType": "none", + "sourcePath": "", + "copiedFile": null, + "projectAsset": null, + "signals": [], + "notes": "轴 Jog 按钮使用文字,无图标" + }, + { + "category": "Jog 轴按钮", + "source": "Python 动态", + "buttonId": "y-", + "label": "Y-", + "tooltip": "Press to jog axis Y", + "imageId": "", + "imageRole": "无图标", + "stateOrVariant": "默认", + "iconName": "", + "requestedSize": null, + "sourceType": "none", + "sourcePath": "", + "copiedFile": null, + "projectAsset": null, + "signals": [], + "notes": "轴 Jog 按钮使用文字,无图标" + }, + { + "category": "Jog 轴按钮", + "source": "Python 动态", + "buttonId": "z+", + "label": "Z+", + "tooltip": "Press to jog axis Z", + "imageId": "", + "imageRole": "无图标", + "stateOrVariant": "默认", + "iconName": "", + "requestedSize": null, + "sourceType": "none", + "sourcePath": "", + "copiedFile": null, + "projectAsset": null, + "signals": [], + "notes": "轴 Jog 按钮使用文字,无图标" + }, + { + "category": "Jog 轴按钮", + "source": "Python 动态", + "buttonId": "z-", + "label": "Z-", + "tooltip": "Press to jog axis Z", + "imageId": "", + "imageRole": "无图标", + "stateOrVariant": "默认", + "iconName": "", + "requestedSize": null, + "sourceType": "none", + "sourcePath": "", + "copiedFile": null, + "projectAsset": null, + "signals": [], + "notes": "轴 Jog 按钮使用文字,无图标" + }, + { + "category": "Jog 关节按钮", + "source": "Python 动态", + "buttonId": "0+", + "label": "0+", + "tooltip": "Press to jog joint 0", + "imageId": "", + "imageRole": "无图标", + "stateOrVariant": "默认", + "iconName": "", + "requestedSize": null, + "sourceType": "none", + "sourcePath": "", + "copiedFile": null, + "projectAsset": null, + "signals": [], + "notes": "trivial kinematics 时不创建;非平凡运动学才出现" + }, + { + "category": "Jog 关节按钮", + "source": "Python 动态", + "buttonId": "0-", + "label": "0-", + "tooltip": "Press to jog joint 0", + "imageId": "", + "imageRole": "无图标", + "stateOrVariant": "默认", + "iconName": "", + "requestedSize": null, + "sourceType": "none", + "sourcePath": "", + "copiedFile": null, + "projectAsset": null, + "signals": [], + "notes": "trivial kinematics 时不创建;非平凡运动学才出现" + }, + { + "category": "Jog 关节按钮", + "source": "Python 动态", + "buttonId": "1+", + "label": "1+", + "tooltip": "Press to jog joint 1", + "imageId": "", + "imageRole": "无图标", + "stateOrVariant": "默认", + "iconName": "", + "requestedSize": null, + "sourceType": "none", + "sourcePath": "", + "copiedFile": null, + "projectAsset": null, + "signals": [], + "notes": "trivial kinematics 时不创建;非平凡运动学才出现" + }, + { + "category": "Jog 关节按钮", + "source": "Python 动态", + "buttonId": "1-", + "label": "1-", + "tooltip": "Press to jog joint 1", + "imageId": "", + "imageRole": "无图标", + "stateOrVariant": "默认", + "iconName": "", + "requestedSize": null, + "sourceType": "none", + "sourcePath": "", + "copiedFile": null, + "projectAsset": null, + "signals": [], + "notes": "trivial kinematics 时不创建;非平凡运动学才出现" + }, + { + "category": "Jog 关节按钮", + "source": "Python 动态", + "buttonId": "2+", + "label": "2+", + "tooltip": "Press to jog joint 2", + "imageId": "", + "imageRole": "无图标", + "stateOrVariant": "默认", + "iconName": "", + "requestedSize": null, + "sourceType": "none", + "sourcePath": "", + "copiedFile": null, + "projectAsset": null, + "signals": [], + "notes": "trivial kinematics 时不创建;非平凡运动学才出现" + }, + { + "category": "Jog 关节按钮", + "source": "Python 动态", + "buttonId": "2-", + "label": "2-", + "tooltip": "Press to jog joint 2", + "imageId": "", + "imageRole": "无图标", + "stateOrVariant": "默认", + "iconName": "", + "requestedSize": null, + "sourceType": "none", + "sourcePath": "", + "copiedFile": null, + "projectAsset": null, + "signals": [], + "notes": "trivial kinematics 时不创建;非平凡运动学才出现" + }, + { + "category": "Jog 关节按钮", + "source": "Python 动态", + "buttonId": "3+", + "label": "3+", + "tooltip": "Press to jog joint 3", + "imageId": "", + "imageRole": "无图标", + "stateOrVariant": "默认", + "iconName": "", + "requestedSize": null, + "sourceType": "none", + "sourcePath": "", + "copiedFile": null, + "projectAsset": null, + "signals": [], + "notes": "trivial kinematics 时不创建;非平凡运动学才出现" + }, + { + "category": "Jog 关节按钮", + "source": "Python 动态", + "buttonId": "3-", + "label": "3-", + "tooltip": "Press to jog joint 3", + "imageId": "", + "imageRole": "无图标", + "stateOrVariant": "默认", + "iconName": "", + "requestedSize": null, + "sourceType": "none", + "sourcePath": "", + "copiedFile": null, + "projectAsset": null, + "signals": [], + "notes": "trivial kinematics 时不创建;非平凡运动学才出现" + }, + { + "category": "Jog 关节按钮", + "source": "Python 动态", + "buttonId": "4+", + "label": "4+", + "tooltip": "Press to jog joint 4", + "imageId": "", + "imageRole": "无图标", + "stateOrVariant": "默认", + "iconName": "", + "requestedSize": null, + "sourceType": "none", + "sourcePath": "", + "copiedFile": null, + "projectAsset": null, + "signals": [], + "notes": "trivial kinematics 时不创建;非平凡运动学才出现" + }, + { + "category": "Jog 关节按钮", + "source": "Python 动态", + "buttonId": "4-", + "label": "4-", + "tooltip": "Press to jog joint 4", + "imageId": "", + "imageRole": "无图标", + "stateOrVariant": "默认", + "iconName": "", + "requestedSize": null, + "sourceType": "none", + "sourcePath": "", + "copiedFile": null, + "projectAsset": null, + "signals": [], + "notes": "trivial kinematics 时不创建;非平凡运动学才出现" + }, + { + "category": "冷却/主轴控制", + "source": "运行时状态", + "buttonId": "rbt_forward", + "label": "主轴正转中", + "tooltip": "", + "imageId": "img_spindle_forward_on", + "imageRole": "正转 active 图标", + "stateOrVariant": "active", + "iconName": "spindle_right_on", + "requestedSize": 48, + "sourceType": "theme-exact-png", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/48x48/actions/spindle_right_on.png", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_spindle_forward_on__spindle_right_on__48.png", + "projectAsset": "app/src/assets/gmoccapy-icons/img_spindle_forward_on__spindle_right_on__48.png", + "signals": [], + "notes": "on_rbt_forward_released/clicked" + }, + { + "category": "冷却/主轴控制", + "source": "Glade 静态", + "buttonId": "rbt_forward", + "label": "", + "tooltip": "", + "imageId": "img_spindle_forward", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "spindle_right", + "requestedSize": 48, + "sourceType": "theme-exact-png", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/48x48/actions/spindle_right.png", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_spindle_forward__spindle_right__48.png", + "projectAsset": "app/src/assets/gmoccapy-icons/img_spindle_forward__spindle_right__48.png", + "signals": [ + "clicked:on_rbt_forward_clicked", + "released:on_rbt_forward_released" + ], + "notes": "" + }, + { + "category": "冷却/主轴控制", + "source": "运行时状态", + "buttonId": "rbt_reverse", + "label": "主轴反转中", + "tooltip": "", + "imageId": "img_spindle_reverse_on", + "imageRole": "反转 active 图标", + "stateOrVariant": "active", + "iconName": "spindle_left_on", + "requestedSize": 48, + "sourceType": "theme-exact-png", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/48x48/actions/spindle_left_on.png", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_spindle_reverse_on__spindle_left_on__48.png", + "projectAsset": "app/src/assets/gmoccapy-icons/img_spindle_reverse_on__spindle_left_on__48.png", + "signals": [], + "notes": "on_rbt_reverse_released/clicked" + }, + { + "category": "冷却/主轴控制", + "source": "Glade 静态", + "buttonId": "rbt_reverse", + "label": "", + "tooltip": "", + "imageId": "img_spindle_reverse", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "spindle_left", + "requestedSize": 48, + "sourceType": "theme-exact-png", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/48x48/actions/spindle_left.png", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_spindle_reverse__spindle_left__48.png", + "projectAsset": "app/src/assets/gmoccapy-icons/img_spindle_reverse__spindle_left__48.png", + "signals": [ + "clicked:on_rbt_reverse_clicked", + "released:on_rbt_reverse_released" + ], + "notes": "" + }, + { + "category": "冷却/主轴控制", + "source": "运行时状态", + "buttonId": "rbt_stop", + "label": "主轴停止已选中", + "tooltip": "", + "imageId": "img_spindle_stop_on", + "imageRole": "停止 active 图标", + "stateOrVariant": "active", + "iconName": "spindle_stop_on", + "requestedSize": 48, + "sourceType": "theme-exact-png", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/48x48/actions/spindle_stop_on.png", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_spindle_stop_on__spindle_stop_on__48.png", + "projectAsset": "app/src/assets/gmoccapy-icons/img_spindle_stop_on__spindle_stop_on__48.png", + "signals": [], + "notes": "on_rbt_stop_clicked" + }, + { + "category": "冷却/主轴控制", + "source": "运行时状态", + "buttonId": "rbt_stop", + "label": "主轴停止未选中", + "tooltip": "", + "imageId": "img_spindle_stop", + "imageRole": "停止 inactive 图标", + "stateOrVariant": "inactive", + "iconName": "spindle_stop", + "requestedSize": 48, + "sourceType": "theme-exact-png", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/48x48/actions/spindle_stop.png", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_spindle_stop__spindle_stop__48.png", + "projectAsset": "app/src/assets/gmoccapy-icons/img_spindle_stop__spindle_stop__48.png", + "signals": [], + "notes": "on_rbt_stop_clicked: widget inactive 时切回停止普通图标" + }, + { + "category": "冷却/主轴控制", + "source": "Glade 静态", + "buttonId": "rbt_stop", + "label": "", + "tooltip": "", + "imageId": "img_spindle_stop_on", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "spindle_stop_on", + "requestedSize": 48, + "sourceType": "theme-exact-png", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/48x48/actions/spindle_stop_on.png", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_spindle_stop_on__spindle_stop_on__48.png", + "projectAsset": "app/src/assets/gmoccapy-icons/img_spindle_stop_on__spindle_stop_on__48.png", + "signals": [ + "clicked:on_rbt_stop_clicked" + ], + "notes": "" + }, + { + "category": "冷却/主轴控制", + "source": "运行时状态", + "buttonId": "tbtn_flood", + "label": "冷却液开", + "tooltip": "", + "imageId": "img_coolant_on", + "imageRole": "Flood active 图标", + "stateOrVariant": "active", + "iconName": "coolant_flood_active", + "requestedSize": 48, + "sourceType": "theme-exact-png", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/48x48/actions/coolant_flood_active.png", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_coolant_on__coolant_flood_active__48.png", + "projectAsset": "app/src/assets/gmoccapy-icons/img_coolant_on__coolant_flood_active__48.png", + "signals": [], + "notes": "on_hal_status_flood_changed" + }, + { + "category": "冷却/主轴控制", + "source": "Glade 静态", + "buttonId": "tbtn_flood", + "label": "", + "tooltip": "", + "imageId": "img_coolant_off", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "coolant_flood_inactive", + "requestedSize": 48, + "sourceType": "theme-exact-png", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/48x48/actions/coolant_flood_inactive.png", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_coolant_off__coolant_flood_inactive__48.png", + "projectAsset": "app/src/assets/gmoccapy-icons/img_coolant_off__coolant_flood_inactive__48.png", + "signals": [ + "toggled:on_tbtn_flood_toggled" + ], + "notes": "" + }, + { + "category": "冷却/主轴控制", + "source": "运行时状态", + "buttonId": "tbtn_mist", + "label": "雾冷开", + "tooltip": "", + "imageId": "img_mist_on", + "imageRole": "Mist active 图标", + "stateOrVariant": "active", + "iconName": "coolant_mist_active", + "requestedSize": 48, + "sourceType": "theme-exact-png", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/48x48/actions/coolant_mist_active.png", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_mist_on__coolant_mist_active__48.png", + "projectAsset": "app/src/assets/gmoccapy-icons/img_mist_on__coolant_mist_active__48.png", + "signals": [], + "notes": "on_hal_status_mist_changed" + }, + { + "category": "冷却/主轴控制", + "source": "Glade 静态", + "buttonId": "tbtn_mist", + "label": "", + "tooltip": "", + "imageId": "img_mist_off", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "coolant_mist_inactive", + "requestedSize": 48, + "sourceType": "theme-exact-png", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/48x48/actions/coolant_mist_inactive.png", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_mist_off__coolant_mist_inactive__48.png", + "projectAsset": "app/src/assets/gmoccapy-icons/img_mist_off__coolant_mist_inactive__48.png", + "signals": [ + "toggled:on_tbtn_mist_toggled" + ], + "notes": "" + }, + { + "category": "预览/视图", + "source": "Glade 静态", + "buttonId": "btn_delete_view", + "label": "", + "tooltip": "clear plot", + "imageId": "img_tool_clear", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "clear", + "requestedSize": 24, + "sourceType": "theme-nearest-png", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/32x32/actions/clear.png", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_tool_clear__clear__24.png", + "projectAsset": "app/src/assets/gmoccapy-icons/img_tool_clear__clear__24.png", + "signals": [ + "clicked:on_btn_delete_view_clicked" + ], + "notes": "" + }, + { + "category": "预览/视图", + "source": "Glade 静态", + "buttonId": "btn_zoom_in", + "label": "", + "tooltip": "Zoom in", + "imageId": "img_zoom_in", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "zoom_in", + "requestedSize": 24, + "sourceType": "theme-nearest-png", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/32x32/actions/zoom_in.png", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_zoom_in__zoom_in__24.png", + "projectAsset": "app/src/assets/gmoccapy-icons/img_zoom_in__zoom_in__24.png", + "signals": [ + "clicked:on_btn_zoom_in_clicked" + ], + "notes": "" + }, + { + "category": "预览/视图", + "source": "Glade 静态", + "buttonId": "btn_zoom_out", + "label": "", + "tooltip": "Zoom out", + "imageId": "img_zoom_out", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "zoom_out", + "requestedSize": 24, + "sourceType": "theme-nearest-png", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/32x32/actions/zoom_out.png", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_zoom_out__zoom_out__24.png", + "projectAsset": "app/src/assets/gmoccapy-icons/img_zoom_out__zoom_out__24.png", + "signals": [ + "clicked:on_btn_zoom_out_clicked" + ], + "notes": "" + }, + { + "category": "预览/视图", + "source": "Glade 静态", + "buttonId": "rbt_view_p", + "label": "", + "tooltip": "view perspective", + "imageId": "img_view_p", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "tool_axis_p", + "requestedSize": 24, + "sourceType": "theme-exact-png", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/24x24/actions/tool_axis_p.png", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_view_p__tool_axis_p__24.png", + "projectAsset": "app/src/assets/gmoccapy-icons/img_view_p__tool_axis_p__24.png", + "signals": [ + "toggled:on_rbt_view_p_toggled" + ], + "notes": "" + }, + { + "category": "预览/视图", + "source": "Glade 静态", + "buttonId": "rbt_view_x", + "label": "", + "tooltip": "view along the X axis from positive to negative", + "imageId": "img_view_x", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "tool_axis_x", + "requestedSize": 24, + "sourceType": "theme-exact-png", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/24x24/actions/tool_axis_x.png", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_view_x__tool_axis_x__24.png", + "projectAsset": "app/src/assets/gmoccapy-icons/img_view_x__tool_axis_x__24.png", + "signals": [ + "toggled:on_rbt_view_x_toggled" + ], + "notes": "" + }, + { + "category": "预览/视图", + "source": "Glade 静态", + "buttonId": "rbt_view_y", + "label": "", + "tooltip": "view along the Y axis from positive to negative", + "imageId": "img_view_y", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "tool_axis_y", + "requestedSize": 24, + "sourceType": "theme-exact-png", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/24x24/actions/tool_axis_y.png", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_view_y__tool_axis_y__24.png", + "projectAsset": "app/src/assets/gmoccapy-icons/img_view_y__tool_axis_y__24.png", + "signals": [ + "toggled:on_rbt_view_y_toggled" + ], + "notes": "" + }, + { + "category": "预览/视图", + "source": "Glade 静态", + "buttonId": "rbt_view_y2", + "label": "", + "tooltip": "view along the Y axis from positive to negative as viewn for a back tool lathe", + "imageId": "img_view_y2", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "tool_axis_y_inv", + "requestedSize": 24, + "sourceType": "theme-exact-png", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/24x24/actions/tool_axis_y_inv.png", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_view_y2__tool_axis_y_inv__24.png", + "projectAsset": "app/src/assets/gmoccapy-icons/img_view_y2__tool_axis_y_inv__24.png", + "signals": [ + "toggled:on_rbt_view_y2_toggled" + ], + "notes": "" + }, + { + "category": "预览/视图", + "source": "Glade 静态", + "buttonId": "rbt_view_z", + "label": "", + "tooltip": "view along the Z axis from positive to negative", + "imageId": "img_view_z", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "tool_axis_z", + "requestedSize": 24, + "sourceType": "theme-exact-png", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/24x24/actions/tool_axis_z.png", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_view_z__tool_axis_z__24.png", + "projectAsset": "app/src/assets/gmoccapy-icons/img_view_z__tool_axis_z__24.png", + "signals": [ + "toggled:on_rbt_view_z_toggled" + ], + "notes": "" + }, + { + "category": "预览/视图", + "source": "Glade 静态", + "buttonId": "tbtn_view_dimension", + "label": "", + "tooltip": "Show or hide dimensions", + "imageId": "img_dimensions", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "dimensions", + "requestedSize": 24, + "sourceType": "theme-nearest-png", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/32x32/actions/dimensions.png", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_dimensions__dimensions__24.png", + "projectAsset": "app/src/assets/gmoccapy-icons/img_dimensions__dimensions__24.png", + "signals": [ + "toggled:on_tbtn_view_dimension_toggled" + ], + "notes": "" + }, + { + "category": "预览/视图", + "source": "Glade 静态", + "buttonId": "tbtn_view_tool_path", + "label": "", + "tooltip": "Show or hide tool path", + "imageId": "img_tool_path", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "toolpath", + "requestedSize": 24, + "sourceType": "theme-exact-png", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/24x24/actions/toolpath.png", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_tool_path__toolpath__24.png", + "projectAsset": "app/src/assets/gmoccapy-icons/img_tool_path__toolpath__24.png", + "signals": [ + "toggled:on_tbtn_view_tool_path_toggled" + ], + "notes": "" + }, + { + "category": "编辑器搜索/编辑", + "source": "Glade 静态", + "buttonId": "btn_comment", + "label": "", + "tooltip": "", + "imageId": "img_edit_comment", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "comment", + "requestedSize": 32, + "sourceType": "theme-exact-png", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/32x32/actions/comment.png", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_edit_comment__comment__32.png", + "projectAsset": "app/src/assets/gmoccapy-icons/img_edit_comment__comment__32.png", + "signals": [ + "clicked:on_btn_toggle_comment_clicked" + ], + "notes": "" + }, + { + "category": "编辑器搜索/编辑", + "source": "Glade 静态", + "buttonId": "btn_redo", + "label": "", + "tooltip": "Redo", + "imageId": "img_edit-redo", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "edit_redo", + "requestedSize": 32, + "sourceType": "theme-exact-png", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/32x32/actions/edit_redo.png", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_edit-redo__edit_redo__32.png", + "projectAsset": "app/src/assets/gmoccapy-icons/img_edit-redo__edit_redo__32.png", + "signals": [ + "clicked:on_btn_redo_clicked" + ], + "notes": "" + }, + { + "category": "编辑器搜索/编辑", + "source": "Glade 静态", + "buttonId": "btn_replace", + "label": "Replace", + "tooltip": "", + "imageId": "", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "", + "requestedSize": null, + "sourceType": "none", + "sourcePath": "", + "copiedFile": null, + "projectAsset": null, + "signals": [ + "clicked:on_btn_replace_clicked" + ], + "notes": "" + }, + { + "category": "编辑器搜索/编辑", + "source": "Glade 静态", + "buttonId": "btn_search_back", + "label": "Search / back", + "tooltip": "", + "imageId": "img_up", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "chevron_up", + "requestedSize": 24, + "sourceType": "theme-svg", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/scalable/actions/chevron_up.svg", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_up__chevron_up__24.svg", + "projectAsset": "app/src/assets/gmoccapy-icons/img_up__chevron_up__24.svg", + "signals": [ + "clicked:on_btn_search_back_clicked" + ], + "notes": "" + }, + { + "category": "编辑器搜索/编辑", + "source": "Glade 静态", + "buttonId": "btn_search_forward", + "label": "Search / fwd", + "tooltip": "", + "imageId": "img_down", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "chevron_down", + "requestedSize": 24, + "sourceType": "theme-svg", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/scalable/actions/chevron_down.svg", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_down__chevron_down__24.svg", + "projectAsset": "app/src/assets/gmoccapy-icons/img_down__chevron_down__24.svg", + "signals": [ + "clicked:on_btn_search_forward_clicked" + ], + "notes": "" + }, + { + "category": "编辑器搜索/编辑", + "source": "Glade 静态", + "buttonId": "btn_undo", + "label": "", + "tooltip": "Undo", + "imageId": "img_edit-undo", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "edit_undo", + "requestedSize": 32, + "sourceType": "theme-exact-png", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/32x32/actions/edit_undo.png", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_edit-undo__edit_undo__32.png", + "projectAsset": "app/src/assets/gmoccapy-icons/img_edit-undo__edit_undo__32.png", + "signals": [ + "clicked:on_btn_undo_clicked" + ], + "notes": "" + }, + { + "category": "编辑器搜索/编辑", + "source": "Glade 静态", + "buttonId": "chk_ignore_case", + "label": "Ignore Case", + "tooltip": "", + "imageId": "", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "", + "requestedSize": null, + "sourceType": "none", + "sourcePath": "", + "copiedFile": null, + "projectAsset": null, + "signals": [], + "notes": "" + }, + { + "category": "编辑器搜索/编辑", + "source": "Glade 静态", + "buttonId": "chk_replace_all", + "label": "Replace All", + "tooltip": "", + "imageId": "", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "", + "requestedSize": null, + "sourceType": "none", + "sourcePath": "", + "copiedFile": null, + "projectAsset": null, + "signals": [], + "notes": "" + }, + { + "category": "编辑页底部栏", + "source": "Glade 静态", + "buttonId": "btn_back_edit", + "label": "", + "tooltip": "Go back to main button list", + "imageId": "img_edit_menu_close", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "back_to_app", + "requestedSize": 48, + "sourceType": "theme-svg", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/scalable/actions/back_to_app.svg", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_edit_menu_close__back_to_app__48.svg", + "projectAsset": "app/src/assets/gmoccapy-icons/img_edit_menu_close__back_to_app__48.svg", + "signals": [ + "clicked:on_btn_back_clicked" + ], + "notes": "" + }, + { + "category": "编辑页底部栏", + "source": "Glade 静态", + "buttonId": "btn_calc", + "label": "", + "tooltip": "Show calculator", + "imageId": "img_edit_menu_calculator", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "calculator_open", + "requestedSize": 32, + "sourceType": "theme-exact-png", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/32x32/actions/calculator_open.png", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_edit_menu_calculator__calculator_open__32.png", + "projectAsset": "app/src/assets/gmoccapy-icons/img_edit_menu_calculator__calculator_open__32.png", + "signals": [ + "clicked:on_btn_show_calc_clicked" + ], + "notes": "" + }, + { + "category": "编辑页底部栏", + "source": "运行时状态", + "buttonId": "btn_keyb", + "label": "隐藏虚拟键盘", + "tooltip": "", + "imageId": "img_edit_menu_keyboard_hide", + "imageRole": "编辑页键盘隐藏图标", + "stateOrVariant": "keyboard shown", + "iconName": "keyboard_hide", + "requestedSize": 32, + "sourceType": "theme-nearest-png", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/48x48/actions/keyboard_hide.png", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_edit_menu_keyboard_hide__keyboard_hide__32.png", + "projectAsset": "app/src/assets/gmoccapy-icons/img_edit_menu_keyboard_hide__keyboard_hide__32.png", + "signals": [], + "notes": "on_ntb_info_switch_page" + }, + { + "category": "编辑页底部栏", + "source": "Glade 静态", + "buttonId": "btn_keyb", + "label": "", + "tooltip": "Show or hide the virtual keyboard", + "imageId": "img_edit_menu_keyboard", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "keyboard", + "requestedSize": 32, + "sourceType": "theme-nearest-png", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/48x48/actions/keyboard.png", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_edit_menu_keyboard__keyboard__32.png", + "projectAsset": "app/src/assets/gmoccapy-icons/img_edit_menu_keyboard__keyboard__32.png", + "signals": [ + "clicked:on_btn_show_kbd_clicked" + ], + "notes": "" + }, + { + "category": "编辑页底部栏", + "source": "Glade 静态", + "buttonId": "btn_new", + "label": "", + "tooltip": "clear the edit field and make a new file", + "imageId": "img_edit_menu_new", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "new_document", + "requestedSize": 32, + "sourceType": "theme-svg", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/scalable/actions/new_document.svg", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_edit_menu_new__new_document__32.svg", + "projectAsset": "app/src/assets/gmoccapy-icons/img_edit_menu_new__new_document__32.svg", + "signals": [ + "clicked:on_btn_new_clicked" + ], + "notes": "" + }, + { + "category": "编辑页底部栏", + "source": "Glade 静态", + "buttonId": "btn_reload_edit", + "label": "", + "tooltip": "Reload file", + "imageId": "img_edit_menu_reload", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "refresh", + "requestedSize": 32, + "sourceType": "theme-nearest-png", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/48x48/actions/refresh.png", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_edit_menu_reload__refresh__32.png", + "projectAsset": "app/src/assets/gmoccapy-icons/img_edit_menu_reload__refresh__32.png", + "signals": [], + "notes": "" + }, + { + "category": "编辑页底部栏", + "source": "Glade 静态", + "buttonId": "btn_save", + "label": "", + "tooltip": "save the file using the original name", + "imageId": "img_edit_menu_save", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "save", + "requestedSize": 32, + "sourceType": "theme-nearest-png", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/48x48/actions/save.png", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_edit_menu_save__save__32.png", + "projectAsset": "app/src/assets/gmoccapy-icons/img_edit_menu_save__save__32.png", + "signals": [], + "notes": "" + }, + { + "category": "编辑页底部栏", + "source": "Glade 静态", + "buttonId": "btn_save_as", + "label": "", + "tooltip": "save the file with a new name", + "imageId": "img_edit_menu_save_as", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "save_as", + "requestedSize": 32, + "sourceType": "theme-nearest-png", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/48x48/actions/save_as.png", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_edit_menu_save_as__save_as__32.png", + "projectAsset": "app/src/assets/gmoccapy-icons/img_edit_menu_save_as__save_as__32.png", + "signals": [], + "notes": "" + }, + { + "category": "编辑页底部栏", + "source": "Glade 静态", + "buttonId": "tbtn_split_view", + "label": "", + "tooltip": "Show preview as split view", + "imageId": "img_split_view", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "split_view", + "requestedSize": 32, + "sourceType": "theme-exact-png", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/32x32/actions/split_view.png", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_split_view__split_view__32.png", + "projectAsset": "app/src/assets/gmoccapy-icons/img_split_view__split_view__32.png", + "signals": [ + "toggled:on_tbtn_split_view_toggled" + ], + "notes": "" + }, + { + "category": "刀具页底部栏", + "source": "Glade 静态", + "buttonId": "btn_back_tool", + "label": "", + "tooltip": "Go back to main button list", + "imageId": "img_back_tool", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "back_to_app", + "requestedSize": 48, + "sourceType": "theme-svg", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/scalable/actions/back_to_app.svg", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_back_tool__back_to_app__48.svg", + "projectAsset": "app/src/assets/gmoccapy-icons/img_back_tool__back_to_app__48.svg", + "signals": [ + "clicked:on_btn_back_clicked" + ], + "notes": "" + }, + { + "category": "刀具页底部栏", + "source": "Glade 静态", + "buttonId": "btn_change_tool", + "label": "", + "tooltip": "change tool to the selected one", + "imageId": "img_toolchange", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "mill_tool_change", + "requestedSize": 48, + "sourceType": "theme-exact-png", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/48x48/actions/mill_tool_change.png", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_toolchange__mill_tool_change__48.png", + "projectAsset": "app/src/assets/gmoccapy-icons/img_toolchange__mill_tool_change__48.png", + "signals": [ + "clicked:on_btn_selected_tool_clicked" + ], + "notes": "" + }, + { + "category": "刀具页底部栏", + "source": "Glade 静态", + "buttonId": "btn_index_tool", + "label": "", + "tooltip": "change tool with the command M61 Q?, no machine move will be done", + "imageId": "img_index_tool", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "mill_tool_set_num", + "requestedSize": 48, + "sourceType": "theme-svg", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/scalable/actions/mill_tool_set_num.svg", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_index_tool__mill_tool_set_num__48.svg", + "projectAsset": "app/src/assets/gmoccapy-icons/img_index_tool__mill_tool_set_num__48.svg", + "signals": [ + "clicked:on_btn_selected_tool_clicked" + ], + "notes": "" + }, + { + "category": "刀具页底部栏", + "source": "Glade 静态", + "buttonId": "btn_select_tool_by_no", + "label": "", + "tooltip": "Select a tool by number", + "imageId": "img_tool_by_no", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "mill_tool_change_num", + "requestedSize": 48, + "sourceType": "theme-svg", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/scalable/actions/mill_tool_change_num.svg", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_tool_by_no__mill_tool_change_num__48.svg", + "projectAsset": "app/src/assets/gmoccapy-icons/img_tool_by_no__mill_tool_change_num__48.svg", + "signals": [ + "clicked:on_btn_select_tool_by_no_clicked" + ], + "notes": "" + }, + { + "category": "刀具页底部栏", + "source": "Glade 静态", + "buttonId": "btn_tool_touchoff_x", + "label": "", + "tooltip": "touch off the tool and set the value to the tool table", + "imageId": "", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "", + "requestedSize": null, + "sourceType": "none", + "sourcePath": "", + "copiedFile": null, + "projectAsset": null, + "signals": [ + "clicked:on_btn_tool_touchoff_clicked" + ], + "notes": "" + }, + { + "category": "刀具页底部栏", + "source": "Glade 静态", + "buttonId": "btn_tool_touchoff_z", + "label": "", + "tooltip": "touch off the tool and set the value to the tool table", + "imageId": "", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "", + "requestedSize": null, + "sourceType": "none", + "sourcePath": "", + "copiedFile": null, + "projectAsset": null, + "signals": [ + "clicked:on_btn_tool_touchoff_clicked" + ], + "notes": "" + }, + { + "category": "文件选择栏", + "source": "Glade 静态", + "buttonId": "btn_back_file_load", + "label": "", + "tooltip": "Close without returning a file path", + "imageId": "img_back_file_load", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "back_to_app", + "requestedSize": 48, + "sourceType": "theme-svg", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/scalable/actions/back_to_app.svg", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_back_file_load__back_to_app__48.svg", + "projectAsset": "app/src/assets/gmoccapy-icons/img_back_file_load__back_to_app__48.svg", + "signals": [ + "clicked:on_btn_back_clicked" + ], + "notes": "" + }, + { + "category": "文件选择栏", + "source": "Glade 静态", + "buttonId": "btn_dir_up", + "label": "", + "tooltip": "Move to parent directory", + "imageId": "img_dir_up", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "chevron_up", + "requestedSize": 32, + "sourceType": "theme-svg", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/scalable/actions/chevron_up.svg", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_dir_up__chevron_up__32.svg", + "projectAsset": "app/src/assets/gmoccapy-icons/img_dir_up__chevron_up__32.svg", + "signals": [ + "clicked:on_btn_dir_up_clicked" + ], + "notes": "" + }, + { + "category": "文件选择栏", + "source": "Glade 静态", + "buttonId": "btn_home", + "label": "", + "tooltip": "Move to your home directory", + "imageId": "img_home", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "home_folder", + "requestedSize": 32, + "sourceType": "theme-svg", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/scalable/actions/home_folder.svg", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_home__home_folder__32.svg", + "projectAsset": "app/src/assets/gmoccapy-icons/img_home__home_folder__32.svg", + "signals": [ + "clicked:on_btn_home_clicked" + ], + "notes": "" + }, + { + "category": "文件选择栏", + "source": "Glade 静态", + "buttonId": "btn_jump_to", + "label": "", + "tooltip": "Jump to user defined directory", + "imageId": "img_jump_to", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "user_defined_folder", + "requestedSize": 32, + "sourceType": "theme-svg", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/scalable/actions/user_defined_folder.svg", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_jump_to__user_defined_folder__32.svg", + "projectAsset": "app/src/assets/gmoccapy-icons/img_jump_to__user_defined_folder__32.svg", + "signals": [ + "clicked:on_btn_jump_to_clicked" + ], + "notes": "" + }, + { + "category": "文件选择栏", + "source": "Glade 静态", + "buttonId": "btn_reload_dir", + "label": "", + "tooltip": "Refresh directory", + "imageId": "img_refresh_dir", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "refresh", + "requestedSize": 32, + "sourceType": "theme-nearest-png", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/48x48/actions/refresh.png", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_refresh_dir__refresh__32.png", + "projectAsset": "app/src/assets/gmoccapy-icons/img_refresh_dir__refresh__32.png", + "signals": [ + "clicked:on_btn_refresh_dir_clicked" + ], + "notes": "" + }, + { + "category": "文件选择栏", + "source": "Glade 静态", + "buttonId": "btn_sel_next", + "label": "", + "tooltip": "Select the next file", + "imageId": "img_sel_next", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "chevron_right", + "requestedSize": 32, + "sourceType": "theme-svg", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/scalable/actions/chevron_right.svg", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_sel_next__chevron_right__32.svg", + "projectAsset": "app/src/assets/gmoccapy-icons/img_sel_next__chevron_right__32.svg", + "signals": [ + "clicked:on_btn_sel_next_clicked" + ], + "notes": "" + }, + { + "category": "文件选择栏", + "source": "Glade 静态", + "buttonId": "btn_sel_prev", + "label": "", + "tooltip": "Select the previous file", + "imageId": "img_sel_prev", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "chevron_left", + "requestedSize": 32, + "sourceType": "theme-svg", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/scalable/actions/chevron_left.svg", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_sel_prev__chevron_left__32.svg", + "projectAsset": "app/src/assets/gmoccapy-icons/img_sel_prev__chevron_left__32.svg", + "signals": [ + "clicked:on_btn_sel_prev_clicked" + ], + "notes": "" + }, + { + "category": "文件选择栏", + "source": "Glade 静态", + "buttonId": "btn_select", + "label": "", + "tooltip": "select the highlighted file and return the path", + "imageId": "img_select", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "select_file", + "requestedSize": 32, + "sourceType": "theme-nearest-png", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/48x48/actions/select_file.png", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_select__select_file__32.png", + "projectAsset": "app/src/assets/gmoccapy-icons/img_select__select_file__32.png", + "signals": [ + "clicked:on_btn_select_clicked" + ], + "notes": "" + }, + { + "category": "文件选择栏", + "source": "Glade 静态", + "buttonId": "tbtn_sort", + "label": "Sort by / date", + "tooltip": "Sort files by date, newest first", + "imageId": "", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "", + "requestedSize": null, + "sourceType": "none", + "sourcePath": "", + "copiedFile": null, + "projectAsset": null, + "signals": [ + "toggled:on_tbtn_sort_toggled" + ], + "notes": "" + }, + { + "category": "内嵌 ToolEdit 控件", + "source": "内嵌控件", + "buttonId": "tooldedit.add", + "label": "新增刀具", + "tooltip": "Add new tool", + "imageId": "img_tool_add", + "imageRole": "动态按钮图标", + "stateOrVariant": "默认", + "iconName": "add", + "requestedSize": 32, + "sourceType": "theme-exact-png", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/32x32/actions/add.png", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_tool_add__add__32.png", + "projectAsset": "app/src/assets/gmoccapy-icons/img_tool_add__add__32.png", + "signals": [], + "notes": "Python 改造 ToolEdit" + }, + { + "category": "内嵌 ToolEdit 控件", + "source": "内嵌控件", + "buttonId": "tooldedit.apply", + "label": "保存刀具表", + "tooltip": "Save tool table to file", + "imageId": "img_tool_save", + "imageRole": "动态按钮图标", + "stateOrVariant": "默认", + "iconName": "save", + "requestedSize": 32, + "sourceType": "theme-nearest-png", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/48x48/actions/save.png", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_tool_save__save__32.png", + "projectAsset": "app/src/assets/gmoccapy-icons/img_tool_save__save__32.png", + "signals": [], + "notes": "Python 改造 ToolEdit" + }, + { + "category": "内嵌 ToolEdit 控件", + "source": "内嵌控件", + "buttonId": "tooldedit.calculator", + "label": "刀具表计算器", + "tooltip": "Use calculator to edit numeric values", + "imageId": "img_tool_calculator", + "imageRole": "动态按钮图标", + "stateOrVariant": "默认", + "iconName": "calculator_open", + "requestedSize": 32, + "sourceType": "theme-exact-png", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/32x32/actions/calculator_open.png", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_tool_calculator__calculator_open__32.png", + "projectAsset": "app/src/assets/gmoccapy-icons/img_tool_calculator__calculator_open__32.png", + "signals": [], + "notes": "Python 改造 ToolEdit" + }, + { + "category": "内嵌 ToolEdit 控件", + "source": "内嵌控件", + "buttonId": "tooldedit.delete", + "label": "删除选中刀具", + "tooltip": "Delete selected tool", + "imageId": "img_tool_delete", + "imageRole": "动态按钮图标", + "stateOrVariant": "默认", + "iconName": "delete", + "requestedSize": 32, + "sourceType": "theme-exact-png", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/32x32/actions/delete.png", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_tool_delete__delete__32.png", + "projectAsset": "app/src/assets/gmoccapy-icons/img_tool_delete__delete__32.png", + "signals": [], + "notes": "Python 改造 ToolEdit" + }, + { + "category": "内嵌 ToolEdit 控件", + "source": "内嵌控件", + "buttonId": "tooldedit.reload", + "label": "重载刀具表", + "tooltip": "Reload tool table from file", + "imageId": "img_tool_reload", + "imageRole": "动态按钮图标", + "stateOrVariant": "默认", + "iconName": "refresh", + "requestedSize": 32, + "sourceType": "theme-nearest-png", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/48x48/actions/refresh.png", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_tool_reload__refresh__32.png", + "projectAsset": "app/src/assets/gmoccapy-icons/img_tool_reload__refresh__32.png", + "signals": [], + "notes": "Python 改造 ToolEdit" + }, + { + "category": "内嵌 OffsetPage 控件", + "source": "内嵌控件", + "buttonId": "offsetpage.calculator", + "label": "坐标偏置计算器", + "tooltip": "Use calculator to edit numeric values", + "imageId": "img_offset_calculator", + "imageRole": "动态按钮图标", + "stateOrVariant": "默认", + "iconName": "calculator_open", + "requestedSize": 32, + "sourceType": "theme-exact-png", + "sourcePath": "linuxcnc/share/gmoccapy/icons/classic/32x32/actions/calculator_open.png", + "copiedFile": "work/working3/gmoccapy_button_icons/files/img_offset_calculator__calculator_open__32.png", + "projectAsset": "app/src/assets/gmoccapy-icons/img_offset_calculator__calculator_open__32.png", + "signals": [], + "notes": "Python 改造 OffsetPage" + }, + { + "category": "内嵌 OffsetPage 控件", + "source": "内嵌控件", + "buttonId": "offsetpage.edit_offsets", + "label": "Edit Offsets", + "tooltip": "Edit offsets in OffsetPage", + "imageId": "", + "imageRole": "无图标", + "stateOrVariant": "默认", + "iconName": "", + "requestedSize": null, + "sourceType": "none", + "sourcePath": "", + "copiedFile": null, + "projectAsset": null, + "signals": [], + "notes": "内嵌控件文字按钮,无图标" + }, + { + "category": "内嵌 OffsetPage 控件", + "source": "内嵌控件", + "buttonId": "offsetpage.set_selected", + "label": "Set selected", + "tooltip": "Set selected coordinate system active", + "imageId": "", + "imageRole": "无图标", + "stateOrVariant": "默认", + "iconName": "", + "requestedSize": null, + "sourceType": "none", + "sourcePath": "", + "copiedFile": null, + "projectAsset": null, + "signals": [], + "notes": "内嵌控件文字按钮,无图标" + }, + { + "category": "内嵌 OffsetPage 控件", + "source": "内嵌控件", + "buttonId": "offsetpage.zero_g92", + "label": "Zero G92", + "tooltip": "Set G92 offsets to zero", + "imageId": "", + "imageRole": "无图标", + "stateOrVariant": "默认", + "iconName": "", + "requestedSize": null, + "sourceType": "none", + "sourcePath": "", + "copiedFile": null, + "projectAsset": null, + "signals": [], + "notes": "内嵌控件文字按钮,无图标" + }, + { + "category": "设置页控件", + "source": "Glade 静态", + "buttonId": "abs_colorbutton", + "label": "", + "tooltip": "", + "imageId": "", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "", + "requestedSize": null, + "sourceType": "none", + "sourcePath": "", + "copiedFile": null, + "projectAsset": null, + "signals": [ + "color-set:on_abs_colorbutton_color_set" + ], + "notes": "" + }, + { + "category": "设置页控件", + "source": "Glade 静态", + "buttonId": "audio_alert_chooser", + "label": "", + "tooltip": "", + "imageId": "", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "", + "requestedSize": null, + "sourceType": "none", + "sourcePath": "", + "copiedFile": null, + "projectAsset": null, + "signals": [ + "file-set:on_change_sound" + ], + "notes": "" + }, + { + "category": "设置页控件", + "source": "Glade 静态", + "buttonId": "audio_error_chooser", + "label": "", + "tooltip": "", + "imageId": "", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "", + "requestedSize": null, + "sourceType": "none", + "sourcePath": "", + "copiedFile": null, + "projectAsset": null, + "signals": [ + "file-set:on_change_sound" + ], + "notes": "" + }, + { + "category": "设置页控件", + "source": "Glade 静态", + "buttonId": "chk_en_audio", + "label": "Enable sound", + "tooltip": "", + "imageId": "", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "", + "requestedSize": null, + "sourceType": "none", + "sourcePath": "", + "copiedFile": null, + "projectAsset": null, + "signals": [ + "toggled:on_chk_en_audio_toggled" + ], + "notes": "" + }, + { + "category": "设置页控件", + "source": "Glade 静态", + "buttonId": "chk_font_monospace", + "label": "Monospace", + "tooltip": "", + "imageId": "", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "", + "requestedSize": null, + "sourceType": "none", + "sourcePath": "", + "copiedFile": null, + "projectAsset": null, + "signals": [ + "toggled:on_chk_font_monospace_toggled" + ], + "notes": "" + }, + { + "category": "设置页控件", + "source": "Glade 静态", + "buttonId": "chk_font_regular", + "label": "Regular/Medium", + "tooltip": "", + "imageId": "", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "", + "requestedSize": null, + "sourceType": "none", + "sourcePath": "", + "copiedFile": null, + "projectAsset": null, + "signals": [ + "toggled:on_chk_font_regular_toggled" + ], + "notes": "" + }, + { + "category": "设置页控件", + "source": "Glade 静态", + "buttonId": "chk_hide_cursor", + "label": "Hide cursor", + "tooltip": "", + "imageId": "", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "", + "requestedSize": null, + "sourceType": "none", + "sourcePath": "", + "copiedFile": null, + "projectAsset": null, + "signals": [ + "toggled:on_chk_hide_cursor_toggled" + ], + "notes": "" + }, + { + "category": "设置页控件", + "source": "Glade 静态", + "buttonId": "chk_hide_tooltips", + "label": "Hide tooltips", + "tooltip": "", + "imageId": "", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "", + "requestedSize": null, + "sourceType": "none", + "sourcePath": "", + "copiedFile": null, + "projectAsset": null, + "signals": [ + "toggled:on_chk_hide_tooltips_toggled" + ], + "notes": "" + }, + { + "category": "设置页控件", + "source": "Glade 静态", + "buttonId": "chk_kbd_set_height", + "label": "Height", + "tooltip": "", + "imageId": "", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "", + "requestedSize": null, + "sourceType": "none", + "sourcePath": "", + "copiedFile": null, + "projectAsset": null, + "signals": [ + "toggled:on_chk_kb_set_height_toggled" + ], + "notes": "" + }, + { + "category": "设置页控件", + "source": "Glade 静态", + "buttonId": "chk_kbd_set_width", + "label": "Width", + "tooltip": "", + "imageId": "", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "", + "requestedSize": null, + "sourceType": "none", + "sourcePath": "", + "copiedFile": null, + "projectAsset": null, + "signals": [ + "toggled:on_chk_kb_set_width_toggled" + ], + "notes": "" + }, + { + "category": "设置页控件", + "source": "Glade 静态", + "buttonId": "chk_reload_tool", + "label": "Reload Tool on Start", + "tooltip": "If checked, the tool in spindle / will be saved on each change / and the last tool will be reloaded / at start of the GUI. Also it's / length offset will be reloaded.", + "imageId": "", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "", + "requestedSize": null, + "sourceType": "none", + "sourcePath": "", + "copiedFile": null, + "projectAsset": null, + "signals": [ + "toggled:on_chk_reload_tool_toggled" + ], + "notes": "" + }, + { + "category": "设置页控件", + "source": "Glade 静态", + "buttonId": "chk_show_dro", + "label": "Show DRO", + "tooltip": "", + "imageId": "", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "", + "requestedSize": null, + "sourceType": "none", + "sourcePath": "", + "copiedFile": null, + "projectAsset": null, + "signals": [ + "toggled:on_chk_show_dro_toggled" + ], + "notes": "" + }, + { + "category": "设置页控件", + "source": "Glade 静态", + "buttonId": "chk_show_dtg", + "label": "Show DTG", + "tooltip": "", + "imageId": "", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "", + "requestedSize": null, + "sourceType": "none", + "sourcePath": "", + "copiedFile": null, + "projectAsset": null, + "signals": [ + "toggled:on_chk_show_dtg_toggled" + ], + "notes": "" + }, + { + "category": "设置页控件", + "source": "Glade 静态", + "buttonId": "chk_show_offsets", + "label": "Show offsets", + "tooltip": "", + "imageId": "", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "", + "requestedSize": null, + "sourceType": "none", + "sourcePath": "", + "copiedFile": null, + "projectAsset": null, + "signals": [ + "toggled:on_chk_show_offsets_toggled" + ], + "notes": "" + }, + { + "category": "设置页控件", + "source": "Glade 静态", + "buttonId": "chk_toggle_readout", + "label": "Toggle DRO mode by / clicking on the DRO", + "tooltip": "", + "imageId": "", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "", + "requestedSize": null, + "sourceType": "none", + "sourcePath": "", + "copiedFile": null, + "projectAsset": null, + "signals": [ + "toggled:on_chk_toggle_readout_toggled" + ], + "notes": "" + }, + { + "category": "设置页控件", + "source": "Glade 静态", + "buttonId": "chk_turtle_jog", + "label": "Hide turtle Jog Button", + "tooltip": "", + "imageId": "", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "", + "requestedSize": null, + "sourceType": "none", + "sourcePath": "", + "copiedFile": null, + "projectAsset": null, + "signals": [ + "toggled:on_chk_turtle_jog_toggled" + ], + "notes": "" + }, + { + "category": "设置页控件", + "source": "Glade 静态", + "buttonId": "chk_use_frames", + "label": "Use frames", + "tooltip": "If checked, the messages / will be in a frame.", + "imageId": "", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "", + "requestedSize": null, + "sourceType": "none", + "sourcePath": "", + "copiedFile": null, + "projectAsset": null, + "signals": [ + "toggled:on_chk_use_frames_toggled" + ], + "notes": "" + }, + { + "category": "设置页控件", + "source": "Glade 静态", + "buttonId": "chk_use_kb_on_edit", + "label": "Show keyboard on EDIT", + "tooltip": "", + "imageId": "", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "", + "requestedSize": null, + "sourceType": "none", + "sourcePath": "", + "copiedFile": null, + "projectAsset": null, + "signals": [ + "toggled:on_chk_use_kb_on_edit_toggled" + ], + "notes": "" + }, + { + "category": "设置页控件", + "source": "Glade 静态", + "buttonId": "chk_use_kb_on_file_selection", + "label": "Show keyboard on load file", + "tooltip": "", + "imageId": "", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "", + "requestedSize": null, + "sourceType": "none", + "sourcePath": "", + "copiedFile": null, + "projectAsset": null, + "signals": [ + "toggled:on_chk_use_kb_on_file_selection_toggled" + ], + "notes": "" + }, + { + "category": "设置页控件", + "source": "Glade 静态", + "buttonId": "chk_use_kb_on_mdi", + "label": "Show keyboard on MDI", + "tooltip": "", + "imageId": "", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "", + "requestedSize": null, + "sourceType": "none", + "sourcePath": "", + "copiedFile": null, + "projectAsset": null, + "signals": [ + "toggled:on_chk_use_kb_on_mdi_toggled" + ], + "notes": "" + }, + { + "category": "设置页控件", + "source": "Glade 静态", + "buttonId": "chk_use_kb_on_offset", + "label": "Show keyboard on offset", + "tooltip": "", + "imageId": "", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "", + "requestedSize": null, + "sourceType": "none", + "sourcePath": "", + "copiedFile": null, + "projectAsset": null, + "signals": [ + "toggled:on_chk_use_kb_on_offset_toggled" + ], + "notes": "" + }, + { + "category": "设置页控件", + "source": "Glade 静态", + "buttonId": "chk_use_kb_on_tooledit", + "label": "Show keyboard on tooledit", + "tooltip": "", + "imageId": "", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "", + "requestedSize": null, + "sourceType": "none", + "sourcePath": "", + "copiedFile": null, + "projectAsset": null, + "signals": [ + "toggled:on_chk_use_kb_on_tooledit_toggled" + ], + "notes": "" + }, + { + "category": "设置页控件", + "source": "Glade 静态", + "buttonId": "chk_use_kb_shortcuts", + "label": "Use keyboard shortcuts", + "tooltip": "", + "imageId": "", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "", + "requestedSize": null, + "sourceType": "none", + "sourcePath": "", + "copiedFile": null, + "projectAsset": null, + "signals": [ + "toggled:on_chk_use_kb_shortcuts_toggled" + ], + "notes": "" + }, + { + "category": "设置页控件", + "source": "Glade 静态", + "buttonId": "chk_use_tool_measurement", + "label": "Use auto tool measurement", + "tooltip": "", + "imageId": "", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "", + "requestedSize": null, + "sourceType": "none", + "sourcePath": "", + "copiedFile": null, + "projectAsset": null, + "signals": [ + "toggled:on_chk_use_tool_measurement_toggled" + ], + "notes": "" + }, + { + "category": "设置页控件", + "source": "Glade 静态", + "buttonId": "dtg_colorbutton", + "label": "", + "tooltip": "", + "imageId": "", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "", + "requestedSize": null, + "sourceType": "none", + "sourcePath": "", + "copiedFile": null, + "projectAsset": null, + "signals": [ + "color-set:on_dtg_colorbutton_color_set" + ], + "notes": "" + }, + { + "category": "设置页控件", + "source": "Glade 静态", + "buttonId": "file_to_load_chooser", + "label": "", + "tooltip": "", + "imageId": "", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "", + "requestedSize": null, + "sourceType": "none", + "sourcePath": "", + "copiedFile": null, + "projectAsset": null, + "signals": [ + "file-set:on_file_to_load_chooser_file_set" + ], + "notes": "" + }, + { + "category": "设置页控件", + "source": "Glade 静态", + "buttonId": "fontbutton_gcodeview", + "label": "", + "tooltip": "", + "imageId": "", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "", + "requestedSize": null, + "sourceType": "none", + "sourcePath": "", + "copiedFile": null, + "projectAsset": null, + "signals": [ + "font-set:on_fontbutton_gcodeview_font_set" + ], + "notes": "" + }, + { + "category": "设置页控件", + "source": "Glade 静态", + "buttonId": "fontbutton_popup", + "label": "", + "tooltip": "The font to use", + "imageId": "", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "", + "requestedSize": null, + "sourceType": "none", + "sourcePath": "", + "copiedFile": null, + "projectAsset": null, + "signals": [ + "font-set:on_fontbutton_popup_font_set" + ], + "notes": "" + }, + { + "category": "设置页控件", + "source": "Glade 静态", + "buttonId": "homed_colorbtn", + "label": "", + "tooltip": "", + "imageId": "", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "", + "requestedSize": null, + "sourceType": "none", + "sourcePath": "", + "copiedFile": null, + "projectAsset": null, + "signals": [ + "color-set:on_homed_colorbtn_color_set" + ], + "notes": "" + }, + { + "category": "设置页控件", + "source": "Glade 静态", + "buttonId": "jump_to_dir_chooser", + "label": "", + "tooltip": "", + "imageId": "", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "", + "requestedSize": null, + "sourceType": "none", + "sourcePath": "", + "copiedFile": null, + "projectAsset": null, + "signals": [ + "file-set:on_jump_to_dir_chooser_file_set" + ], + "notes": "" + }, + { + "category": "设置页控件", + "source": "Glade 静态", + "buttonId": "rbt_hal_unlock", + "label": "Use hal pin to unlock", + "tooltip": "", + "imageId": "", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "", + "requestedSize": null, + "sourceType": "none", + "sourcePath": "", + "copiedFile": null, + "projectAsset": null, + "signals": [ + "toggled:on_rbt_unlock_toggled" + ], + "notes": "" + }, + { + "category": "设置页控件", + "source": "Glade 静态", + "buttonId": "rbt_no_unlock", + "label": "Do not use unlock code", + "tooltip": "", + "imageId": "", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "", + "requestedSize": null, + "sourceType": "none", + "sourcePath": "", + "copiedFile": null, + "projectAsset": null, + "signals": [ + "toggled:on_rbt_unlock_toggled" + ], + "notes": "" + }, + { + "category": "设置页控件", + "source": "Glade 静态", + "buttonId": "rbt_use_unlock", + "label": "Use unlock code", + "tooltip": "", + "imageId": "", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "", + "requestedSize": null, + "sourceType": "none", + "sourcePath": "", + "copiedFile": null, + "projectAsset": null, + "signals": [ + "toggled:on_rbt_unlock_toggled" + ], + "notes": "" + }, + { + "category": "设置页控件", + "source": "Glade 静态", + "buttonId": "rbtn_fullscreen", + "label": "Start as fullscreen", + "tooltip": "", + "imageId": "", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "", + "requestedSize": null, + "sourceType": "none", + "sourcePath": "", + "copiedFile": null, + "projectAsset": null, + "signals": [ + "toggled:on_rbtn_fullscreen_toggled" + ], + "notes": "" + }, + { + "category": "设置页控件", + "source": "Glade 静态", + "buttonId": "rbtn_maximized", + "label": "Start maximized", + "tooltip": "", + "imageId": "", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "", + "requestedSize": null, + "sourceType": "none", + "sourcePath": "", + "copiedFile": null, + "projectAsset": null, + "signals": [ + "toggled:on_rbtn_maximized_toggled" + ], + "notes": "" + }, + { + "category": "设置页控件", + "source": "Glade 静态", + "buttonId": "rbtn_no_run_from_line", + "label": "Do not use run from line", + "tooltip": "", + "imageId": "", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "", + "requestedSize": null, + "sourceType": "none", + "sourcePath": "", + "copiedFile": null, + "projectAsset": null, + "signals": [ + "toggled:on_rbtn_run_from_line_toggled" + ], + "notes": "" + }, + { + "category": "设置页控件", + "source": "Glade 静态", + "buttonId": "rbtn_run_from_line", + "label": "Use run from line", + "tooltip": "", + "imageId": "", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "", + "requestedSize": null, + "sourceType": "none", + "sourcePath": "", + "copiedFile": null, + "projectAsset": null, + "signals": [ + "toggled:on_rbtn_run_from_line_toggled" + ], + "notes": "" + }, + { + "category": "设置页控件", + "source": "Glade 静态", + "buttonId": "rbtn_show_offsets", + "label": "show offsets", + "tooltip": "", + "imageId": "", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "", + "requestedSize": null, + "sourceType": "none", + "sourcePath": "", + "copiedFile": null, + "projectAsset": null, + "signals": [], + "notes": "" + }, + { + "category": "设置页控件", + "source": "Glade 静态", + "buttonId": "rbtn_show_preview", + "label": "show preview", + "tooltip": "", + "imageId": "", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "", + "requestedSize": null, + "sourceType": "none", + "sourcePath": "", + "copiedFile": null, + "projectAsset": null, + "signals": [ + "toggled:on_rbtn_show_preview_toggled" + ], + "notes": "" + }, + { + "category": "设置页控件", + "source": "Glade 静态", + "buttonId": "rbtn_window", + "label": "Start as window", + "tooltip": "", + "imageId": "", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "", + "requestedSize": null, + "sourceType": "none", + "sourcePath": "", + "copiedFile": null, + "projectAsset": null, + "signals": [ + "toggled:on_rbtn_window_toggled" + ], + "notes": "" + }, + { + "category": "设置页控件", + "source": "Glade 静态", + "buttonId": "rel_colorbutton", + "label": "", + "tooltip": "", + "imageId": "", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "", + "requestedSize": null, + "sourceType": "none", + "sourcePath": "", + "copiedFile": null, + "projectAsset": null, + "signals": [ + "color-set:on_rel_colorbutton_color_set" + ], + "notes": "" + }, + { + "category": "设置页控件", + "source": "Glade 静态", + "buttonId": "unhomed_colorbtn", + "label": "", + "tooltip": "", + "imageId": "", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "", + "requestedSize": null, + "sourceType": "none", + "sourcePath": "", + "copiedFile": null, + "projectAsset": null, + "signals": [ + "color-set:on_unhomed_colorbtn_color_set" + ], + "notes": "" + }, + { + "category": "Glade 静态按钮", + "source": "Glade 静态", + "buttonId": "btn_calibration", + "label": "Calibration", + "tooltip": "launch calibration", + "imageId": "", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "", + "requestedSize": null, + "sourceType": "none", + "sourcePath": "", + "copiedFile": null, + "projectAsset": null, + "signals": [ + "clicked:on_btn_calibration_clicked" + ], + "notes": "" + }, + { + "category": "Glade 静态按钮", + "source": "Glade 静态", + "buttonId": "btn_classicladder", + "label": "Cl.-ladder", + "tooltip": "Open classicladder", + "imageId": "", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "", + "requestedSize": null, + "sourceType": "none", + "sourcePath": "", + "copiedFile": null, + "projectAsset": null, + "signals": [ + "clicked:on_btn_classicladder_clicked" + ], + "notes": "" + }, + { + "category": "Glade 静态按钮", + "source": "Glade 静态", + "buttonId": "btn_delete", + "label": "", + "tooltip": "delete MDI history", + "imageId": "", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "", + "requestedSize": null, + "sourceType": "none", + "sourcePath": "", + "copiedFile": null, + "projectAsset": null, + "signals": [ + "clicked:on_btn_delete_clicked" + ], + "notes": "" + }, + { + "category": "Glade 静态按钮", + "source": "Glade 静态", + "buttonId": "btn_feed_100", + "label": "100%", + "tooltip": "reset feed override to 100 %", + "imageId": "", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "", + "requestedSize": null, + "sourceType": "none", + "sourcePath": "", + "copiedFile": null, + "projectAsset": null, + "signals": [ + "clicked:on_btn_feed_100_clicked" + ], + "notes": "" + }, + { + "category": "Glade 静态按钮", + "source": "Glade 静态", + "buttonId": "btn_hal_meter", + "label": "Hal Meter", + "tooltip": "launch hal meter", + "imageId": "", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "", + "requestedSize": null, + "sourceType": "none", + "sourcePath": "", + "copiedFile": null, + "projectAsset": null, + "signals": [ + "clicked:on_btn_hal_meter_clicked" + ], + "notes": "" + }, + { + "category": "Glade 静态按钮", + "source": "Glade 静态", + "buttonId": "btn_hal_scope", + "label": "Hal-Scope", + "tooltip": "launch hal scope", + "imageId": "", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "", + "requestedSize": null, + "sourceType": "none", + "sourcePath": "", + "copiedFile": null, + "projectAsset": null, + "signals": [ + "clicked:on_btn_hal_scope_clicked" + ], + "notes": "" + }, + { + "category": "Glade 静态按钮", + "source": "Glade 静态", + "buttonId": "btn_launch_test_message", + "label": "Launch test message", + "tooltip": "Push here to launch a test message / to test your settings.", + "imageId": "", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "", + "requestedSize": null, + "sourceType": "none", + "sourcePath": "", + "copiedFile": null, + "projectAsset": null, + "signals": [ + "pressed:on_btn_launch_test_message_pressed" + ], + "notes": "" + }, + { + "category": "Glade 静态按钮", + "source": "Glade 静态", + "buttonId": "btn_none", + "label": "none", + "tooltip": "", + "imageId": "", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "", + "requestedSize": null, + "sourceType": "none", + "sourcePath": "", + "copiedFile": null, + "projectAsset": null, + "signals": [ + "clicked:on_btn_none_clicked" + ], + "notes": "" + }, + { + "category": "Glade 静态按钮", + "source": "Glade 静态", + "buttonId": "btn_show_hal", + "label": "Halshow", + "tooltip": "opens the show hal tool", + "imageId": "", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "", + "requestedSize": null, + "sourceType": "none", + "sourcePath": "", + "copiedFile": null, + "projectAsset": null, + "signals": [ + "clicked:on_btn_show_hal_clicked" + ], + "notes": "" + }, + { + "category": "Glade 静态按钮", + "source": "Glade 静态", + "buttonId": "btn_spindle_100", + "label": "100%", + "tooltip": "", + "imageId": "", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "", + "requestedSize": null, + "sourceType": "none", + "sourcePath": "", + "copiedFile": null, + "projectAsset": null, + "signals": [ + "clicked:on_btn_spindle_100_clicked" + ], + "notes": "" + }, + { + "category": "Glade 静态按钮", + "source": "Glade 静态", + "buttonId": "btn_status", + "label": "Status", + "tooltip": "launch linuxcnc status", + "imageId": "", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "", + "requestedSize": null, + "sourceType": "none", + "sourcePath": "", + "copiedFile": null, + "projectAsset": null, + "signals": [ + "clicked:on_btn_status_clicked" + ], + "notes": "" + }, + { + "category": "Glade 静态按钮", + "source": "Glade 静态", + "buttonId": "btn_use_current", + "label": "current / file", + "tooltip": "", + "imageId": "", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "", + "requestedSize": null, + "sourceType": "none", + "sourcePath": "", + "copiedFile": null, + "projectAsset": null, + "signals": [ + "clicked:on_btn_use_current_clicked" + ], + "notes": "" + }, + { + "category": "Glade 静态按钮", + "source": "Glade 静态", + "buttonId": "chkbtn_hide_titlebar", + "label": "Hide title bar", + "tooltip": "", + "imageId": "", + "imageRole": "静态绑定", + "stateOrVariant": "默认", + "iconName": "", + "requestedSize": null, + "sourceType": "none", + "sourcePath": "", + "copiedFile": null, + "projectAsset": null, + "signals": [ + "toggled:on_chkbtn_hide_titlebar_toggled" + ], + "notes": "" + } + ] +} diff --git a/web-rtcp-5axis-sim-plan/app/src/ui/gmoccapy-icon-registry.js b/web-rtcp-5axis-sim-plan/app/src/ui/gmoccapy-icon-registry.js new file mode 100644 index 0000000..a6ab697 --- /dev/null +++ b/web-rtcp-5axis-sim-plan/app/src/ui/gmoccapy-icon-registry.js @@ -0,0 +1,146 @@ +const ICON_BASE = new URL("../assets/gmoccapy-icons/", import.meta.url).href; + +const ICONS = { + tbtn_estop: { + active: icon("main_switch_on", "img_emergency__main_switch_on__48.png"), + inactive: icon("main_switch_off", "img_emergency_off__main_switch_off__48.png"), + default: icon("main_switch_on", "img_emergency__main_switch_on__48.png"), + }, + tbtn_on: { + active: icon("power_on", "img_machine_on__power_on__48.png"), + inactive: icon("power_off", "img_machine_off__power_off__48.png"), + default: icon("power_off", "img_machine_off__power_off__48.png"), + }, + rbt_manual: { + active: icon("mode_manual_active", "img_manual_on__mode_manual_active__48.png"), + inactive: icon("mode_manual_inactive", "img_manual__mode_manual_inactive__48.png"), + default: icon("mode_manual_inactive", "img_manual__mode_manual_inactive__48.png"), + }, + rbt_mdi: { + active: icon("mode_mdi_active", "img_mdi_on__mode_mdi_active__48.png"), + inactive: icon("mode_mdi_inactive", "img_mdi__mode_mdi_inactive__48.png"), + default: icon("mode_mdi_inactive", "img_mdi__mode_mdi_inactive__48.png"), + }, + rbt_auto: { + active: icon("mode_auto_active", "img_auto_on__mode_auto_active__48.png"), + inactive: icon("mode_auto_inactive", "img_auto__mode_auto_inactive__48.png"), + default: icon("mode_auto_inactive", "img_auto__mode_auto_inactive__48.png"), + }, + tbtn_setup: { + active: icon("mode_settings_active", "img_settings_on__mode_settings_active__48.png"), + inactive: icon("mode_settings_inactive", "img_settings__mode_settings_inactive__48.png"), + default: icon("mode_settings_inactive", "img_settings__mode_settings_inactive__48.png"), + }, + tbtn_user_tabs: { + active: icon("mode_user_tabs_active", "img_user_tabs_on__mode_user_tabs_active__48.png"), + inactive: icon("mode_user_tabs_inactive", "img_user_tabs__mode_user_tabs_inactive__48.png"), + default: icon("mode_user_tabs_inactive", "img_user_tabs__mode_user_tabs_inactive__48.png"), + }, + btn_load: { default: icon("open_file", "img_open__open_file__32.svg") }, + btn_reload: { default: icon("refresh", "img_reload1__refresh__32.png") }, + btn_run: { default: icon("play", "img_run__play__32.png") }, + btn_stop: { default: icon("stop", "img_stop__stop__32.png") }, + tbtn_pause: { + active: icon("pause_active", "img_pause_active__pause_active__32.png"), + inactive: icon("pause", "img_pause__pause__32.png"), + default: icon("pause", "img_pause__pause__32.png"), + }, + btn_step: { default: icon("step", "img_step__step__32.png") }, + btn_homing: { default: icon("ref_all", "img_ref_menu__ref_all__48.png") }, + btn_tool: { default: icon("hsk_mill_tool", "img_tools__hsk_mill_tool__48.png") }, + btn_touch: { default: icon("touch_off", "img_touch_off__touch_off__48.png") }, + ref_all: { default: icon("ref_all", "img_ref_all__ref_all__48.png") }, + btn_fullscreen: { + active: icon("fullscreen_close", "img_fullsize_preview0_close__fullscreen_close__48.png"), + inactive: icon("fullscreen_open", "img_fullsize_preview0_open__fullscreen_open__48.png"), + default: icon("fullscreen_open", "img_fullsize_preview0_open__fullscreen_open__48.png"), + }, + rbt_forward: { + active: icon("spindle_right_on", "img_spindle_forward_on__spindle_right_on__48.png"), + inactive: icon("spindle_right", "img_spindle_forward__spindle_right__48.png"), + default: icon("spindle_right", "img_spindle_forward__spindle_right__48.png"), + }, + rbt_reverse: { + active: icon("spindle_left_on", "img_spindle_reverse_on__spindle_left_on__48.png"), + inactive: icon("spindle_left", "img_spindle_reverse__spindle_left__48.png"), + default: icon("spindle_left", "img_spindle_reverse__spindle_left__48.png"), + }, + rbt_stop: { + active: icon("spindle_stop_on", "img_spindle_stop_on__spindle_stop_on__48.png"), + inactive: icon("spindle_stop", "img_spindle_stop__spindle_stop__48.png"), + default: icon("spindle_stop_on", "img_spindle_stop_on__spindle_stop_on__48.png"), + }, + tbtn_flood: { + active: icon("coolant_flood_active", "img_coolant_on__coolant_flood_active__48.png"), + inactive: icon("coolant_flood_inactive", "img_coolant_off__coolant_flood_inactive__48.png"), + default: icon("coolant_flood_inactive", "img_coolant_off__coolant_flood_inactive__48.png"), + }, + tbtn_mist: { + active: icon("coolant_mist_active", "img_mist_on__coolant_mist_active__48.png"), + inactive: icon("coolant_mist_inactive", "img_mist_off__coolant_mist_inactive__48.png"), + default: icon("coolant_mist_inactive", "img_mist_off__coolant_mist_inactive__48.png"), + }, + btn_zoom_in: { default: icon("zoom_in", "img_zoom_in__zoom_in__24.png") }, + btn_zoom_out: { default: icon("zoom_out", "img_zoom_out__zoom_out__24.png") }, + rbt_view_x: { default: icon("tool_axis_x", "img_view_x__tool_axis_x__24.png") }, + rbt_view_y: { default: icon("tool_axis_y", "img_view_y__tool_axis_y__24.png") }, + rbt_view_z: { default: icon("tool_axis_z", "img_view_z__tool_axis_z__24.png") }, + rbt_view_p: { default: icon("tool_axis_p", "img_view_p__tool_axis_p__24.png") }, + tbtn_view_tool_path: { default: icon("toolpath", "img_tool_path__toolpath__24.png") }, + tbtn_view_dimension: { default: icon("dimensions", "img_dimensions__dimensions__24.png") }, + btn_exit: { default: icon("logout", "img_close__logout__48.png") }, + btn_save_session: { default: icon("save", "img_tool_save__save__32.png") }, +}; + +export const GMOCAPY_ICON_REGISTRY_BOUNDARY = "gmoccapy_icon_registry_from_working3_manifest_core_ui_subset"; + +export function getGmoccapyIcon(buttonId, variant = "default") { + const variants = ICONS[buttonId] || null; + const fallback = { + buttonId, + variant, + iconName: "text_fallback", + path: null, + fallback: true, + semanticBoundary: GMOCAPY_ICON_REGISTRY_BOUNDARY, + }; + if (!variants) return fallback; + const normalizedVariant = normalizeVariant(variant); + const resolved = variants[normalizedVariant] || variants.default || variants.inactive || variants.active || null; + if (!resolved) return fallback; + return { + buttonId, + variant: normalizedVariant, + ...resolved, + fallback: false, + semanticBoundary: GMOCAPY_ICON_REGISTRY_BOUNDARY, + }; +} + +export function listGmoccapyIconRegistryEntries() { + return Object.entries(ICONS).flatMap(([buttonId, variants]) => ( + Object.entries(variants).map(([variant, entry]) => ({ + buttonId, + variant, + ...entry, + semanticBoundary: GMOCAPY_ICON_REGISTRY_BOUNDARY, + })) + )); +} + +function icon(iconName, filename) { + return { + iconName, + filename, + path: `${ICON_BASE}${filename}`, + }; +} + +function normalizeVariant(variant) { + if (variant === true) return "active"; + if (variant === false) return "inactive"; + const value = String(variant || "default").toLowerCase(); + if (["active", "on", "selected", "state_on", "paused", "fullscreen active"].includes(value)) return "active"; + if (["inactive", "off", "default", "state_estop_reset"].includes(value)) return value === "default" ? "default" : "inactive"; + return value; +} 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 c26bf3f..6fd3eed 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 @@ -1,5 +1,8 @@ import { renderFiveAxisScene } from "../visualization/five-axis-scene.js"; import { gateLinuxCncTaskAction } from "../state/linuxcnc-task-policy.js"; +import { gmoccapyCommunicationModel, createGmoccapyCommunicationSummary } from "../runtime/gmoccapy-communication-model.js"; +import { gmoccapyHalModel, createGmoccapyHalSummary } from "../runtime/gmoccapy-hal-model.js"; +import { getGmoccapyIcon } from "./gmoccapy-icon-registry.js"; const REGIONS = [ "titlebar", @@ -104,11 +107,11 @@ function renderPreview(element, state, dispatch) {
- - - - - + ${iconButtonHtml({ buttonId: "rbt_view_x", action: "view-x", label: "X", title: "View X", active: state.preview.selectedView === "x" })} + ${iconButtonHtml({ buttonId: "rbt_view_y", action: "view-y", label: "Y", title: "View Y", active: state.preview.selectedView === "y" })} + ${iconButtonHtml({ buttonId: "rbt_view_z", action: "view-z", label: "Z", title: "View Z", active: state.preview.selectedView === "z" })} + ${iconButtonHtml({ buttonId: "rbt_view_p", action: "reset-view", label: "Fit", title: "Fit perspective", active: state.preview.selectedView === "iso" })} + ${iconButtonHtml({ buttonId: "tbtn_view_tool_path", action: "clear-preview", label: "Clear", title: "Clear preview path" })}
`; @@ -145,12 +148,11 @@ function renderPreview(element, state, dispatch) { const toolbar = element.querySelector("[data-preview-points]"); if (toolbar) { toolbar.dataset.previewPoints = String(state.preview.pathPoints); - for (const view of ["x", "y", "z"]) { - toolbar.querySelector(`[data-action="view-${view}"]`)?.setAttribute( - "data-active", - state.preview.selectedView === view ? "true" : "false", - ); - } + updateIconButton(toolbar.querySelector('[data-action="view-x"]'), "rbt_view_x", state.preview.selectedView === "x"); + updateIconButton(toolbar.querySelector('[data-action="view-y"]'), "rbt_view_y", state.preview.selectedView === "y"); + updateIconButton(toolbar.querySelector('[data-action="view-z"]'), "rbt_view_z", state.preview.selectedView === "z"); + updateIconButton(toolbar.querySelector('[data-action="reset-view"]'), "rbt_view_p", state.preview.selectedView === "iso"); + updateIconButton(toolbar.querySelector('[data-action="clear-preview"]'), "tbtn_view_tool_path", state.preview.pathPoints > 0); } const canvas = element.querySelector("[data-five-axis-canvas]"); @@ -345,16 +347,18 @@ function mdiQuickCommands(state) { } function renderSidebar(element, state, dispatch) { + const tcpKinsType = tcpKinsTypeForProfile(state.profile); + const tcpDisabled = tcpKinsType ? "" : ` disabled title="${escapeHtml(`${state.profile.id} is ${state.profile.kinematics} reference only`)}"`; element.innerHTML = ` - - - - - - - + ${iconButtonHtml({ buttonId: "tbtn_estop", action: "estop", label: "E-STOP", title: "Estop the machine / F1", className: "sidebar-button estop", active: state.machine.estopActive })} + ${iconButtonHtml({ buttonId: "tbtn_on", action: "power", label: "POWER", title: "Turn the machine on/off / F2", className: "sidebar-button power", active: state.machine.powerOn })} + ${iconButtonHtml({ buttonId: "tbtn_setup", action: "reset", label: "RESET", title: "Reset estop and return machine off", className: "sidebar-button", active: false })} + ${iconButtonHtml({ buttonId: "rbt_auto", action: "mode-auto", label: "AUTO", title: "Enter auto mode", className: "sidebar-button", active: state.machine.mode === "auto" })} + ${iconButtonHtml({ buttonId: "rbt_manual", action: "mode-manual", label: "MANUAL", title: "Enter manual mode", className: "sidebar-button", active: state.machine.mode === "manual" })} + ${iconButtonHtml({ buttonId: "tbtn_user_tabs", action: "mode-jog", label: "JOG", title: "Manual jog page", className: "sidebar-button", active: state.machine.mode === "manual" })} + ${iconButtonHtml({ buttonId: "rbt_mdi", action: "mode-mdi", label: "MDI", title: "Enter MDI mode", className: "sidebar-button", active: state.machine.mode === "mdi" })} - + `; @@ -369,7 +373,7 @@ function renderSidebar(element, state, dispatch) { dispatch({ type: "SET_KINS_TYPE", kinsType: "identity" }); }); element.querySelector('[data-action="kins-tcp"]').addEventListener("click", () => { - const tcpKinsType = state.profile.kinematicsParameters.switchkinsTypes.find((type) => type.value === 1)?.webKinsType || "tcp-xyzac"; + if (!tcpKinsType) return; dispatch({ type: "SET_KINS_TYPE", kinsType: tcpKinsType }); }); } @@ -377,11 +381,13 @@ function renderSidebar(element, state, dispatch) { function renderInfoTabs(element, state) { const frame = state.rtcpFrame; const taskPolicy = state.linuxCncTaskPolicy; + const commSummary = createGmoccapyCommunicationSummary(); + const halSummary = createGmoccapyHalSummary(); element.innerHTML = `
Size:
${state.fileSizeBytes} bytes
@@ -431,6 +437,18 @@ function renderInfoTabs(element, state) {
Source map:
${state.linuxCncBoundaryAdapter.sourceSummary.referenceCount} refs / ${state.linuxCncBoundaryAdapter.sourceSummary.sourceRequiredCount} source files
Profile summary:
${state.linuxCncBoundaryAdapter.profileSummary.coordinates} / ${state.linuxCncBoundaryAdapter.profileSummary.jointCount} joints / ${state.linuxCncBoundaryAdapter.profileSummary.toolCount} tools
Boundary ready:
${state.linuxCncBoundaryReadiness.ready ? "ready" : "blocked"} (${state.linuxCncBoundaryReadiness.missing.join(", ")})
+
gmoccapy comms:
${gmoccapyCommunicationModel.semanticBoundary}
+
NML command:
${formatGmoccapyNativePath("command")}
+
NML status:
${formatGmoccapyNativePath("status")}
+
Web runtime:
${gmoccapyCommunicationModel.webPath.path.join(" -> ")}
+
postgui order:
${commSummary.postguiAfterHalcompReady ? "halcomp.ready before POSTGUI_HALFILE" : "pending"}
+
native RUN:
${formatGmoccapyActionMapping("auto-run")}
+
HAL model:
${gmoccapyHalModel.semanticBoundary}
+
HAL files:
${halSummary.halFileCount} files / POSTGUI ${halSummary.postguiRequiresHalcompReady ? "after halcomp.ready" : "pending"}
+
HAL pins:
${halSummary.nativePinGroupCount} groups / ${halSummary.nativePinCount} pins
+
postgui nets:
${gmoccapyHalModel.postguiNets.map((net) => net.signal).join(" / ")}
+
Tool loop:
${halSummary.hasToolChangeSimulationLoop ? "simulated tool-change loop" : "pending"}
+
Operator:
${escapeHtml(state.operatorMessage)}
`; } @@ -603,15 +621,25 @@ function overrideControl(label, target, value, prefix = "") { } function renderSpindleCoolant(element, state, dispatch) { + const forwardGate = gateLinuxCncTaskAction(state, { type: "SPINDLE", direction: "forward" }); + const reverseGate = gateLinuxCncTaskAction(state, { type: "SPINDLE", direction: "reverse" }); + const stopGate = gateLinuxCncTaskAction(state, { type: "SPINDLE", direction: "stop" }); + const floodGate = gateLinuxCncTaskAction(state, { type: "TOGGLE_COOLANT", kind: "flood" }); + const mistGate = gateLinuxCncTaskAction(state, { type: "TOGGLE_COOLANT", kind: "mist" }); element.innerHTML = `

Cooling

- - + ${iconButtonHtml({ buttonId: "tbtn_flood", action: "toggle-flood", label: "Flood", title: floodGate.operatorMessage || "Flood coolant", active: state.coolant.flood, className: state.coolant.flood ? "active" : "", gate: floodGate })} + ${iconButtonHtml({ buttonId: "tbtn_mist", action: "toggle-mist", label: "Mist", title: mistGate.operatorMessage || "Mist coolant", active: state.coolant.mist, className: state.coolant.mist ? "active" : "", gate: mistGate })}

Spindle

${state.spindle.rpm} rpm +
+ ${iconButtonHtml({ buttonId: "rbt_forward", action: "spindle-forward", label: "FWD", title: forwardGate.operatorMessage || "Spindle forward", active: state.spindle.direction === "forward", gate: forwardGate })} + ${iconButtonHtml({ buttonId: "rbt_stop", action: "spindle-stop", label: "STOP", title: stopGate.operatorMessage || "Spindle stop", active: !state.spindle.enabled || state.spindle.direction === "stop", gate: stopGate })} + ${iconButtonHtml({ buttonId: "rbt_reverse", action: "spindle-reverse", label: "REV", title: reverseGate.operatorMessage || "Spindle reverse", active: state.spindle.direction === "reverse", gate: reverseGate })} +
${state.spindle.override} %
@@ -633,6 +661,15 @@ function renderSpindleCoolant(element, state, dispatch) { element.querySelector('[data-action="spindle-override-up"]').addEventListener("click", () => { dispatch({ type: "ADJUST_SPINDLE_OVERRIDE", delta: 10 }); }); + element.querySelector('[data-action="spindle-forward"]').addEventListener("click", () => { + dispatch({ type: "SET_SPINDLE_DIRECTION", direction: "forward" }); + }); + element.querySelector('[data-action="spindle-reverse"]').addEventListener("click", () => { + dispatch({ type: "SET_SPINDLE_DIRECTION", direction: "reverse" }); + }); + element.querySelector('[data-action="spindle-stop"]').addEventListener("click", () => { + dispatch({ type: "SET_SPINDLE_DIRECTION", direction: "stop" }); + }); } function renderBottomControls(element, state, dispatch) { @@ -669,7 +706,15 @@ function renderBottomControls(element, state, dispatch) { const blockedAttrs = gate.allowed ? ` data-command-ready="true" aria-disabled="false"` : ` data-command-ready="false" aria-disabled="${promptable ? "true" : "false"}"`; - return ``; + return iconButtonHtml({ + buttonId: bottomIconButtonId(action), + action, + label, + title: gate.allowed ? label : gate.operatorMessage || "blocked", + active: bottomControlActive(state, action), + disabled: Boolean(disabled), + attrs: blockedAttrs, + }); }) .join("")} `; @@ -714,6 +759,99 @@ function bottomControlGate(state, action) { return gateLinuxCncTaskAction(state, actionMap[action] || { type: "UI_CONTROL" }); } +function bottomIconButtonId(action) { + return { + OPEN: "btn_load", + RELOAD: "btn_reload", + RUN_READY: "ref_all", + RUN: "btn_run", + STOP: "btn_stop", + PAUSE: "tbtn_pause", + RESUME: "btn_run", + STEP: "btn_step", + HOME: "btn_homing", + JOG_X_NEG: "rbt_view_x", + JOG_X_POS: "rbt_view_x", + JOG_Y_NEG: "rbt_view_y", + JOG_Y_POS: "rbt_view_y", + MDI_RUN: "rbt_mdi", + SAVE_SESSION: "btn_save_session", + RESTORE_SESSION: "btn_reload", + AUDIT_FULL_BOUNDARY: "tbtn_setup", + FULL: "btn_fullscreen", + }[action] || "btn_load"; +} + +function bottomControlActive(state, action) { + if (action === "PAUSE") return state.runState === "paused"; + if (action === "RUN" || action === "RESUME") return state.runState === "running"; + if (action === "STEP") return state.runState === "stepping"; + if (action === "HOME") return state.machine.allHomed; + if (action === "FULL") return state.preview.fullscreen; + return false; +} + +function iconButtonHtml({ + buttonId, + action, + label, + title = label, + active = false, + className = "", + gate = null, + disabled = false, + attrs = "", +} = {}) { + const icon = getGmoccapyIcon(buttonId, active ? "active" : "inactive"); + const disabledAttr = disabled || gate?.allowed === false ? " disabled" : ""; + const readyAttr = gate + ? ` data-command-ready="${gate.allowed ? "true" : "false"}" aria-disabled="${gate.allowed ? "false" : "true"}"` + : ""; + const labelText = escapeHtml(label || icon.iconName); + const titleAttr = title ? ` title="${escapeHtml(title)}"` : ""; + const classAttr = className ? ` class="${escapeHtml(className)}"` : ""; + const iconMarkup = icon.path + ? `` + : ``; + return ` + + `; +} + +function updateIconButton(button, buttonId, active) { + if (!button) return; + const icon = getGmoccapyIcon(buttonId, active ? "active" : "inactive"); + button.dataset.active = active ? "true" : "false"; + button.dataset.iconName = icon.iconName; + button.dataset.iconVariant = icon.variant; + const image = button.querySelector("img"); + if (image && icon.path) image.src = icon.path; +} + +function formatGmoccapyNativePath(kind) { + const entry = gmoccapyCommunicationModel.nativePaths[kind]; + if (!entry) return "pending"; + return `${entry.label}: ${entry.path.join(" -> ")}`; +} + +function formatGmoccapyActionMapping(actionId) { + const mapping = gmoccapyCommunicationModel.actionMappings.find((item) => item.actionId === actionId); + if (!mapping) return "pending"; + return `${mapping.nativeCommand} / ${mapping.gate}`; +} + function formatNumber(value, digits = 3) { return Number(value).toFixed(digits); } @@ -724,6 +862,13 @@ function formatAxisLimitSummary(axisLimits) { .join(" "); } +function tcpKinsTypeForProfile(profile) { + if (profile?.tcpCapable === false) return null; + return profile?.kinematicsParameters?.switchkinsTypes + ?.find((type) => type.value === 1 && String(type.webKinsType || "").startsWith("tcp-")) + ?.webKinsType || null; +} + function escapeHtml(value) { return String(value) .replaceAll("&", "&") diff --git a/web-rtcp-5axis-sim-plan/docs/gmoccapy-xyzab-reference.md b/web-rtcp-5axis-sim-plan/docs/gmoccapy-xyzab-reference.md new file mode 100644 index 0000000..29c3a08 --- /dev/null +++ b/web-rtcp-5axis-sim-plan/docs/gmoccapy-xyzab-reference.md @@ -0,0 +1,174 @@ +# gmoccapy XYZAB Reference + +Date: 2026-06-26 + +This document records how the LinuxCNC `gmoccapy_XYZAB.ini` simulation maps into +the Web RTCP 5-axis simulator. It is a reference boundary, not a browser port of +the native gmoccapy GTK runtime. + +## Source Inputs + +Primary input: + +```text +work/working3/gmoccapy_XYZAB_execution_analysis.md +linuxcnc/configs/sim/gmoccapy/gmoccapy_XYZAB.ini +linuxcnc/configs/sim/gmoccapy/core_sim_XYZAB.hal +linuxcnc/configs/sim/gmoccapy/spindle_sim.hal +linuxcnc/configs/sim/gmoccapy/simulated_home.hal +linuxcnc/configs/sim/gmoccapy/gmoccapy_postgui.hal +work/working3/gmoccapy_button_icons/button_icon_inventory.csv +work/working3/gmoccapy_button_icons/files/ +``` + +Project assets generated from those inputs: + +```text +app/src/ui-reference/gmoccapy-button-icons.json +app/src/assets/gmoccapy-icons/ +app/src/profiles/gmoccapy-xyzab.js +app/src/runtime/gmoccapy-communication-model.js +app/src/runtime/gmoccapy-hal-model.js +``` + +## Native LinuxCNC Configuration + +`gmoccapy_XYZAB.ini` defines a simulated five-axis machine: + +- UI: `[DISPLAY] DISPLAY = gmoccapy`. +- UI poll cycle: `[DISPLAY] CYCLE_TIME = 100` ms. +- Task process: `[TASK] TASK = milltask`. +- Motion module: `[EMCMOT] EMCMOT = motmod`. +- Realtime periods: `BASE_PERIOD = 100000` ns, `SERVO_PERIOD = 1000000` ns. +- Coordinates: `[TRAJ] COORDINATES = X Y Z A B`. +- Kinematics: `[KINS] KINEMATICS = trivkins coordinates=xyzab`. +- Joint count: `[KINS] JOINTS = 5`. +- Homing policy: `[TRAJ] NO_FORCE_HOMING = 0`. +- HALUI: `[HAL] HALUI = halui`. + +The native profile is a `trivkins` simulation. It is not a TCP/RTCP proof and +must not be promoted as source-derived table-rotary-tilting kinematics. + +## Native Startup Order + +The native command is: + +```bash +linuxcnc linuxcnc/configs/sim/gmoccapy/gmoccapy_XYZAB.ini +``` + +The LinuxCNC script performs these stages: + +1. Parse INI and export `CONFIG_DIR`, `INI_FILE_NAME`, and config-local `PATH`. +2. Start `linuxcncsvr -ini ` for NML buffers. +3. Start realtime, RTAPI, and HAL. +4. Load task process with `halcmd loadusr -Wn inihal milltask -ini `. +5. Load `halui` with `halcmd loadusr -Wn halui halui -ini `. +6. Execute normal `[HAL] HALFILE` entries: + `core_sim_XYZAB.hal`, `spindle_sim.hal`, and `simulated_home.hal`. +7. Run `halcmd start`. +8. Start the display with `gmoccapy -ini `. +9. After gmoccapy creates `gmoccapy.*` pins and calls `halcomp.ready()`, execute + `[HAL] POSTGUI_HALFILE = gmoccapy_postgui.hal`. + +The postgui file is order-sensitive because it references `gmoccapy.*` pins that +do not exist during ordinary HALFILE loading. + +## Native Communication Model + +gmoccapy talks to LinuxCNC through local LinuxCNC mechanisms: + +- Command path: `gmoccapy -> linuxcnc.command() -> NML emcCommand -> milltask`. +- Status path: `milltask -> NML emcStatus/emcError -> linuxcnc.stat()/error_channel()`. +- HAL path: `gmoccapy.* pins <-> HAL shared memory`. +- HALUI path: `halui` exposes LinuxCNC commands and status as HAL pins. +- REMAP path: `[RS274NGC] REMAP` and `[PYTHON]` run inside the task/interpreter + side, not inside the GUI. + +The Web application does not connect to native NML buffers, HAL shared memory, or +realtime threads. Web buttons dispatch through `store.dispatch`, task policy +gates, source-derived runtimes where available, and UI status snapshots. + +## HAL Topology + +`core_sim_XYZAB.hal` loads `trivkins` and `motmod`, then loops commanded joint +positions directly back to feedback: + +```text +joint.0 X command -> joint.0 feedback +joint.1 Y command -> joint.1 feedback +joint.2 Z command -> joint.2 feedback +joint.3 A command -> joint.3 feedback +joint.4 B command -> joint.4 feedback +``` + +It also creates the simulation loops: + +- `iocontrol.0.user-enable-out -> iocontrol.0.emc-enable-in`. +- `iocontrol.0.tool-prepare -> iocontrol.0.tool-prepared`. +- `iocontrol.0.tool-change -> iocontrol.0.tool-changed`. +- `spindle.0.forward`, `spindle.0.reverse`. +- `iocontrol.0.coolant-flood`, `iocontrol.0.coolant-mist`. + +`spindle_sim.hal` simulates speed feedback: + +```text +spindle.0.speed-out -> limit2 -> sim_encoder -> encoder -> spindle.0.speed-in +near_speed.out -> spindle.0.at-speed +``` + +`simulated_home.hal` creates simulated X/Y/Z home switches at X=1, Y=0.5, Z=2. + +`gmoccapy_postgui.hal` maps native HAL state into GUI pins: + +- `gmoccapy.spindle_feedback_bar`. +- `gmoccapy.spindle_at_speed_led`. +- `gmoccapy.tooloffset-x`. +- `gmoccapy.tooloffset-z`. + +It also re-establishes the simulated tool-change loop after unlinking conflicting +pins. + +## G-code Gates + +Because `NO_FORCE_HOMING = 0`, MDI and Auto require the normal LinuxCNC sequence: + +```text +reset estop +machine on +home all axes +load a program or MDI command +switch to the correct mode +interpreter idle +run MDI or AUTO_RUN +``` + +The native stack enforces this in three layers: + +1. gmoccapy widget sensitivity and page state. +2. gladevcp actions and gmoccapy callback checks. +3. LinuxCNC task, interpreter, motion, IO, and HAL validation. + +The Web project mirrors this as UI disabled reasons, `linuxcnc-task-policy` +gates, and runtime preconditions. The `gmoccapy-xyzab` profile is allowed as a +reference selection, but full LinuxCNC 5-axis source-derived RUN proof remains +limited to profiles that have project runtime support. + +## Button Icon Boundary + +The icon inventory from `working3/gmoccapy_button_icons` was converted into a +project-local manifest: + +```text +app/src/ui-reference/gmoccapy-button-icons.json +``` + +The copied icons live in: + +```text +app/src/assets/gmoccapy-icons/ +``` + +These assets prove UI origin and visual mapping only. Button correctness still +depends on the Web store, task policy, runtime state, and browser interaction +evidence. diff --git a/web-rtcp-5axis-sim-plan/docs/traceability-matrix.md b/web-rtcp-5axis-sim-plan/docs/traceability-matrix.md index ff05fe0..7eb153e 100644 --- a/web-rtcp-5axis-sim-plan/docs/traceability-matrix.md +++ b/web-rtcp-5axis-sim-plan/docs/traceability-matrix.md @@ -39,6 +39,10 @@ CNC 语义必须来自 LinuxCNC source/WASM/source-derived boundary; | `xyzac-trt` profile | `app/src/profiles/xyzac-trt.js` | `configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzac-trt.ini` | source/config reference | profile boundary node smoke | | `xyzac-trt` source reference map | `app/src/profiles/source-reference-map.js` | `xyzac-trt.ini`, `xyzac-trt.xml`, `switchkins_postgui.hal`, `xyzac-trt_cmds.hal`, `xyzac-trt-kins.c`, `trtfuncs.c`, `switchkins.c` | profile/source map only, not runtime proof | profile boundary node smoke | | `xyzbc-trt` profile | `app/src/profiles/xyzbc-trt.js` | `configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzbc-trt.ini` | source/config reference + runtime module switch | profile node smoke + browser profile switch smoke | +| `gmoccapy-xyzab` reference profile | `app/src/profiles/gmoccapy-xyzab.js` | `linuxcnc/configs/sim/gmoccapy/gmoccapy_XYZAB.ini`, `core_sim_XYZAB.hal`, `spindle_sim.hal`, `simulated_home.hal`, `gmoccapy_postgui.hal` | gmoccapy/trivkins reference profile only; not RTCP proof | gmoccapy XYZAB profile node smoke | +| gmoccapy_XYZAB NML/HAL communication model | `app/src/runtime/gmoccapy-communication-model.js`, `docs/gmoccapy-xyzab-reference.md` | `gmoccapy.py`, `linuxcnc.command/stat/error_channel`, `milltask`, HALUI, POSTGUI_HALFILE startup order | native communication reference mapped to Web store/task policy; browser does not attach to NML/HAL shared memory | gmoccapy communication model node smoke | +| gmoccapy_XYZAB HAL/postgui diagnostics model | `app/src/runtime/gmoccapy-hal-model.js`, `docs/gmoccapy-xyzab-reference.md` | `core_sim_XYZAB.hal`, `spindle_sim.hal`, `simulated_home.hal`, `gmoccapy_postgui.hal` | HAL pin/postgui reference and Web diagnostics only | gmoccapy HAL model node smoke | +| gmoccapy button icon manifest | `app/src/ui-reference/gmoccapy-button-icons.json`, `app/src/assets/gmoccapy-icons/` | `work/working3/gmoccapy_button_icons/button_icon_inventory.csv`, copied classic theme and macro image files | UI asset provenance only; button semantics still require task policy/runtime evidence | gmoccapy icon manifest node smoke | | SWITCHKINS panel | `app/src/panel-schema/xyzac-trt-pyvcp.js` | `xyzac-trt.xml`, `switchkins_postgui.hal` | UI/HAL binding reference | profile boundary node smoke + browser DOM smoke | | M428/M429/M430 state | `app/src/profiles/xyzac-trt.js`, `app/src/panel-schema/xyzac-trt-pyvcp.js` | `remap_subs/428remap.ngc`, `429remap.ngc`, `430remap.ngc` | LinuxCNC remap/source reference only until runtime adapter is connected | profile boundary node smoke | | LinuxCNC boundary adapter | `app/src/runtime/linuxcnc-boundary-adapter.js` | LinuxCNC interpreter/kinematics/TP WASM adapter point | kinematics + interpreter + TP timing runtime connected; task/motion/HAL simulation runtime connected separately | profile boundary node smoke + browser DOM smoke | @@ -77,6 +81,11 @@ src/hal/user_comps/vismach/5axisgui.py src/hal/user_comps/vismach/xyzac-trt-gui.py src/hal/user_comps/vismach/xyzbc-trt-gui.py configs/sim/gmoccapy/gmoccapy_XYZAC.ini +configs/sim/gmoccapy/gmoccapy_XYZAB.ini +configs/sim/gmoccapy/core_sim_XYZAB.hal +configs/sim/gmoccapy/spindle_sim.hal +configs/sim/gmoccapy/simulated_home.hal +configs/sim/gmoccapy/gmoccapy_postgui.hal configs/sim/qtvcp_screens/qtdragon/README ``` diff --git a/web-rtcp-5axis-sim-plan/gptlog-process/gpdlog.md b/web-rtcp-5axis-sim-plan/gptlog-process/gpdlog.md index 716cf72..47bd685 100644 --- a/web-rtcp-5axis-sim-plan/gptlog-process/gpdlog.md +++ b/web-rtcp-5axis-sim-plan/gptlog-process/gpdlog.md @@ -3792,3 +3792,923 @@ Final log-sync step: - `记录云仓库同步日志` - The final action is to push that log commit to: - `origin/master` + +--- + +## GPT/Codex execution log - 2026-06-26 10:10:14 EDT + +User request: +- 使用 `/home/meswork/cnc_wams/work/working3` 的资料,编写完善 + `/home/meswork/cnc_wams/web-rtcp-5axis-sim-plan` 功能的文档。 +- 文档要求覆盖: + - 01 功能内容。 + - 02 程序开发详细步骤。 + - 03 推进台账:每轮做了什么、改了哪些文件、验证了什么、下一步是什么。 + - 04 任务矩阵:所有任务编号、状态、验收标准,防止重复做。 + - 05 验收证据:命令、页面、job_id、report_id、PDF、截图等证据。 + - 06 决策记录:为什么这么做,后续变更时不反复争论同一个问题。 +- 文档创建在 `/home/meswork/cnc_wams/work/working4`。 + +Workspace and rules: +- Working directory: `/home/meswork/cnc_wams`. +- AGENTS.md logging rule requires appending the full execution process log to: + `/home/meswork/cnc_wams/web-rtcp-5axis-sim-plan/gptlog-process/gpdlog.md`. +- Filesystem access: unrestricted. +- Approval policy: never. + +Discovery commands executed: +- `find /home/meswork/cnc_wams/work/working3 -maxdepth 3 -type f | sort` + - Confirmed `working3` contains: + - `gmoccapy_XYZAB_execution_analysis.md` + - `gmoccapy_button_icons/README.md` + - `gmoccapy_button_icons/button_icon_inventory.csv` + - `gmoccapy_button_icons/button_icon_inventory.md` + - `gmoccapy_button_icons/files/` with copied PNG/SVG icon assets. +- `find /home/meswork/cnc_wams/web-rtcp-5axis-sim-plan -maxdepth 3 -type f | sort | sed 's#^#/##'` + - Confirmed target project contains README, docs, app sources, build readiness artifact, tests, working notes, run evidence, and `gptlog-process/gpdlog.md`. +- `find /home/meswork/cnc_wams/work -maxdepth 2 -type d | sort` + - Confirmed `work/working4` directory exists. +- `find /home/meswork/cnc_wams/work/working4 -maxdepth 2 -type f -print | sort` + - Confirmed `working4` was empty before writing documents. + +Source documents read: +- `sed -n '1,240p' /home/meswork/cnc_wams/work/working3/gmoccapy_XYZAB_execution_analysis.md` +- `sed -n '240,520p' /home/meswork/cnc_wams/work/working3/gmoccapy_XYZAB_execution_analysis.md` +- `sed -n '520,900p' /home/meswork/cnc_wams/work/working3/gmoccapy_XYZAB_execution_analysis.md` + - Extracted LinuxCNC/gmoccapy_XYZAB startup order, NML command/status/error communication, HAL/postgui behavior, HALUI role, G-code run conditions, task/mode/interpreter/home interlocks, and button/control logic. +- `sed -n '1,220p' /home/meswork/cnc_wams/work/working3/gmoccapy_button_icons/README.md` + - Confirmed icon inventory structure and naming conventions. +- `sed -n '1,220p' /home/meswork/cnc_wams/work/working3/gmoccapy_button_icons/button_icon_inventory.md` + - Reviewed icon inventory summary and representative rows. +- `head -n 30 /home/meswork/cnc_wams/work/working3/gmoccapy_button_icons/button_icon_inventory.csv` + - Reviewed CSV field names and button/icon mapping examples. +- `wc -l /home/meswork/cnc_wams/work/working3/gmoccapy_XYZAB_execution_analysis.md /home/meswork/cnc_wams/work/working3/gmoccapy_button_icons/button_icon_inventory.csv /home/meswork/cnc_wams/work/working3/gmoccapy_button_icons/button_icon_inventory.md` + - Confirmed line counts: + - `gmoccapy_XYZAB_execution_analysis.md`: 1287 lines. + - `button_icon_inventory.csv`: 212 lines. + - `button_icon_inventory.md`: 247 lines. + +Target project context read: +- `sed -n '1,240p' /home/meswork/cnc_wams/web-rtcp-5axis-sim-plan/README.md` + - Confirmed project goal: Web RTCP five-axis simulation, not a real machine controller or native LinuxCNC replacement. +- `sed -n '1,260p' /home/meswork/cnc_wams/web-rtcp-5axis-sim-plan/docs/technical-roadmap.md` + - Confirmed technology route: native HTML/CSS/ES modules, Three.js, LinuxCNC source-derived WASM boundaries, gmoccapy-style shell. +- `sed -n '1,260p' /home/meswork/cnc_wams/web-rtcp-5axis-sim-plan/docs/traceability-matrix.md` + - Confirmed existing traceability records for gmoccapy UI, run controls, LinuxCNC kinematics/interpreter/task-HAL runtime, profiles, OPFS/session, full execution boundary, and native task/HAL readiness. +- `sed -n '1,260p' /home/meswork/cnc_wams/web-rtcp-5axis-sim-plan/app/src/main.js` +- `sed -n '260,620p' /home/meswork/cnc_wams/web-rtcp-5axis-sim-plan/app/src/main.js` + - Confirmed app attaches profile INI config, kinematics runtime, interpreter runtime, task/HAL runtime, machine-file staging, and default LinuxCNC program preview. +- `find /home/meswork/cnc_wams/web-rtcp-5axis-sim-plan/app/src -maxdepth 3 -type f | sort` + - Confirmed current module layout: profiles, runtime, state, UI, styles, visualization, vendor Three.js. +- `sed -n '1,260p' /home/meswork/cnc_wams/web-rtcp-5axis-sim-plan/working_run/12-working-run-final-completion-record.md` + - Confirmed RUN chain, preconditions, status loop, unit conversion, browser evidence, and working_run remaining tasks were previously closed. +- `sed -n '1,260p' /home/meswork/cnc_wams/web-rtcp-5axis-sim-plan/docs/native-task-hal-sync-implementation-steps.md` + - Reviewed existing native task/HAL synchronization plan and promotion boundaries. +- `sed -n '1,220p' /home/meswork/cnc_wams/web-rtcp-5axis-sim-plan/app/package.json` + - Confirmed build, dev, browser smoke, and node smoke scripts. +- `sed -n '1,260p' /home/meswork/cnc_wams/web-rtcp-5axis-sim-plan/app/src/profiles/index.js` +- `sed -n '1,260p' /home/meswork/cnc_wams/web-rtcp-5axis-sim-plan/app/src/profiles/xyzac-trt.js` +- `sed -n '1,260p' /home/meswork/cnc_wams/web-rtcp-5axis-sim-plan/app/src/profiles/xyzbc-trt.js` + - Confirmed current profile set is `xyzac-trt` and `xyzbc-trt`; no gmoccapy_XYZAB profile exists yet. +- `rg -n "icon|button|gmoccapy|status-sidebar|bottom|run|pause|stop|home|tool|touch|coolant|spindle" /home/meswork/cnc_wams/web-rtcp-5axis-sim-plan/app/src/ui/gmoccapy-shell.js` +- `sed -n '1,260p' /home/meswork/cnc_wams/web-rtcp-5axis-sim-plan/app/src/ui/gmoccapy-shell.js` + - Confirmed UI has text-based controls and existing regions for titlebar, preview, DRO, G-code, status sidebar, info tabs, override, spindle/coolant, bottom controls. +- `sed -n '1,280p' /home/meswork/cnc_wams/web-rtcp-5axis-sim-plan/app/src/state/store.js` + - Confirmed store state includes machine state, run state, kinematics/interpreter/task-HAL runtime status, machine-file staging, DRO, feed, spindle, coolant, preview, tool preview. +- `sed -n '1,240p' /home/meswork/cnc_wams/web-rtcp-5axis-sim-plan/tests/node/verify_run_preconditions.mjs` + - Confirmed existing run-precondition tests cover profile/INI/kinematics/machine-file readiness and task policy gates. + +Existing evidence paths checked: +- `find /home/meswork/cnc_wams/qa/web-rtcp-5axis-site-test/output -maxdepth 2 -type f | sort` + - Confirmed existing QA JSON/PDF/DOCX/screenshots including button control evidence, cloud run evidence, native task/HAL comparison, toolpath preview cases, run preconditions feedback, and LinuxCNC source run reports. +- `find /home/meswork/cnc_wams/web-rtcp-5axis-sim-plan/build -maxdepth 3 -type f | sort` + - Confirmed `build/readiness/native-task-hal-readiness.json`. +- `find /home/meswork/cnc_wams/web-rtcp-5axis-sim-plan/working_run/run-feedback-evidence -maxdepth 1 -type f | sort` + - Confirmed `run-feedback-local.json` and `run-feedback-local.png`. + +Files created with `apply_patch`: +- `/home/meswork/cnc_wams/work/working4/README.md` + - Index for the generated working4 document set. +- `/home/meswork/cnc_wams/work/working4/01-function-content.md` + - Functional scope, current project state, working3 value, proposed feature packages, non-goals, success definition. +- `/home/meswork/cnc_wams/work/working4/02-program-development-steps.md` + - Development plan by stages: asset ingestion, gmoccapy_XYZAB profile, communication diagnostics, icon mapping, gates, HAL/postgui diagnostics, browser evidence. +- `/home/meswork/cnc_wams/work/working4/03-progress-ledger.md` + - Progress ledger with initial W4-DOC-001 entry and future entry template. +- `/home/meswork/cnc_wams/work/working4/04-task-matrix.md` + - Task matrix with IDs, statuses, files, and acceptance standards. +- `/home/meswork/cnc_wams/work/working4/05-acceptance-evidence.md` + - Evidence ledger for current document output, reusable existing evidence, future required evidence, job/report table, and gaps. +- `/home/meswork/cnc_wams/work/working4/06-decision-records.md` + - Decision records ADR-001 through ADR-008 covering source input policy, no GTK port, XYZAB/trivkins boundary, NML/HAL diagnostics, icons vs semantics, three-layer gate model, postgui ordering, and evidence-first promotion. + +Validation commands executed: +- `find /home/meswork/cnc_wams/work/working4 -maxdepth 1 -type f -printf '%f\n' | sort` + - Confirmed files: + - `01-function-content.md` + - `02-program-development-steps.md` + - `03-progress-ledger.md` + - `04-task-matrix.md` + - `05-acceptance-evidence.md` + - `06-decision-records.md` + - `README.md` +- `rg -n "功能内容|程序开发详细步骤|推进台账|任务矩阵|验收证据|决策记录|gmoccapy-xyzab|working3|working4" /home/meswork/cnc_wams/work/working4` + - Confirmed required sections and key terms appear across the document set. +- `git diff --check -- /home/meswork/cnc_wams/work/working4` + - Result: success, no whitespace errors reported. +- `wc -l /home/meswork/cnc_wams/work/working4/*.md` + - Confirmed total document size: 970 lines. + - Per file: + - `01-function-content.md`: 98 lines. + - `02-program-development-steps.md`: 316 lines. + - `03-progress-ledger.md`: 101 lines. + - `04-task-matrix.md`: 85 lines. + - `05-acceptance-evidence.md`: 155 lines. + - `06-decision-records.md`: 160 lines. + - `README.md`: 55 lines. +- `date '+%Y-%m-%d %H:%M:%S %Z'` + - Result: `2026-06-26 10:10:14 EDT`. +- `git status --short -- work/working4 web-rtcp-5axis-sim-plan/gptlog-process/gpdlog.md` + - Before appending this log, showed `?? work/working4/`. +- `git diff --stat -- work/working4` + - No stat output because the files were untracked at that moment. + +Result: +- Completed the requested working4 documentation set. +- Did not modify application source code in `web-rtcp-5axis-sim-plan/app/src`. +- Did not run app build or smoke tests because this turn only generated planning/traceability documents and did not alter runtime code. +- Appended this execution process log to `web-rtcp-5axis-sim-plan/gptlog-process/gpdlog.md` per workspace rule. + +Next recommended implementation step: +- Start with `W4-A01` and `W4-A02` from `work/working4/04-task-matrix.md`: + - Create `web-rtcp-5axis-sim-plan/docs/gmoccapy-xyzab-reference.md`. + - Convert the gmoccapy button CSV inventory into a Web-consumable JSON manifest. + +--- + +## GPT/Codex execution log - W4-IMPL-001 gmoccapy XYZAB reference/profile/models + +Timestamp: 2026-06-26 10:43:51 EDT +Workspace: `/home/meswork/cnc_wams` +User request: `按“/home/meswork/cnc_wams/work/working4“开始工作` + +Process summary: +- Read workspace instruction from user-provided AGENTS content: append full process log after execution to `web-rtcp-5axis-sim-plan/gptlog-process/gpdlog.md`. +- Started from `/home/meswork/cnc_wams/work/working4` as requested. +- Read `work/working4/README.md`, `01-function-content.md`, `02-program-development-steps.md`, `03-progress-ledger.md`, `04-task-matrix.md`, `05-acceptance-evidence.md`, and `06-decision-records.md`. +- Identified first todo group as W4-A01 through W4-A04, then proceeded through reference profile/model/test work that could be verified independently. +- Checked dirty worktree with `git status --short`; existing `web-rtcp-5axis-sim-plan/gptlog-process/gpdlog.md` was already modified and `work/working4/` was untracked. + +Repository context inspected: +- `rg --files web-rtcp-5axis-sim-plan/app/src` +- `rg --files web-rtcp-5axis-sim-plan/tests` +- `sed -n '1,260p' web-rtcp-5axis-sim-plan/app/src/profiles/index.js` +- `sed -n '1,300p' web-rtcp-5axis-sim-plan/app/src/profiles/xyzac-trt.js` +- `sed -n '1,300p' web-rtcp-5axis-sim-plan/app/src/profiles/xyzbc-trt.js` +- `sed -n '1,360p' web-rtcp-5axis-sim-plan/app/src/profiles/source-reference-map.js` +- `sed -n '1,260p' web-rtcp-5axis-sim-plan/tests/node/verify_profile_boundary.mjs` +- `sed -n '1,300p' web-rtcp-5axis-sim-plan/tests/node/verify_run_preconditions.mjs` +- `sed -n '1,340p' web-rtcp-5axis-sim-plan/app/src/state/linuxcnc-task-policy.js` +- `sed -n '1,380p' web-rtcp-5axis-sim-plan/app/src/state/store.js` +- `sed -n '280,620p' web-rtcp-5axis-sim-plan/app/src/ui/gmoccapy-shell.js` +- `sed -n '2200,2365p' web-rtcp-5axis-sim-plan/app/src/state/store.js` +- `sed -n '1,260p' web-rtcp-5axis-sim-plan/app/src/runtime/linuxcnc-boundary-adapter.js` +- `cat web-rtcp-5axis-sim-plan/app/package.json` +- `sed -n '1,260p' web-rtcp-5axis-sim-plan/app/scripts/build-static.mjs` +- `sed -n '1,240p' web-rtcp-5axis-sim-plan/app/src/runtime/rtcp-frame.js` + +working3/LinuxCNC inputs inspected: +- `sed -n '1,260p' /home/meswork/cnc_wams/work/working3/gmoccapy_XYZAB_execution_analysis.md` +- `sed -n '260,620p' /home/meswork/cnc_wams/work/working3/gmoccapy_XYZAB_execution_analysis.md` +- `sed -n '620,980p' /home/meswork/cnc_wams/work/working3/gmoccapy_XYZAB_execution_analysis.md` +- `sed -n '1,80p' /home/meswork/cnc_wams/work/working3/gmoccapy_button_icons/button_icon_inventory.csv` +- `wc -l /home/meswork/cnc_wams/work/working3/gmoccapy_button_icons/button_icon_inventory.csv` returned 212 lines including header. +- `find /home/meswork/cnc_wams/work/working3 -maxdepth 4 -type f | sort` confirmed CSV, Markdown inventory, and copied icon files. +- `sed -n '1,260p' linuxcnc/configs/sim/gmoccapy/gmoccapy_XYZAB.ini` +- `sed -n '1,260p' linuxcnc/configs/sim/gmoccapy/core_sim_XYZAB.hal` +- `sed -n '1,220p' linuxcnc/configs/sim/gmoccapy/gmoccapy_postgui.hal` +- `sed -n '1,180p' linuxcnc/configs/sim/gmoccapy/spindle_sim.hal` +- `sed -n '1,160p' linuxcnc/configs/sim/gmoccapy/simulated_home.hal` +- `sed -n '1,220p' linuxcnc/configs/sim/gmoccapy/tool.tbl` +- Verified `linuxcnc/src/emc/kinematics/trivkins.c` exists. +- Verified `wasm-port/vendor/linuxcnc/configs/sim/gmoccapy` does not exist, so `gmoccapy-xyzab` must remain reference-only and not use machine-file staging. + +Asset/manifest generation: +- Ran a Node CSV conversion script that: + - Parsed `work/working3/gmoccapy_button_icons/button_icon_inventory.csv`. + - Wrote `web-rtcp-5axis-sim-plan/app/src/ui-reference/gmoccapy-button-icons.json`. + - Copied icon files from `work/working3/gmoccapy_button_icons/files/` to `web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/`. +- Output: + - `manifest_entries=211` + - `copied_icons=112` +- Verified: + - `find web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons -maxdepth 1 -type f | wc -l` returned `112`. + - Manifest JSON parse check printed `211 112 rbt_auto app/src/assets/gmoccapy-icons/img_auto_on__mode_auto_active__48.png`. + +Files added: +- `web-rtcp-5axis-sim-plan/docs/gmoccapy-xyzab-reference.md` +- `web-rtcp-5axis-sim-plan/app/src/ui-reference/gmoccapy-button-icons.json` +- `web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/` with 112 copied PNG/SVG files +- `web-rtcp-5axis-sim-plan/app/src/profiles/gmoccapy-xyzab.js` +- `web-rtcp-5axis-sim-plan/app/src/runtime/gmoccapy-communication-model.js` +- `web-rtcp-5axis-sim-plan/app/src/runtime/gmoccapy-hal-model.js` +- `web-rtcp-5axis-sim-plan/tests/node/verify_gmoccapy_xyzab_profile.mjs` +- `web-rtcp-5axis-sim-plan/tests/node/verify_gmoccapy_icon_manifest.mjs` +- `web-rtcp-5axis-sim-plan/tests/node/verify_gmoccapy_communication_model.mjs` +- `web-rtcp-5axis-sim-plan/tests/node/verify_gmoccapy_hal_model.mjs` + +Files modified: +- `web-rtcp-5axis-sim-plan/app/package.json` + - Added new gmoccapy tests to `smoke:node`. +- `web-rtcp-5axis-sim-plan/app/src/profiles/index.js` + - Registered `gmoccapyXyzabProfile`. +- `web-rtcp-5axis-sim-plan/app/src/profiles/source-reference-map.js` + - Added gmoccapy_XYZAB INI/HAL/postgui/trivkins/gui/glade/icon/doc references. +- `web-rtcp-5axis-sim-plan/app/src/runtime/rtcp-frame.js` + - Generalized fixture joint-pose axis mapping from profile coordinates so XYZAB maps joint 4 to B instead of C. +- `web-rtcp-5axis-sim-plan/app/src/state/store.js` + - Added protection for `tcpCapable=false` profiles in `SET_RTCP` and `SET_KINS_TYPE`. + - Updated RUN_READY TCP behavior to only enable RTCP when the selected profile actually has a tcp switchkins type. + - Removed default `tcp-xyzac` fallback from MDI TCP resolution for non-TCP profiles. +- `web-rtcp-5axis-sim-plan/app/src/ui/gmoccapy-shell.js` + - Disabled TCP sidebar button for profiles without a TCP kins type and added a reference-only title reason. +- `web-rtcp-5axis-sim-plan/docs/traceability-matrix.md` + - Added gmoccapy_XYZAB profile, communication model, HAL model, and icon manifest traceability rows. +- `web-rtcp-5axis-sim-plan/tests/node/verify_profile_boundary.mjs` + - Updated expected profile list to include `gmoccapy-xyzab` and added reference-only assertions. +- `web-rtcp-5axis-sim-plan/tests/node/verify_rtcp_store.mjs` + - Updated available profile assertion for the third profile. +- `work/working4/03-progress-ledger.md` + - Added W4-IMPL-001 ledger entry. +- `work/working4/04-task-matrix.md` + - Marked W4-A01..A04, W4-P01..P04, W4-T01..T04, W4-T08, W4-V01..V05 done; left UI icon integration, gate expansion, QA report/screenshot tasks todo. +- `work/working4/05-acceptance-evidence.md` + - Added W4-IMPL-001 evidence with commands, outputs, manifest counts, and remaining gaps. +- `work/working4/06-decision-records.md` + - Added ADR-009: gmoccapy_XYZAB profile must block TCP/RTCP switching. + +Important implementation decisions: +- `gmoccapy-xyzab` is selectable but remains `trivkins coordinates=xyzab`, `tcpCapable=false`, `rtcpProof=false`, `promotionAllowed=false`. +- UI and store both prevent TCP/RTCP activation for `gmoccapy-xyzab`. +- Existing source-derived runtime proof remains with `xyzac-trt` and `xyzbc-trt`. +- Button manifest and copied icons are treated as UI asset provenance only, not control semantics proof. +- Communication and HAL/postgui models are data/test additions only in this turn; they are not yet rendered in the info panel. + +Validation commands and results: +- `node web-rtcp-5axis-sim-plan/tests/node/verify_gmoccapy_xyzab_profile.mjs` + - `gmoccapy_xyzab_profile_smoke=ok` +- `node web-rtcp-5axis-sim-plan/tests/node/verify_gmoccapy_icon_manifest.mjs` + - Initially failed because test expected non-existent CSV IDs `btn_view_x` etc.; inspected manifest and corrected test IDs to `rbt_view_x/y/z/p`, `tbtn_view_tool_path`, `tbtn_view_dimension`. + - Final result: `gmoccapy_icon_manifest_smoke=ok` +- `node web-rtcp-5axis-sim-plan/tests/node/verify_gmoccapy_communication_model.mjs` + - `gmoccapy_communication_model_smoke=ok` +- `node web-rtcp-5axis-sim-plan/tests/node/verify_gmoccapy_hal_model.mjs` + - `gmoccapy_hal_model_smoke=ok` +- `node web-rtcp-5axis-sim-plan/tests/node/verify_profile_boundary.mjs` + - `profile_boundary_smoke=ok` +- `node web-rtcp-5axis-sim-plan/tests/node/verify_rtcp_store.mjs` + - Initially failed because existing test expected `availableProfiles.length === 2`; updated assertion to expected IDs `xyzac-trt`, `xyzbc-trt`, `gmoccapy-xyzab`. + - Final result: `rtcp_store_smoke=ok` +- `npm --prefix web-rtcp-5axis-sim-plan/app run build` + - `gmoccapy_static_build=ok` +- `npm --prefix web-rtcp-5axis-sim-plan/app run smoke:node` + - Passed all chained tests, including: + - `profile_boundary_smoke=ok` + - `gmoccapy_xyzab_profile_smoke=ok` + - `gmoccapy_icon_manifest_smoke=ok` + - `gmoccapy_communication_model_smoke=ok` + - `gmoccapy_hal_model_smoke=ok` + - `linear_unit_conversion_smoke=ok` +- `bash web-rtcp-5axis-sim-plan/tests/browser/verify_gmoccapy_shell_browser.sh` + - `gmoccapy_shell_smoke=ok` +- `bash web-rtcp-5axis-sim-plan/tests/browser/verify_gmoccapy_dist_browser.sh` + - `gmoccapy_dist_smoke=ok` +- `git diff --check -- web-rtcp-5axis-sim-plan work/working4` + - Returned 0 with no whitespace errors. +- Final asset check: + - `find web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons -maxdepth 1 -type f | wc -l` returned `112`. + - Manifest check printed `manifest 211 112`. + +Final git status summary: +- Modified tracked files: + - `web-rtcp-5axis-sim-plan/app/package.json` + - `web-rtcp-5axis-sim-plan/app/src/profiles/index.js` + - `web-rtcp-5axis-sim-plan/app/src/profiles/source-reference-map.js` + - `web-rtcp-5axis-sim-plan/app/src/runtime/rtcp-frame.js` + - `web-rtcp-5axis-sim-plan/app/src/state/store.js` + - `web-rtcp-5axis-sim-plan/app/src/ui/gmoccapy-shell.js` + - `web-rtcp-5axis-sim-plan/docs/traceability-matrix.md` + - `web-rtcp-5axis-sim-plan/gptlog-process/gpdlog.md` + - `web-rtcp-5axis-sim-plan/tests/node/verify_profile_boundary.mjs` + - `web-rtcp-5axis-sim-plan/tests/node/verify_rtcp_store.mjs` +- Untracked new files/directories: + - `web-rtcp-5axis-sim-plan/app/src/assets/` + - `web-rtcp-5axis-sim-plan/app/src/profiles/gmoccapy-xyzab.js` + - `web-rtcp-5axis-sim-plan/app/src/runtime/gmoccapy-communication-model.js` + - `web-rtcp-5axis-sim-plan/app/src/runtime/gmoccapy-hal-model.js` + - `web-rtcp-5axis-sim-plan/app/src/ui-reference/` + - `web-rtcp-5axis-sim-plan/docs/gmoccapy-xyzab-reference.md` + - `web-rtcp-5axis-sim-plan/tests/node/verify_gmoccapy_communication_model.mjs` + - `web-rtcp-5axis-sim-plan/tests/node/verify_gmoccapy_hal_model.mjs` + - `web-rtcp-5axis-sim-plan/tests/node/verify_gmoccapy_icon_manifest.mjs` + - `web-rtcp-5axis-sim-plan/tests/node/verify_gmoccapy_xyzab_profile.mjs` + - `work/working4/` + +Remaining work intentionally left todo: +- W4-U01..U05: icon registry and actual UI icon integration, plus communication/HAL diagnostics rendering in info panel. +- W4-G01..G05 and W4-T05: dedicated gmoccapy_XYZAB gate expansion/test. +- W4-T06..T07: browser smoke extensions and QA JSON/PDF/screenshot report. + +Result: W4-A/W4-P/W4-T01..T04/W4-V implementation slice completed and verified. + +--- + +## Codex execution log - W4-IMPL-002 + +Timestamp: 2026-06-26 15:08:32 EDT +Workspace: `/home/meswork/cnc_wams` +User request: Continue the previous round and finish the work under `/home/meswork/cnc_wams/work/working4`. + +Process followed: +1. Inspected `work/working4/README.md`, `03-progress-ledger.md`, `04-task-matrix.md`, `05-acceptance-evidence.md`, `01-function-content.md`, `02-program-development-steps.md`, and `06-decision-records.md`. +2. Confirmed previous round had completed W4-A and W4-P items, with remaining todo items in UI/icon integration, communication/HAL diagnostics rendering, gmoccapy_XYZAB gates, browser smoke, and QA report generation. +3. Inspected existing implementation files: + - `app/src/ui/gmoccapy-shell.js` + - `app/src/styles/gmoccapy.css` + - `app/src/state/store.js` + - `app/src/state/linuxcnc-task-policy.js` + - existing tests under `tests/node/` and `tests/browser/` + - existing QA capture scripts under `qa/web-rtcp-5axis-site-test/` +4. Implemented a focused gmoccapy icon registry and wired it into current shell rendering without introducing a frontend framework or runtime dependency on `work/working3`. +5. Extended the info panel to render gmoccapy communication and HAL/postgui diagnostics from the already-created models. +6. Extended task policy for gmoccapy_XYZAB gate semantics while preserving existing `xyzac-trt`/`xyzbc-trt` runtime behavior. +7. Added spindle direction state and gate-guarded spindle/coolant/override store actions. +8. Added Node tests for icon registry and gmoccapy_XYZAB gate behavior. +9. Updated browser smoke to assert core icon DOM attributes and gmoccapy NML/HAL diagnostics. +10. Added a QA capture script that generates JSON/PDF/screenshots for gmoccapy_XYZAB function evidence. +11. Updated `work/working4/03-progress-ledger.md`, `04-task-matrix.md`, and `05-acceptance-evidence.md` with current status and evidence. +12. Ran targeted tests, full smoke tests, browser tests, QA capture, and whitespace checks. + +Files added: +- `web-rtcp-5axis-sim-plan/app/src/ui/gmoccapy-icon-registry.js` +- `web-rtcp-5axis-sim-plan/tests/node/verify_gmoccapy_icon_registry.mjs` +- `web-rtcp-5axis-sim-plan/tests/node/verify_gmoccapy_xyzab_gates.mjs` +- `qa/web-rtcp-5axis-site-test/capture-gmoccapy-xyzab-function-cases.mjs` +- `qa/web-rtcp-5axis-site-test/output/gmoccapy-xyzab-function-report.json` +- `qa/web-rtcp-5axis-site-test/output/gmoccapy-xyzab-function-report.pdf` +- `qa/web-rtcp-5axis-site-test/output/gmoccapy-xyzab/01-loaded.png` +- `qa/web-rtcp-5axis-site-test/output/gmoccapy-xyzab/02-profile-selected.png` +- `qa/web-rtcp-5axis-site-test/output/gmoccapy-xyzab/03-run-blocked-power.png` +- `qa/web-rtcp-5axis-site-test/output/gmoccapy-xyzab/04-run-blocked-reference-evidence.png` +- `qa/web-rtcp-5axis-site-test/output/gmoccapy-xyzab/05-controls-active.png` +- `qa/web-rtcp-5axis-site-test/output/gmoccapy-xyzab/06-hal-diagnostics.png` + +Files updated in this execution: +- `web-rtcp-5axis-sim-plan/app/package.json` +- `web-rtcp-5axis-sim-plan/app/src/state/linuxcnc-task-policy.js` +- `web-rtcp-5axis-sim-plan/app/src/state/store.js` +- `web-rtcp-5axis-sim-plan/app/src/styles/gmoccapy.css` +- `web-rtcp-5axis-sim-plan/app/src/ui/gmoccapy-shell.js` +- `web-rtcp-5axis-sim-plan/tests/browser/gmoccapy_shell_smoke.html` +- `work/working4/03-progress-ledger.md` +- `work/working4/04-task-matrix.md` +- `work/working4/05-acceptance-evidence.md` +- `web-rtcp-5axis-sim-plan/gptlog-process/gpdlog.md` + +Important fixes/adjustments during validation: +- Initial `verify_gmoccapy_xyzab_gates.mjs` fixture lacked fields required by `applyIniConfigToProfile`; added minimal profile-derived INI structures. +- Initial strict RUN/JOG/HOME policy was too broad and broke existing `verify_rtcp_store.mjs`; narrowed strict RUN checks to `gmoccapy-xyzab`. +- Full `smoke:node` initially failed in `verify_linuxcnc_task_hal_runtime.mjs` because JOG/HOME gating treated a manual-mode stale `runState=running` as active AUTO execution. Adjusted running detection to block JOG/HOME only for AUTO reading/waiting/running, preserving the existing task/HAL HOME/JOG continuity behavior. +- One build attempt failed with `ENOTEMPTY` because `npm run build` and dist browser smoke were run in parallel against `app/dist`; reran build sequentially and it passed. This was a command concurrency issue, not a source failure. + +Validation commands and final results: +- `node --check web-rtcp-5axis-sim-plan/app/src/ui/gmoccapy-shell.js` + - Passed. +- `node --check web-rtcp-5axis-sim-plan/app/src/state/store.js` + - Passed. +- `node --check web-rtcp-5axis-sim-plan/app/src/state/linuxcnc-task-policy.js` + - Passed. +- `node --check qa/web-rtcp-5axis-site-test/capture-gmoccapy-xyzab-function-cases.mjs` + - Passed. +- `node web-rtcp-5axis-sim-plan/tests/node/verify_gmoccapy_icon_registry.mjs` + - `gmoccapy_icon_registry_smoke=ok` +- `node web-rtcp-5axis-sim-plan/tests/node/verify_gmoccapy_xyzab_gates.mjs` + - `gmoccapy_xyzab_gates_smoke=ok` +- `node web-rtcp-5axis-sim-plan/tests/node/verify_rtcp_store.mjs` + - `rtcp_store_smoke=ok` +- `node web-rtcp-5axis-sim-plan/tests/node/verify_run_preconditions.mjs` + - `run_preconditions_ini_profile_smoke=ok` + - `run_preconditions_kinematics_smoke=ok` + - `run_preconditions_machine_file_smoke=ok` +- `node web-rtcp-5axis-sim-plan/tests/node/verify_linuxcnc_task_hal_runtime.mjs` + - `linuxcnc_task_hal_runtime_smoke=ok` + - `task_hal_machine_file_smoke=ok` + - `switchkins_remap_hal_sync_smoke=ok` + - `browser_task_hal_worker_smoke=ok` +- `npm --prefix web-rtcp-5axis-sim-plan/app run smoke:node` + - Passed all chained Node tests, including `gmoccapy_icon_registry_smoke=ok` and `gmoccapy_xyzab_gates_smoke=ok`. +- `npm --prefix web-rtcp-5axis-sim-plan/app run build` + - Final sequential run: `gmoccapy_static_build=ok` +- `bash web-rtcp-5axis-sim-plan/tests/browser/verify_gmoccapy_shell_browser.sh` + - `gmoccapy_shell_smoke=ok` +- `bash web-rtcp-5axis-sim-plan/tests/browser/verify_gmoccapy_dist_browser.sh` + - `gmoccapy_dist_smoke=ok` +- `node qa/web-rtcp-5axis-site-test/capture-gmoccapy-xyzab-function-cases.mjs` + - `gmoccapy_xyzab_function_status=PASS` + - `gmoccapy_xyzab_function_job_id=xyzab-20260626190724-7b80b3aa` + - `gmoccapy_xyzab_function_report_id=report-xyzab-20260626190724-7b80b3aa` + - JSON: `/home/meswork/cnc_wams/qa/web-rtcp-5axis-site-test/output/gmoccapy-xyzab-function-report.json` + - PDF: `/home/meswork/cnc_wams/qa/web-rtcp-5axis-site-test/output/gmoccapy-xyzab-function-report.pdf` + - Screenshots: `/home/meswork/cnc_wams/qa/web-rtcp-5axis-site-test/output/gmoccapy-xyzab/` +- `git diff --check -- web-rtcp-5axis-sim-plan qa/web-rtcp-5axis-site-test work/working4` + - Returned 0 with no whitespace errors. + +QA report checks from JSON: +- PASS XYZAB profile selected +- PASS Reference profile blocks RTCP promotion +- PASS RUN blocked before power +- PASS RUN blocked by reference evidence +- PASS Core icons rendered +- PASS Spindle/coolant state updates +- PASS NML command diagnostic +- PASS Web runtime diagnostic +- PASS HAL postgui diagnostic +- PASS Screenshots are nonblank + +Task matrix outcome: +- Marked W4-U01..W4-U05 done. +- Marked W4-G01..W4-G05 done. +- Marked W4-T05..W4-T07 done. +- Updated W4 evidence with current JSON/PDF/screenshots and latest job/report IDs. + +Final note: +- `gmoccapy-xyzab` remains a `trivkins` reference-only profile. This work validates UI assets, diagnostics, task gate semantics, blocked reasons, and reporting evidence; it does not promote XYZAB as TCP/RTCP proof or native LinuxCNC realtime execution. + +--- + +## 2026-06-26 15:11:55 EDT - working4 remaining-work completion check + +User request: +- Continue and finish remaining work in `/home/meswork/cnc_wams/work/working4`. + +Process: +- Checked `work/working4/04-task-matrix.md` for task rows still in `todo`, `in_progress`, `blocked`, or `deferred`; none were found. +- Checked `work/working4/04-task-matrix.md` and `work/working4/05-acceptance-evidence.md` for stale TODO/pending markers. Remaining `blocked` matches were status vocabulary, expected QA screenshot names/check labels, and completed gate evidence text. +- Parsed `qa/web-rtcp-5axis-site-test/output/gmoccapy-xyzab-function-report.json`; result was `status=PASS`, `steps=6`, `checks=10`. +- Ran `git diff --check -- web-rtcp-5axis-sim-plan qa/web-rtcp-5axis-site-test work/working4`; returned 0. +- Updated `work/working4/04-task-matrix.md` wording for W4-D06 and W4-T08 to remove stale "pending evidence" wording from completed rows. +- Re-ran the remaining-task scan, QA JSON status check, and whitespace check after the wording update. The final task-row scan still found no unfinished W4 task rows; the final QA report status remained `PASS`; the final whitespace check returned 0. + +Outcome: +- No remaining `working4` task-matrix work was found. +- `gmoccapy-xyzab-function-report.json` remains PASS with 6 steps and 10 checks. +- Only documentation wording was changed in this continuation pass, plus this required process-log append. + +Addendum: +- After the log append, ran `git diff --check -- web-rtcp-5axis-sim-plan qa/web-rtcp-5axis-site-test work/working4`; returned 0. +- Checked focused status for `work/working4/04-task-matrix.md` and `web-rtcp-5axis-sim-plan/gptlog-process/gpdlog.md`; status showed the required log file modified and `work/working4/04-task-matrix.md` present as an untracked working file. +- Appended this addendum as the final tool action for this execution. + +--- + +## 2026-06-26 15:17:57 EDT - working4 status-document closure + +User request: +- Continue completing `/home/meswork/cnc_wams/work/working4`. + +Process: +- Inspected git status for `work/working4`, `web-rtcp-5axis-sim-plan`, and `qa/web-rtcp-5axis-site-test`. +- Checked `work/working4/04-task-matrix.md` for unfinished W4 task rows; none were found. +- Read `work/working4/README.md`, `01-function-content.md`, `02-program-development-steps.md`, `03-progress-ledger.md`, `04-task-matrix.md`, and `05-acceptance-evidence.md`. +- Found remaining planning-era wording in `README.md`, `01-function-content.md`, `02-program-development-steps.md`, and `05-acceptance-evidence.md`: the docs still described the stage as planning-only, had feature package rows marked pending/partial, and mentioned no job/report IDs even though implementation and QA evidence now exist. +- Updated `README.md` to state that working4 is implemented, verified, and archived, with the current boundary that `gmoccapy-xyzab` remains reference-only. +- Updated `01-function-content.md` to mark F-XYZAB-01 through F-XYZAB-07 as completed or boundary-completed, and adjusted the success definition to the actual evidence scope. +- Updated `02-program-development-steps.md` to state that phases A through G are complete and that JSON/PDF QA capture is generated. +- Updated `04-task-matrix.md` with W4-D08 for status-document closure and updated W4-V05 to include the QA path in `git diff --check`. +- Updated `05-acceptance-evidence.md` to remove the obsolete "documentation only/no job_id" wording, add icon registry/dist smoke/whitespace evidence rows, and change the document task range to W4-D01 through W4-D08. +- Updated `03-progress-ledger.md` with W4-DOC-002, including files changed, validation commands, results, retained semantic boundaries, and final next step. + +Validation: +- `rg -n "\\| W4-[A-Z0-9-]+ \\| (todo|in_progress|blocked|deferred) \\|" work/working4/04-task-matrix.md || true` + - Returned no unfinished task rows. +- `rg -n "待实施|待验证|待生成|PDF 任务保持 todo|本轮只创建文档|没有生成新的 job_id|后续新增:|TODO" work/working4/README.md work/working4/01-function-content.md work/working4/02-program-development-steps.md work/working4/05-acceptance-evidence.md || true` + - Returned no stale current-state wording. +- `node -e "const r=JSON.parse(require('fs').readFileSync('qa/web-rtcp-5axis-site-test/output/gmoccapy-xyzab-function-report.json','utf8')); if(r.status!=='PASS') process.exit(1); console.log('qa_report_status='+r.status); console.log('qa_report_steps='+r.steps.length); console.log('qa_report_checks='+r.checks.length);"` + - `qa_report_status=PASS` + - `qa_report_steps=6` + - `qa_report_checks=10` +- `git diff --check -- web-rtcp-5axis-sim-plan qa/web-rtcp-5axis-site-test work/working4` + - Returned 0. + +Outcome: +- `working4` no longer has current task rows pending or current status docs saying the work is still planning-only/pending. +- The remaining caveats are intentional semantic boundaries: `gmoccapy-xyzab` is still a `trivkins` reference-only profile and this stage does not prove native LinuxCNC realtime execution. + +--- + +## 2026-06-26 15:20:53 EDT - working4 wording finalization + +User request: +- Continue completing `/home/meswork/cnc_wams/work/working4`. + +Process: +- Re-scanned `work/working4/04-task-matrix.md` for W4 rows still in `todo`, `in_progress`, `blocked`, or `deferred`; none were found. +- Re-scanned current state docs for stale planning wording such as pending implementation, pending validation, pending PDF generation, documentation-only state, missing job_id/report_id, and planning-only headings. +- Inspected `work/working4/06-decision-records.md`, `04-task-matrix.md`, and `03-progress-ledger.md`. +- Identified remaining wording that was not a functional gap but could make the archive look like a plan rather than a completed record: + - `README.md` document descriptions still said "to be improved" and "files to change". + - `02-program-development-steps.md` used "suggested new or updated files" throughout completed phases. + - `03-progress-ledger.md` preserved early historical "remaining issues" without a top-level note explaining that later W4 entries closed them. + - `04-task-matrix.md` still said W4-D01 listed a future execution entry and W4-T07 output PDF only "if needed". +- Updated `README.md` to describe `01-function-content.md` and `02-program-development-steps.md` as completed/recorded content. +- Updated `02-program-development-steps.md` wording from planning suggestions to archived "main new or updated files". +- Added a note near the top of `03-progress-ledger.md` that early remaining issues and next steps are historical and that current state is governed by the task matrix and acceptance evidence. +- Updated the W4-DOC-002 ledger entry to include the `02-program-development-steps.md` wording closure. +- Updated `04-task-matrix.md` W4-D01 and W4-T07 acceptance wording to match the completed archive state. +- Added W4-DOC-003 to `03-progress-ledger.md` for this final wording cleanup. + +Validation: +- `rg -n "\\| W4-[A-Z0-9-]+ \\| (todo|in_progress|blocked|deferred) \\|" work/working4/04-task-matrix.md || true` + - Returned no unfinished W4 task rows. +- `rg -n "待实施|待验证|待生成|PDF 任务保持 todo|本轮只创建文档|没有生成新的 job_id|后续新增:|建议新增|建议新增或更新|必要时输出 PDF|后续执行入口|拟完善功能包|TODO" work/working4/README.md work/working4/01-function-content.md work/working4/02-program-development-steps.md work/working4/04-task-matrix.md work/working4/05-acceptance-evidence.md || true` + - Returned no stale planning/current-state wording. +- `node -e "const r=JSON.parse(require('fs').readFileSync('qa/web-rtcp-5axis-site-test/output/gmoccapy-xyzab-function-report.json','utf8')); if(r.status!=='PASS') process.exit(1); console.log('qa_report_status='+r.status); console.log('qa_report_steps='+r.steps.length); console.log('qa_report_checks='+r.checks.length);"` + - `qa_report_status=PASS` + - `qa_report_steps=6` + - `qa_report_checks=10` +- `git diff --check -- web-rtcp-5axis-sim-plan qa/web-rtcp-5axis-site-test work/working4` + - Returned 0. +- After adding W4-DOC-003, re-ran the W4 task-row scan, stale current-state wording scan, and `git diff --check`; all remained clean. + +Outcome: +- No additional implementation work was needed. +- `working4` docs now read consistently as a completed implementation/evidence archive. +- The only retained caveats are the intended semantic boundaries: `gmoccapy-xyzab` is reference-only and this stage does not prove TCP/RTCP or native LinuxCNC realtime execution. + +--- + +## 2026-06-26 15:22:49 EDT - working4 recheck no-op closure + +User request: +- Continue completing `/home/meswork/cnc_wams/work/working4`. + +Process: +- Rechecked `work/working4/04-task-matrix.md` for W4 task rows in `todo`, `in_progress`, `blocked`, or `deferred`; none were found. +- Rechecked current state docs for stale planning/pending wording: + - `work/working4/README.md` + - `work/working4/01-function-content.md` + - `work/working4/02-program-development-steps.md` + - `work/working4/04-task-matrix.md` + - `work/working4/05-acceptance-evidence.md` +- Read recent `03-progress-ledger.md`, `README.md`, and the acceptance evidence summary to confirm the previous closure entries and retained semantic boundaries. +- Parsed `qa/web-rtcp-5axis-site-test/output/gmoccapy-xyzab-function-report.json`. +- Ran whitespace validation for the project, QA, and working4 paths. +- Checked focused git status for `work/working4`, `gpdlog.md`, and the gmoccapy QA report artifacts. + +Validation: +- W4 unfinished task-row scan returned no rows. +- Stale planning/current-state wording scan returned no rows. +- QA report remained `PASS` with 6 steps and 10 checks. +- `git diff --check -- web-rtcp-5axis-sim-plan qa/web-rtcp-5axis-site-test work/working4` returned 0. +- Focused git status showed expected uncommitted artifacts only: + - modified `web-rtcp-5axis-sim-plan/gptlog-process/gpdlog.md` + - untracked `work/working4/` + - untracked gmoccapy QA report JSON/PDF + +Outcome: +- No new code or documentation edits were needed for `working4` in this pass. +- `working4` remains complete as an implementation/evidence archive, with only the intentional reference-only/native-runtime caveats retained. + +--- + +## 2026-06-26 15:24:59 EDT - working4 QA id-field evidence clarification + +User request: +- Continue completing `/home/meswork/cnc_wams/work/working4`. + +Process: +- Rechecked `04-task-matrix.md` for unfinished W4 rows; none were found. +- Rechecked current state docs for stale planning or pending wording; none was found. +- Parsed `qa/web-rtcp-5axis-site-test/output/gmoccapy-xyzab-function-report.json` and initially checked snake_case `job_id/report_id`, which were empty because the JSON uses camelCase `jobId/reportId`. +- Inspected the QA report JSON structure and confirmed top-level fields include `jobId` and `reportId`. +- Read `qa/web-rtcp-5axis-site-test/capture-gmoccapy-xyzab-function-cases.mjs` and confirmed it writes `jobId/reportId` to JSON while printing `gmoccapy_xyzab_function_job_id` and `gmoccapy_xyzab_function_report_id` to stdout. +- Cross-checked `work/working4/05-acceptance-evidence.md` references for job/report IDs. +- Updated `05-acceptance-evidence.md` to clarify that QA JSON uses camelCase `jobId/reportId`, while console output and the archive table use `job_id/report_id` labels for the same identifiers. +- Added W4-DOC-004 to `03-progress-ledger.md` documenting this evidence-field clarification. + +Validation: +- `rg -n "\\| W4-[A-Z0-9-]+ \\| (todo|in_progress|blocked|deferred) \\|" work/working4/04-task-matrix.md || true` + - Returned no unfinished W4 task rows. +- `rg -n "待实施|待验证|待生成|PDF 任务保持 todo|本轮只创建文档|没有生成新的 job_id|后续新增:|建议新增|建议新增或更新|必要时输出 PDF|后续执行入口|拟完善功能包|TODO" work/working4/README.md work/working4/01-function-content.md work/working4/02-program-development-steps.md work/working4/04-task-matrix.md work/working4/05-acceptance-evidence.md || true` + - Returned no stale current-state wording. +- `node -e "const r=JSON.parse(require('fs').readFileSync('qa/web-rtcp-5axis-site-test/output/gmoccapy-xyzab-function-report.json','utf8')); if(r.status!=='PASS') process.exit(1); console.log('qa_report_jobId='+r.jobId); console.log('qa_report_reportId='+r.reportId); console.log('qa_report_status='+r.status); console.log('qa_report_steps='+r.steps.length); console.log('qa_report_checks='+r.checks.length);"` + - `qa_report_jobId=xyzab-20260626190724-7b80b3aa` + - `qa_report_reportId=report-xyzab-20260626190724-7b80b3aa` + - `qa_report_status=PASS` + - `qa_report_steps=6` + - `qa_report_checks=10` +- `git diff --check -- web-rtcp-5axis-sim-plan qa/web-rtcp-5axis-site-test work/working4` + - Returned 0. + +Outcome: +- No implementation changes were needed. +- `working4` evidence now explicitly documents the QA report field-name mapping, preventing future false-negative checks for `job_id/report_id`. + +--- + +## 2026-06-26 15:26:22 EDT - working4 clean recheck + +User request: +- Continue completing `/home/meswork/cnc_wams/work/working4`. + +Process: +- Rechecked `work/working4/04-task-matrix.md` for unfinished W4 task rows. +- Rechecked current state docs for stale planning/pending wording: + - `work/working4/README.md` + - `work/working4/01-function-content.md` + - `work/working4/02-program-development-steps.md` + - `work/working4/04-task-matrix.md` + - `work/working4/05-acceptance-evidence.md` +- Parsed `qa/web-rtcp-5axis-site-test/output/gmoccapy-xyzab-function-report.json` using `jobId/reportId`. +- Ran whitespace validation on `web-rtcp-5axis-sim-plan`, `qa/web-rtcp-5axis-site-test`, and `work/working4`. +- Checked focused git status for `work/working4`, `gpdlog.md`, and the gmoccapy QA report JSON/PDF. + +Validation: +- W4 unfinished task-row scan returned no rows. +- Stale current-state wording scan returned no rows. +- QA report remained `PASS`: + - `jobId=xyzab-20260626190724-7b80b3aa` + - `reportId=report-xyzab-20260626190724-7b80b3aa` + - `steps=6` + - `checks=10` +- `git diff --check -- web-rtcp-5axis-sim-plan qa/web-rtcp-5axis-site-test work/working4` returned 0. + +Outcome: +- No new `working4` work was found. +- No code or documentation changes were needed in this pass. + +--- + +## 2026-06-26 15:27:29 EDT - working4 no-op verification + +User request: +- Continue completing `/home/meswork/cnc_wams/work/working4`. + +Process: +- Ran the standard W4 unfinished-task scan against `work/working4/04-task-matrix.md`. +- Ran the current-state stale wording scan against the active `working4` docs. +- Parsed `qa/web-rtcp-5axis-site-test/output/gmoccapy-xyzab-function-report.json`. +- Ran `git diff --check -- web-rtcp-5axis-sim-plan qa/web-rtcp-5axis-site-test work/working4`. +- Checked focused status for `work/working4`, `gpdlog.md`, and the gmoccapy QA report JSON/PDF. + +Validation: +- No W4 rows were in `todo`, `in_progress`, `blocked`, or `deferred`. +- No stale current-state planning/pending wording was found. +- QA report remained `PASS`: + - `jobId=xyzab-20260626190724-7b80b3aa` + - `reportId=report-xyzab-20260626190724-7b80b3aa` + - `steps=6` + - `checks=10` +- `git diff --check` returned 0. + +Outcome: +- No new work was needed for `working4`. +- No `working4` source, evidence, or implementation files were changed in this pass. + +--- + +## 2026-06-26 15:32:48 EDT - working4 final closure page + +User request: +- Continue completing `/home/meswork/cnc_wams/work/working4`. + +Process: +- Performed a higher-level closure audit instead of only repeating keyword checks. +- Inspected the file list under `work/working4`; only README and documents 01 through 06 existed. +- Read `README.md`, `04-task-matrix.md`, and recent `03-progress-ledger.md`. +- Determined that the work was complete but the archive lacked a single final closure entry point summarizing completion, evidence, retained boundaries, and future-change rules. +- Added `work/working4/07-final-closure.md`. +- Updated `README.md` to mark `07-final-closure.md` as the final closure entry and add it to the document list and maintenance steps. +- Updated `04-task-matrix.md` with W4-D09 for the final closure document and adjusted W4-D01 to list 01-07 documents. +- Updated `03-progress-ledger.md` with W4-DOC-005. +- Updated `05-acceptance-evidence.md` to include `07-final-closure.md` in the document output list and extend the document closure row from W4-D01..W4-D08 to W4-D01..W4-D09. +- Fixed the stale-wording example command in `07-final-closure.md` so the command itself does not trip the stale-wording scan. +- Updated W4-DOC-005 results after validation. + +Validation: +- `rg -n "\\| W4-[A-Z0-9-]+ \\| (todo|in_progress|blocked|deferred) \\|" work/working4/04-task-matrix.md || true` + - Returned no unfinished W4 task rows. +- `rg -n "待实施|待验证|待生成|PDF 任务保持 todo|本轮只创建文档|没有生成新的 job_id|后续新增:|建议新增|建议新增或更新|必要时输出 PDF|后续执行入口|拟完善功能包|TODO" work/working4/README.md work/working4/01-function-content.md work/working4/02-program-development-steps.md work/working4/04-task-matrix.md work/working4/05-acceptance-evidence.md work/working4/07-final-closure.md || true` + - Returned no stale current-state wording. +- `node -e "const r=JSON.parse(require('fs').readFileSync('qa/web-rtcp-5axis-site-test/output/gmoccapy-xyzab-function-report.json','utf8')); if(r.status!=='PASS') process.exit(1); console.log('qa_report_jobId='+r.jobId); console.log('qa_report_reportId='+r.reportId); console.log('qa_report_status='+r.status); console.log('qa_report_steps='+r.steps.length); console.log('qa_report_checks='+r.checks.length);"` + - `qa_report_jobId=xyzab-20260626190724-7b80b3aa` + - `qa_report_reportId=report-xyzab-20260626190724-7b80b3aa` + - `qa_report_status=PASS` + - `qa_report_steps=6` + - `qa_report_checks=10` +- `git diff --check -- web-rtcp-5axis-sim-plan qa/web-rtcp-5axis-site-test work/working4` + - Returned 0. + +Outcome: +- `working4` now has a single final closure document: `work/working4/07-final-closure.md`. +- Task matrix and evidence archive are aligned through W4-D09. +- No implementation changes were needed. + +--- + +## 2026-06-26 15:34:24 EDT - working4 final closure recheck + +User request: +- Continue completing `/home/meswork/cnc_wams/work/working4`. + +Process: +- Verified `work/working4` file list includes README and documents 01 through 07. +- Rechecked `04-task-matrix.md` for unfinished W4 task rows; none were found. +- Rechecked current state docs, including `07-final-closure.md`, for stale planning/pending wording; none was found. +- Parsed `qa/web-rtcp-5axis-site-test/output/gmoccapy-xyzab-function-report.json`. +- Ran `git diff --check -- web-rtcp-5axis-sim-plan qa/web-rtcp-5axis-site-test work/working4`. +- Read `07-final-closure.md` to verify it contains the final conclusion, QA evidence paths, identifiers, retained boundaries, validation commands, and future-change rules. +- Checked focused git status for `work/working4`, `gpdlog.md`, and gmoccapy QA report JSON/PDF. + +Validation: +- File list includes `07-final-closure.md`. +- W4 unfinished task-row scan returned no rows. +- Stale current-state wording scan returned no rows. +- QA report remained `PASS`: + - `jobId=xyzab-20260626190724-7b80b3aa` + - `reportId=report-xyzab-20260626190724-7b80b3aa` + - `steps=6` + - `checks=10` +- `git diff --check` returned 0. + +Outcome: +- No additional `working4` edits were needed. +- Final closure documentation remains complete and consistent. + +--- + +## 2026-06-26 15:35:37 EDT - working4 final state verification + +User request: +- Continue completing `/home/meswork/cnc_wams/work/working4`. + +Process: +- Verified `work/working4/07-final-closure.md` exists. +- Rechecked `work/working4/04-task-matrix.md` for W4 rows in `todo`, `in_progress`, `blocked`, or `deferred`. +- Rechecked current state docs for stale planning/pending wording: + - `README.md` + - `01-function-content.md` + - `02-program-development-steps.md` + - `04-task-matrix.md` + - `05-acceptance-evidence.md` + - `07-final-closure.md` +- Parsed `qa/web-rtcp-5axis-site-test/output/gmoccapy-xyzab-function-report.json`. +- Ran `git diff --check -- web-rtcp-5axis-sim-plan qa/web-rtcp-5axis-site-test work/working4`. +- Checked focused git status for `work/working4`, `gpdlog.md`, and gmoccapy QA report JSON/PDF. + +Validation: +- `final_closure=present` +- No unfinished W4 task rows were found. +- No stale current-state wording was found. +- QA report remained `PASS`: + - `jobId=xyzab-20260626190724-7b80b3aa` + - `reportId=report-xyzab-20260626190724-7b80b3aa` + - `steps=6` + - `checks=10` +- `git diff --check` returned 0. + +Outcome: +- No new `working4` work was found. +- No source, evidence, or implementation files required changes in this pass. + +--- + +## 2026-06-26 17:46:14 EDT - working4 resumed validation and QA refresh + +User request: +- Continue the prior turn and finish the work under `/home/meswork/cnc_wams/work/working4`. +- The prior turn was intentionally interrupted by the user, then the user requested "continue". + +Process: +- Restored workspace context from `/home/meswork/cnc_wams`. +- Listed `work/working4` files and confirmed the document set: + - `README.md` + - `01-function-content.md` + - `02-program-development-steps.md` + - `03-progress-ledger.md` + - `04-task-matrix.md` + - `05-acceptance-evidence.md` + - `06-decision-records.md` + - `07-final-closure.md` +- Checked git status and observed existing working tree changes in `web-rtcp-5axis-sim-plan`, QA outputs, and `work/working4`. +- Read workspace `AGENTS.md` and confirmed the required process log path: + - `/home/meswork/cnc_wams/web-rtcp-5axis-sim-plan/gptlog-process/gpdlog.md` +- Read `work/working4/README.md`, `03-progress-ledger.md`, `04-task-matrix.md`, and `07-final-closure.md`. +- Confirmed the current `working4` documents already recorded all W4-D/W4-A/W4-P/W4-U/W4-G/W4-T/W4-V tasks as complete. +- Ran the unfinished W4 task-row scan: + - `rg -n "\\| W4-[A-Z0-9-]+ \\| (todo|in_progress|blocked|deferred) \\|" work/working4/04-task-matrix.md` + - Result: no matches, command exited 1 as expected for no unfinished task rows. +- Ran the stale current-state wording scan against: + - `work/working4/README.md` + - `work/working4/01-function-content.md` + - `work/working4/02-program-development-steps.md` + - `work/working4/04-task-matrix.md` + - `work/working4/05-acceptance-evidence.md` + - `work/working4/07-final-closure.md` + - Result: no matches, command exited 1 as expected for no stale wording. +- Parsed the existing QA JSON before rerunning capture: + - `jobId=xyzab-20260626190724-7b80b3aa` + - `reportId=report-xyzab-20260626190724-7b80b3aa` + - `status=PASS` + - `steps=6` + - `checks=10` +- Ran `git diff --check -- web-rtcp-5axis-sim-plan qa/web-rtcp-5axis-site-test work/working4`. + - Result: returned 0. +- Ran full validation: + - `npm --prefix web-rtcp-5axis-sim-plan/app run build` + - `npm --prefix web-rtcp-5axis-sim-plan/app run smoke:node` + - `bash web-rtcp-5axis-sim-plan/tests/browser/verify_gmoccapy_shell_browser.sh` + - `bash web-rtcp-5axis-sim-plan/tests/browser/verify_gmoccapy_dist_browser.sh` + - `node qa/web-rtcp-5axis-site-test/capture-gmoccapy-xyzab-function-cases.mjs` +- Validation outputs: + - Build: `gmoccapy_static_build=ok` + - Node smoke included: + - `linuxcnc_kinematics_runtime_smoke=ok` + - `linuxcnc_interpreter_runtime_smoke=ok` + - `linuxcnc_ini_runtime_smoke=ok` + - `run_preconditions_ini_profile_smoke=ok` + - `run_preconditions_kinematics_smoke=ok` + - `run_preconditions_machine_file_smoke=ok` + - `run_feedback_status_loop_smoke=ok` + - `run_ready_sequence_smoke=ok` + - `linuxcnc_task_hal_runtime_smoke=ok` + - `task_hal_machine_file_smoke=ok` + - `switchkins_remap_hal_sync_smoke=ok` + - `browser_task_hal_worker_smoke=ok` + - `native_task_hal_source_artifact_audit=ok` + - `full_linuxcnc_5axis_source_node_smoke=ok` + - `real_linuxcnc_5axis_program_cases_smoke=ok` + - `full_execution_boundary_smoke=ok` + - `machine_file_staging_smoke=ok` + - `five_axis_session_smoke=ok` + - `rtcp_store_smoke=ok` + - `profile_boundary_smoke=ok` + - `gmoccapy_xyzab_profile_smoke=ok` + - `gmoccapy_icon_manifest_smoke=ok` + - `gmoccapy_icon_registry_smoke=ok` + - `gmoccapy_communication_model_smoke=ok` + - `gmoccapy_hal_model_smoke=ok` + - `gmoccapy_xyzab_gates_smoke=ok` + - `linear_unit_conversion_smoke=ok` + - Browser shell smoke: `gmoccapy_shell_smoke=ok` + - Dist browser smoke: `gmoccapy_dist_smoke=ok` + - QA capture: + - `gmoccapy_xyzab_function_status=PASS` + - `gmoccapy_xyzab_function_job_id=xyzab-20260626214346-f4b4aa36` + - `gmoccapy_xyzab_function_report_id=report-xyzab-20260626214346-f4b4aa36` + - JSON path: `/home/meswork/cnc_wams/qa/web-rtcp-5axis-site-test/output/gmoccapy-xyzab-function-report.json` + - PDF path: `/home/meswork/cnc_wams/qa/web-rtcp-5axis-site-test/output/gmoccapy-xyzab-function-report.pdf` + - Screenshot directory: `/home/meswork/cnc_wams/qa/web-rtcp-5axis-site-test/output/gmoccapy-xyzab` +- Parsed the refreshed QA JSON: + - `jobId=xyzab-20260626214346-f4b4aa36` + - `reportId=report-xyzab-20260626214346-f4b4aa36` + - `status=PASS` + - `steps=6` + - `checks=10` + - `generatedAt=2026-06-26T21:43:46.310Z` +- Updated `work/working4/05-acceptance-evidence.md`: + - Changed the current QA capture command output to the refreshed `job_id` and `report_id`. + - Added a new job/report table row for the resumed QA capture. +- Updated `work/working4/07-final-closure.md`: + - Changed final QA identifiers to the refreshed `jobId` and `reportId`. + - Added `generatedAt=2026-06-26T21:43:46.310Z`. + - Added the full build, node smoke, browser smoke, dist smoke, and QA capture commands to final validation commands. + - Updated final validation results to mention the full validation chain. +- Updated `work/working4/03-progress-ledger.md`: + - Appended `W4-VERIFY-006` with process, files changed, validation commands, results, retained boundaries, and next-step rule. +- Rechecked identifier usage: + - Old `20260626190724` identifiers remain only in historical ledger/history rows. + - Current final closure and current QA evidence point to `xyzab-20260626214346-f4b4aa36`. +- Rechecked unfinished task rows: + - No matches. +- Rechecked stale current-state wording: + - No matches. +- Rechecked whitespace with `git diff --check -- web-rtcp-5axis-sim-plan qa/web-rtcp-5axis-site-test work/working4`. + - Result: returned 0. + +Files changed in this execution: +- `/home/meswork/cnc_wams/work/working4/03-progress-ledger.md` +- `/home/meswork/cnc_wams/work/working4/05-acceptance-evidence.md` +- `/home/meswork/cnc_wams/work/working4/07-final-closure.md` +- `/home/meswork/cnc_wams/qa/web-rtcp-5axis-site-test/output/gmoccapy-xyzab-function-report.json` +- `/home/meswork/cnc_wams/qa/web-rtcp-5axis-site-test/output/gmoccapy-xyzab-function-report.pdf` +- `/home/meswork/cnc_wams/qa/web-rtcp-5axis-site-test/output/gmoccapy-xyzab/` +- `/home/meswork/cnc_wams/web-rtcp-5axis-sim-plan/gptlog-process/gpdlog.md` + +Outcome: +- `working4` remains complete. +- The current final closure evidence now points to the refreshed QA report: + - `jobId=xyzab-20260626214346-f4b4aa36` + - `reportId=report-xyzab-20260626214346-f4b4aa36` +- Full build, Node smoke, browser smoke, dist smoke, QA capture, stale wording scan, unfinished task scan, and whitespace checks all pass. +- Retained boundary remains unchanged: `gmoccapy-xyzab` is a `trivkins` reference-only profile and is not a TCP/RTCP or native LinuxCNC realtime execution proof. diff --git a/web-rtcp-5axis-sim-plan/tests/browser/gmoccapy_shell_smoke.html b/web-rtcp-5axis-sim-plan/tests/browser/gmoccapy_shell_smoke.html index c7b8d27..ea3702f 100644 --- a/web-rtcp-5axis-sim-plan/tests/browser/gmoccapy_shell_smoke.html +++ b/web-rtcp-5axis-sim-plan/tests/browser/gmoccapy_shell_smoke.html @@ -263,6 +263,37 @@ if (!doc.querySelector('[data-linuxcnc-task-policy="source"]')?.textContent.includes("linuxcnc/src/emc/task/emctaskmain.cc")) { throw new Error("missing LinuxCNC emctaskmain source diagnostic"); } + for (const [selector, iconName] of [ + ['[data-action="estop"]', "main_switch_off"], + ['[data-action="power"]', "power_off"], + ['[data-action="mode-manual"]', "mode_manual_active"], + ['[data-action="mode-auto"]', "mode_auto_inactive"], + ['[data-action="mode-mdi"]', "mode_mdi_inactive"], + ['[data-action="RUN"]', "play"], + ['[data-action="STOP"]', "stop"], + ['[data-action="PAUSE"]', "pause"], + ['[data-action="HOME"]', "ref_all"], + ['[data-action="toggle-flood"]', "coolant_flood_active"], + ['[data-action="toggle-mist"]', "coolant_mist_inactive"], + ['[data-action="view-x"]', "tool_axis_x"], + ]) { + const button = doc.querySelector(selector); + if (!button || button.dataset.iconName !== iconName || !button.querySelector("img")) { + throw new Error(`missing gmoccapy icon ${selector} expected ${iconName}, got ${button?.dataset.iconName}`); + } + } + if (!doc.querySelector('[data-gmoccapy-comm="boundary"]')?.textContent.includes("native_gmoccapy_nml_hal_reference")) { + throw new Error("missing gmoccapy communication boundary diagnostic"); + } + if (!doc.querySelector('[data-gmoccapy-comm="native-command"]')?.textContent.includes("NML emcCommand")) { + throw new Error("missing gmoccapy NML command diagnostic"); + } + if (!doc.querySelector('[data-gmoccapy-comm="web-path"]')?.textContent.includes("store.dispatch")) { + throw new Error("missing gmoccapy Web runtime mapping"); + } + if (!doc.querySelector('[data-gmoccapy-hal="postgui"]')?.textContent.includes("tool-change-loop")) { + throw new Error("missing gmoccapy HAL postgui diagnostic"); + } if (!doc.querySelector('[data-tool-preview="summary"]')?.textContent.includes("T1")) { throw new Error("missing tool preview summary"); } diff --git a/web-rtcp-5axis-sim-plan/tests/node/verify_gmoccapy_communication_model.mjs b/web-rtcp-5axis-sim-plan/tests/node/verify_gmoccapy_communication_model.mjs new file mode 100644 index 0000000..a52c785 --- /dev/null +++ b/web-rtcp-5axis-sim-plan/tests/node/verify_gmoccapy_communication_model.mjs @@ -0,0 +1,75 @@ +import assert from "node:assert/strict"; + +import { + createGmoccapyCommunicationSummary, + gmoccapyCommunicationModel, +} from "../../app/src/runtime/gmoccapy-communication-model.js"; + +const model = gmoccapyCommunicationModel; + +assert.equal(model.apiName, "web-rtcp-5axis-gmoccapy-communication-model"); +assert.equal(model.profileId, "gmoccapy-xyzab"); +assert.equal(model.nativeConfigPath.endsWith("gmoccapy_XYZAB.ini"), true); +assert.equal(model.cycleTimeMs, 100); +assert.equal(model.semanticBoundary, "native_gmoccapy_nml_hal_reference_web_store_runtime_mapping"); + +assert.deepEqual(model.nativePaths.command.path, ["gmoccapy", "linuxcnc.command()", "NML emcCommand", "milltask"]); +assert.equal(model.nativePaths.status.path.includes("linuxcnc.stat()"), true); +assert.equal(model.nativePaths.status.path.includes("linuxcnc.error_channel()"), true); +assert.equal(model.nativePaths.hal.path.includes("HAL shared memory"), true); +assert.equal(model.nativePaths.remap.path.includes("Python remap prolog/ngc/epilog"), true); +assert.deepEqual(model.webPath.path, ["button", "store.dispatch", "linuxcnc-task-policy", "runtime/status snapshot", "UI/Three.js"]); + +assert.equal(model.startupStages.length, 9); +assert.equal(model.startupStages[0].id, "parse-ini"); +assert.equal(model.startupStages.at(-1).id, "postgui"); +assert.equal(model.startupStages.at(-1).nativeStep.includes("halcomp.ready()"), true); + +const actionIds = model.actionMappings.map((mapping) => mapping.actionId); +for (const actionId of [ + "estop", + "estop-reset", + "power-on", + "mode-manual", + "mode-mdi", + "mode-auto", + "jog", + "home", + "mdi", + "auto-run", + "auto-pause", + "auto-resume", + "abort", + "spindle", + "coolant", +]) { + assert.equal(actionIds.includes(actionId), true, `${actionId} missing`); +} + +const runMapping = model.actionMappings.find((mapping) => mapping.actionId === "auto-run"); +assert.equal(runMapping.nativeCommand, "command.auto(AUTO_RUN, start_line)"); +assert.equal(runMapping.webAction, "RUN"); +assert.equal(runMapping.gate.includes("INI loaded"), true); +assert.equal(runMapping.gate.includes("runtime ready"), true); + +const jogMapping = model.actionMappings.find((mapping) => mapping.actionId === "jog"); +assert.equal(jogMapping.nativeCommand.includes("JOG_CONTINUOUS"), true); +assert.equal(jogMapping.gate, "machine on, manual mode, not running"); + +const spindleMapping = model.actionMappings.find((mapping) => mapping.actionId === "spindle"); +assert.equal(spindleMapping.nativeStatus.includes("spindle.0.forward"), true); +assert.equal(spindleMapping.gate.includes("restricted during interpreter"), true); + +const summary = createGmoccapyCommunicationSummary(model); +assert.equal(summary.apiName, "web-rtcp-5axis-gmoccapy-communication-model-summary"); +assert.equal(summary.profileId, "gmoccapy-xyzab"); +assert.equal(summary.nativePathCount, 4); +assert.equal(summary.startupStageCount, 9); +assert.equal(summary.actionCount, 15); +assert.equal(summary.postguiAfterHalcompReady, true); +assert.equal(summary.hasNativeNmlCommandPath, true); +assert.equal(summary.hasNativeHalPath, true); +assert.equal(summary.hasWebStorePath, true); +assert.equal(summary.semanticBoundary, model.semanticBoundary); + +console.log("gmoccapy_communication_model_smoke=ok"); diff --git a/web-rtcp-5axis-sim-plan/tests/node/verify_gmoccapy_hal_model.mjs b/web-rtcp-5axis-sim-plan/tests/node/verify_gmoccapy_hal_model.mjs new file mode 100644 index 0000000..4589abf --- /dev/null +++ b/web-rtcp-5axis-sim-plan/tests/node/verify_gmoccapy_hal_model.mjs @@ -0,0 +1,72 @@ +import assert from "node:assert/strict"; + +import { + createGmoccapyHalSummary, + gmoccapyHalModel, +} from "../../app/src/runtime/gmoccapy-hal-model.js"; + +const model = gmoccapyHalModel; + +assert.equal(model.apiName, "web-rtcp-5axis-gmoccapy-hal-model"); +assert.equal(model.profileId, "gmoccapy-xyzab"); +assert.equal(model.nativeConfigPath.endsWith("gmoccapy_XYZAB.ini"), true); +assert.equal(model.semanticBoundary, "gmoccapy_hal_pin_postgui_reference_web_diagnostic_only"); + +assert.equal(model.halFiles.length, 4); +assert.equal(model.halFiles.some((file) => file.path.endsWith("core_sim_XYZAB.hal") && file.stage === "HALFILE"), true); +assert.equal(model.halFiles.some((file) => file.path.endsWith("spindle_sim.hal") && file.stage === "HALFILE"), true); +assert.equal(model.halFiles.some((file) => file.path.endsWith("simulated_home.hal") && file.stage === "HALFILE"), true); +assert.equal(model.halFiles.some((file) => file.path.endsWith("gmoccapy_postgui.hal") && file.requiresHalcompReady), true); + +const groups = new Map(model.nativePins.map((group) => [group.group, group])); +for (const groupName of [ + "hard-buttons", + "jog", + "override", + "tool", + "program", + "message", + "spindle-postgui", +]) { + assert.equal(groups.has(groupName), true, `${groupName} missing`); +} + +assert.equal(groups.get("hard-buttons").pins.includes("gmoccapy.h-button.button-0"), true); +assert.equal(groups.get("hard-buttons").pins.includes("gmoccapy.v-button.button-6"), true); +assert.equal(groups.get("jog").pins.includes("gmoccapy.jog.axis.jog-b-minus"), true); +assert.equal(groups.get("override").pins.includes("gmoccapy.rapid.rapid-override.direct-value"), true); +assert.equal(groups.get("tool").pins.includes("gmoccapy.toolchange-changed"), true); +assert.equal(groups.get("program").pins.includes("gmoccapy.program.current-line"), true); +assert.equal(groups.get("message").pins.includes("gmoccapy.error"), true); +assert.equal(groups.get("spindle-postgui").pins.includes("gmoccapy.spindle_at_speed_led"), true); + +assert.equal(model.coreNets.length, 10); +assert.equal(model.coreNets.some((net) => net.signal === "Xpos" && net.target === "joint.0.motor-pos-fb"), true); +assert.equal(model.coreNets.some((net) => net.signal === "Bpos" && net.target === "joint.4.motor-pos-fb"), true); +assert.equal(model.coreNets.some((net) => net.signal === "estop-loop"), true); +assert.equal(model.coreNets.some((net) => net.signal === "tool-change-loop"), true); + +assert.equal(model.spindleNets.length, 4); +assert.equal(model.spindleNets.some((net) => net.signal === "spindle-speed-cmd"), true); +assert.equal(model.spindleNets.some((net) => net.signal === "spindle-at-speed"), true); + +assert.equal(model.postguiNets.length, 5); +assert.equal(model.postguiNets.every((net) => net.requiresHalcompReady), true); +assert.equal(model.postguiNets.some((net) => net.target === "gmoccapy.spindle_feedback_bar"), true); +assert.equal(model.postguiNets.some((net) => net.target === "gmoccapy.tooloffset-x"), true); +assert.equal(model.postguiNets.some((net) => net.simulationLoop && net.signal === "tool-change-loop"), true); + +const summary = createGmoccapyHalSummary(model); +assert.equal(summary.apiName, "web-rtcp-5axis-gmoccapy-hal-model-summary"); +assert.equal(summary.profileId, "gmoccapy-xyzab"); +assert.equal(summary.halFileCount, 4); +assert.equal(summary.nativePinGroupCount, 7); +assert.equal(summary.nativePinCount >= 50, true); +assert.equal(summary.coreNetCount, 10); +assert.equal(summary.spindleNetCount, 4); +assert.equal(summary.postguiNetCount, 5); +assert.equal(summary.postguiRequiresHalcompReady, true); +assert.equal(summary.hasToolChangeSimulationLoop, true); +assert.equal(summary.semanticBoundary, model.semanticBoundary); + +console.log("gmoccapy_hal_model_smoke=ok"); diff --git a/web-rtcp-5axis-sim-plan/tests/node/verify_gmoccapy_icon_manifest.mjs b/web-rtcp-5axis-sim-plan/tests/node/verify_gmoccapy_icon_manifest.mjs new file mode 100644 index 0000000..f8010e3 --- /dev/null +++ b/web-rtcp-5axis-sim-plan/tests/node/verify_gmoccapy_icon_manifest.mjs @@ -0,0 +1,84 @@ +import assert from "node:assert/strict"; +import { access, readFile } from "node:fs/promises"; +import { join } from "node:path"; + +const repoRoot = new URL("../../..", import.meta.url).pathname.replace(/\/$/, ""); +const manifestPath = join(repoRoot, "web-rtcp-5axis-sim-plan/app/src/ui-reference/gmoccapy-button-icons.json"); +const manifest = JSON.parse(await readFile(manifestPath, "utf8")); + +assert.equal(manifest.schema, "web-rtcp-5axis-gmoccapy-button-icons-v1"); +assert.equal(manifest.semanticBoundary, "gmoccapy_button_icon_asset_reference_only_not_control_semantics"); +assert.equal(manifest.generatedFrom.csv, "work/working3/gmoccapy_button_icons/button_icon_inventory.csv"); +assert.equal(manifest.rowCount, 211); +assert.equal(manifest.entries.length, 211); +assert.equal(manifest.copiedIconCount, 112); + +const entriesByButton = new Map(); +for (const entry of manifest.entries) { + if (!entriesByButton.has(entry.buttonId)) entriesByButton.set(entry.buttonId, []); + entriesByButton.get(entry.buttonId).push(entry); + if (entry.projectAsset) { + await access(join(repoRoot, "web-rtcp-5axis-sim-plan", entry.projectAsset.replace(/^app\//, "app/"))); + } +} + +const coreButtons = [ + "tbtn_estop", + "tbtn_on", + "rbt_manual", + "rbt_mdi", + "rbt_auto", + "tbtn_setup", + "tbtn_user_tabs", + "btn_homing", + "btn_tool", + "btn_touch", + "btn_load", + "btn_reload", + "btn_run", + "btn_stop", + "tbtn_pause", + "btn_step", + "ref_all", + "home_axis_x", + "home_axis_y", + "home_axis_z", + "home_axis_a", + "home_axis_b", + "touch_x", + "touch_y", + "touch_z", + "touch_a", + "touch_b", + "rbt_forward", + "rbt_reverse", + "rbt_stop", + "tbtn_flood", + "tbtn_mist", + "btn_zoom_in", + "btn_zoom_out", + "rbt_view_x", + "rbt_view_y", + "rbt_view_z", + "rbt_view_p", + "tbtn_view_tool_path", + "tbtn_view_dimension", +]; + +for (const buttonId of coreButtons) { + const entries = entriesByButton.get(buttonId) || []; + assert.equal(entries.length > 0, true, `${buttonId} missing from manifest`); + assert.equal(entries.some((entry) => entry.projectAsset || entry.sourceType === "none"), true, `${buttonId} lacks asset/fallback`); +} + +assert.equal(entriesByButton.get("rbt_auto").some((entry) => entry.stateOrVariant === "active" && entry.iconName === "mode_auto_active"), true); +assert.equal(entriesByButton.get("rbt_auto").some((entry) => entry.iconName === "mode_auto_inactive"), true); +assert.equal(entriesByButton.get("tbtn_estop").some((entry) => entry.iconName === "main_switch_on"), true); +assert.equal(entriesByButton.get("tbtn_estop").some((entry) => entry.iconName === "main_switch_off"), true); +assert.equal(entriesByButton.get("tbtn_flood").some((entry) => entry.iconName === "coolant_flood_active"), true); +assert.equal(entriesByButton.get("tbtn_mist").some((entry) => entry.iconName === "coolant_mist_inactive"), true); + +const copiedAssets = new Set(manifest.entries.map((entry) => entry.projectAsset).filter(Boolean)); +assert.equal(copiedAssets.size, 112); + +console.log("gmoccapy_icon_manifest_smoke=ok"); diff --git a/web-rtcp-5axis-sim-plan/tests/node/verify_gmoccapy_icon_registry.mjs b/web-rtcp-5axis-sim-plan/tests/node/verify_gmoccapy_icon_registry.mjs new file mode 100644 index 0000000..5c4c594 --- /dev/null +++ b/web-rtcp-5axis-sim-plan/tests/node/verify_gmoccapy_icon_registry.mjs @@ -0,0 +1,63 @@ +import assert from "node:assert/strict"; +import { access, readFile } from "node:fs/promises"; +import { join } from "node:path"; + +import { + GMOCAPY_ICON_REGISTRY_BOUNDARY, + getGmoccapyIcon, + listGmoccapyIconRegistryEntries, +} from "../../app/src/ui/gmoccapy-icon-registry.js"; + +const repoRoot = new URL("../../..", import.meta.url).pathname.replace(/\/$/, ""); +const manifestPath = join(repoRoot, "web-rtcp-5axis-sim-plan/app/src/ui-reference/gmoccapy-button-icons.json"); +const manifest = JSON.parse(await readFile(manifestPath, "utf8")); +const manifestIconNames = new Set(manifest.entries.map((entry) => entry.iconName).filter(Boolean)); +const registryEntries = listGmoccapyIconRegistryEntries(); + +assert.equal(GMOCAPY_ICON_REGISTRY_BOUNDARY, "gmoccapy_icon_registry_from_working3_manifest_core_ui_subset"); +assert.equal(registryEntries.length >= 40, true); + +const required = [ + ["tbtn_estop", "active", "main_switch_on"], + ["tbtn_estop", "inactive", "main_switch_off"], + ["tbtn_on", "active", "power_on"], + ["rbt_manual", "active", "mode_manual_active"], + ["rbt_mdi", "active", "mode_mdi_active"], + ["rbt_auto", "active", "mode_auto_active"], + ["btn_load", "default", "open_file"], + ["btn_reload", "default", "refresh"], + ["btn_run", "default", "play"], + ["btn_stop", "default", "stop"], + ["tbtn_pause", "active", "pause_active"], + ["btn_step", "default", "step"], + ["btn_homing", "default", "ref_all"], + ["btn_tool", "default", "hsk_mill_tool"], + ["btn_touch", "default", "touch_off"], + ["rbt_forward", "active", "spindle_right_on"], + ["rbt_reverse", "active", "spindle_left_on"], + ["rbt_stop", "active", "spindle_stop_on"], + ["tbtn_flood", "active", "coolant_flood_active"], + ["tbtn_mist", "inactive", "coolant_mist_inactive"], + ["rbt_view_x", "default", "tool_axis_x"], + ["rbt_view_y", "default", "tool_axis_y"], + ["rbt_view_z", "default", "tool_axis_z"], + ["rbt_view_p", "default", "tool_axis_p"], + ["tbtn_view_tool_path", "default", "toolpath"], + ["tbtn_view_dimension", "default", "dimensions"], +]; + +for (const [buttonId, variant, expectedIconName] of required) { + const icon = getGmoccapyIcon(buttonId, variant); + assert.equal(icon.iconName, expectedIconName, `${buttonId}/${variant}`); + assert.equal(icon.fallback, false, `${buttonId}/${variant} should use an asset`); + assert.equal(icon.semanticBoundary, GMOCAPY_ICON_REGISTRY_BOUNDARY); + assert.equal(manifestIconNames.has(icon.iconName), true, `${icon.iconName} missing from manifest`); + assert.match(icon.path, /\/assets\/gmoccapy-icons\//); + await access(new URL(icon.path)); +} + +const fallback = getGmoccapyIcon("unknown_button", "active"); +assert.equal(fallback.iconName, "text_fallback"); +assert.equal(fallback.fallback, true); + +console.log("gmoccapy_icon_registry_smoke=ok"); diff --git a/web-rtcp-5axis-sim-plan/tests/node/verify_gmoccapy_xyzab_gates.mjs b/web-rtcp-5axis-sim-plan/tests/node/verify_gmoccapy_xyzab_gates.mjs new file mode 100644 index 0000000..2c11b40 --- /dev/null +++ b/web-rtcp-5axis-sim-plan/tests/node/verify_gmoccapy_xyzab_gates.mjs @@ -0,0 +1,180 @@ +import assert from "node:assert/strict"; + +import { getFiveAxisProfile } from "../../app/src/profiles/index.js"; +import { createSimulationStore, validateRunPreconditions } from "../../app/src/state/store.js"; +import { gateLinuxCncTaskAction } from "../../app/src/state/linuxcnc-task-policy.js"; + +const profile = getFiveAxisProfile("gmoccapy-xyzab"); +const store = createSimulationStore(); +store.dispatch({ type: "SET_PROFILE", profileId: "gmoccapy-xyzab" }); + +assert.equal(store.getState().profile.id, profile.id); +assert.equal(store.getState().machine.noForceHoming, false); + +let gate = gateLinuxCncTaskAction(store.getState(), { type: "RUN" }); +assert.equal(gate.allowed, false); +assert.equal(gate.operatorMessage, "run blocked: machine must be on"); + +store.dispatch({ type: "TOGGLE_POWER" }); +gate = gateLinuxCncTaskAction(store.getState(), { type: "RUN" }); +assert.equal(gate.allowed, false); +assert.equal(gate.operatorMessage, "run blocked: switch to auto mode first"); + +store.dispatch({ type: "SET_MODE", mode: "auto" }); +gate = gateLinuxCncTaskAction(store.getState(), { type: "RUN" }); +assert.equal(gate.allowed, false); +assert.equal(gate.operatorMessage, "run blocked: home machine first"); + +store.dispatch({ type: "SET_MODE", mode: "manual" }); +store.dispatch({ type: "HOME" }); +store.dispatch({ type: "SET_MODE", mode: "auto" }); +gate = gateLinuxCncTaskAction(store.getState(), { type: "RUN" }); +assert.equal(gate.allowed, false); +assert.equal(gate.operatorMessage, "run blocked: LinuxCNC INI not loaded"); + +store.dispatch({ + type: "ATTACH_INI_CONFIG", + profileId: "gmoccapy-xyzab", + iniConfig: { + profileId: "gmoccapy-xyzab", + path: profile.iniPath, + sourceText: "[TRAJ]\nCOORDINATES = X Y Z A B\nNO_FORCE_HOMING = 0\n[KINS]\nKINEMATICS = trivkins coordinates=xyzab\n", + validation: { ready: true }, + traj: { coordinates: "XYZAB", noForceHoming: false }, + kinematics: { name: "trivkins", sparm: "coordinates=xyzab" }, + kinematicsParameters: profile.kinematicsParameters, + kinematicsModuleId: profile.kinematicsModuleId, + axisLimits: profile.axisLimits, + jointConfig: profile.jointConfig, + display: profile.display, + rs274ngc: profile.rs274ngc, + hal: { + ...profile.hal, + halcmd: profile.hal.halcmd, + initialSets: [], + }, + halui: profile.halui, + emcmot: { servoPeriodNs: 1000000 }, + emcio: {}, + task: { cycleTimeSeconds: 0.001 }, + }, +}); + +gate = gateLinuxCncTaskAction(store.getState(), { type: "RUN" }); +assert.equal(gate.allowed, false); +assert.equal(gate.operatorMessage, "run blocked: LinuxCNC machine files not staged"); + +store.dispatch({ + type: "MACHINE_FILE_STAGING_COMPLETE", + plan: { + profileId: "gmoccapy-xyzab", + selectedProgramSourceRel: null, + }, + save: { + fileCount: 2, + files: [ + { + sourceRel: "configs/sim/gmoccapy/gmoccapy_XYZAB.ini", + wasmPath: "/work/sim/gmoccapy/gmoccapy_XYZAB.ini", + kind: "ini", + text: "", + bytes: 0, + }, + ], + summary: { gcodeFileCount: 0 }, + }, +}); + +gate = gateLinuxCncTaskAction(store.getState(), { type: "RUN" }); +assert.equal(gate.allowed, false); +assert.equal(gate.operatorMessage, "run blocked: no machine-file G-code opened for task/HAL session"); + +store.dispatch({ + type: "MACHINE_FILE_STAGING_COMPLETE", + plan: { + profileId: "gmoccapy-xyzab", + selectedProgramSourceRel: "configs/sim/gmoccapy/demos/xyzab-demo.ngc", + }, + save: { + fileCount: 2, + files: [ + { + sourceRel: "configs/sim/gmoccapy/demos/xyzab-demo.ngc", + wasmPath: "/work/sim/gmoccapy/demos/xyzab-demo.ngc", + kind: "demo", + text: "G0 X0\nM2\n", + bytes: 9, + }, + ], + summary: { gcodeFileCount: 1 }, + }, + selectedGcodeSourceRel: "configs/sim/gmoccapy/demos/xyzab-demo.ngc", +}); + +gate = gateLinuxCncTaskAction(store.getState(), { type: "RUN" }); +assert.equal(gate.allowed, false); +assert.equal(gate.operatorMessage, "run blocked: task/HAL runtime not ready"); + +store.dispatch({ + type: "ATTACH_TASK_HAL_RUNTIME", + runtime: { + loaded: true, + readiness() { + return { + loaded: true, + taskRuntimeReady: true, + motionRuntimeReady: true, + halRuntimeReady: true, + }; + }, + }, +}); + +gate = gateLinuxCncTaskAction(store.getState(), { type: "RUN" }); +assert.equal(gate.allowed, true); +assert.equal(gate.status.canRunAutoStrict, true); +assert.equal(gate.status.profileId, "gmoccapy-xyzab"); + +const runPreconditions = validateRunPreconditions(store.getState(), { + requireTaskHalRuntime: false, + requireTaskHalSession: false, +}); +assert.equal(runPreconditions.ok, false); +assert.equal(runPreconditions.operatorMessage, "run blocked: unsupported five-axis profile gmoccapy-xyzab"); + +const manualStore = createSimulationStore(); +manualStore.dispatch({ type: "SET_PROFILE", profileId: "gmoccapy-xyzab" }); +manualStore.dispatch({ type: "TOGGLE_POWER" }); +gate = gateLinuxCncTaskAction(manualStore.getState(), { type: "JOG", axis: "x", direction: 1 }); +assert.equal(gate.allowed, true); +gate = gateLinuxCncTaskAction(manualStore.getState(), { type: "HOME" }); +assert.equal(gate.allowed, true); + +manualStore.dispatch({ type: "HOME" }); +manualStore.dispatch({ type: "SET_MODE", mode: "mdi" }); +gate = gateLinuxCncTaskAction(manualStore.getState(), { type: "RUN_MDI" }); +assert.equal(gate.allowed, true); + +const controlStore = createSimulationStore(); +controlStore.dispatch({ type: "SET_PROFILE", profileId: "gmoccapy-xyzab" }); +controlStore.dispatch({ type: "ESTOP" }); +gate = gateLinuxCncTaskAction(controlStore.getState(), { type: "TOGGLE_COOLANT", kind: "flood" }); +assert.equal(gate.allowed, false); +assert.equal(gate.operatorMessage, "coolant blocked: machine must be on"); +gate = gateLinuxCncTaskAction(controlStore.getState(), { type: "SET_SPINDLE_DIRECTION", direction: "forward" }); +assert.equal(gate.allowed, false); +assert.equal(gate.operatorMessage, "spindle blocked: machine must be on"); + +controlStore.dispatch({ type: "RESET" }); +controlStore.dispatch({ type: "TOGGLE_POWER" }); +controlStore.dispatch({ type: "SET_SPINDLE_DIRECTION", direction: "forward" }); +assert.equal(controlStore.getState().spindle.enabled, true); +assert.equal(controlStore.getState().spindle.direction, "forward"); +controlStore.dispatch({ type: "SET_SPINDLE_DIRECTION", direction: "stop" }); +assert.equal(controlStore.getState().spindle.enabled, false); +assert.equal(controlStore.getState().spindle.direction, "stop"); + +controlStore.dispatch({ type: "TOGGLE_COOLANT", kind: "flood" }); +assert.equal(controlStore.getState().coolant.flood, true); + +console.log("gmoccapy_xyzab_gates_smoke=ok"); diff --git a/web-rtcp-5axis-sim-plan/tests/node/verify_gmoccapy_xyzab_profile.mjs b/web-rtcp-5axis-sim-plan/tests/node/verify_gmoccapy_xyzab_profile.mjs new file mode 100644 index 0000000..9b7c4ae --- /dev/null +++ b/web-rtcp-5axis-sim-plan/tests/node/verify_gmoccapy_xyzab_profile.mjs @@ -0,0 +1,116 @@ +import assert from "node:assert/strict"; + +import { getFiveAxisProfile, fiveAxisProfiles } from "../../app/src/profiles/index.js"; +import { buildRtcpFrame } from "../../app/src/runtime/rtcp-frame.js"; +import { createLinuxCncBoundaryAdapter, createLinuxCncBoundaryReadiness } from "../../app/src/runtime/linuxcnc-boundary-adapter.js"; +import { createProfileSourceReferenceSummary } from "../../app/src/profiles/source-reference-map.js"; +import { createSimulationStore, validateRunPreconditions } from "../../app/src/state/store.js"; + +const profile = getFiveAxisProfile("gmoccapy-xyzab"); + +assert.equal(profile.id, "gmoccapy-xyzab"); +assert.equal(profile.title, "gmoccapy XYZAB trivkins reference"); +assert.equal(profile.iniPath, "linuxcnc/configs/sim/gmoccapy/gmoccapy_XYZAB.ini"); +assert.deepEqual(profile.coordinates, ["X", "Y", "Z", "A", "B"]); +assert.equal(profile.traj.coordinates, "XYZAB"); +assert.equal(profile.joints.length, 5); +assert.equal(profile.jointConfig.length, 5); +assert.equal(profile.kinematics, "trivkins coordinates=xyzab"); +assert.equal(profile.kinematicsModuleId, "gmoccapy-xyzab-trivkins-reference"); +assert.equal(profile.tcpCapable, false); +assert.equal(profile.rtcpProof, false); +assert.equal(profile.linuxCncKinematicsReady, false); +assert.equal(profile.promotionAllowed, false); +assert.equal(profile.semanticBoundary, "gmoccapy_xyzab_trivkins_reference_only_not_rtcp_proof"); +assert.equal(profile.homing.noForceHoming, false); +assert.equal(profile.homing.noForceHomingIniValue, 0); +assert.equal(profile.hal.postguiRequiresHalcompReady, true); +assert.deepEqual(profile.hal.halFiles, ["core_sim_XYZAB.hal", "spindle_sim.hal", "simulated_home.hal"]); +assert.deepEqual(profile.hal.postguiHalFiles, ["gmoccapy_postgui.hal"]); +assert.equal(profile.nativeRuntime.task, "milltask"); +assert.equal(profile.nativeRuntime.emcmot, "motmod"); +assert.equal(profile.nativeRuntime.halui, "halui"); +assert.equal(profile.nativeRuntime.displayCycleTimeMs, 100); +assert.equal(profile.nativeRuntime.servoPeriodNs, 1000000); +assert.equal(profile.axisLimits.X.max, 600); +assert.equal(profile.axisLimits.Y.max, 400); +assert.equal(profile.axisLimits.Z.min, -400); +assert.equal(profile.axisLimits.B.maxVelocity, 90); +assert.equal(profile.jointConfig[4].axis, "B"); +assert.equal(profile.jointConfig[4].homeOffset, 45); +assert.equal(profile.hal.halcmd.feedbackNets.length, 5); +assert.equal(profile.hal.halcmd.offsetNets.some((net) => net.target === "gmoccapy.tooloffset-z"), true); +assert.equal(profile.hal.halcmd.simulationLoops.some((net) => net.signal === "tool-change-loop"), true); +assert.equal(profile.halPins.includes("gmoccapy.program.current-line"), true); +assert.equal(profile.halPins.includes("gmoccapy.spindle_at_speed_led"), true); +assert.equal(profile.toolTable.toolCount, 17); +assert.equal(profile.macros.includes("go_to_position X-pos Y-pos Z-pos"), true); +assert.equal(profile.panelSchema.id, "gmoccapy-xyzab-hal-component"); +assert.equal(profile.panelSchema.boundary, "gmoccapy_hal_component_reference_only"); +assert.equal(profile.panelSchema.groups.length, 2); + +assert.deepEqual(fiveAxisProfiles.map(({ id }) => id), ["xyzac-trt", "xyzbc-trt", "gmoccapy-xyzab"]); + +const sourceSummary = createProfileSourceReferenceSummary("gmoccapy-xyzab"); +assert.equal(sourceSummary.profileId, "gmoccapy-xyzab"); +assert.equal(sourceSummary.referenceCount >= 10, true); +assert.equal(sourceSummary.kinds.includes("ini"), true); +assert.equal(sourceSummary.kinds.includes("halfile"), true); +assert.equal(sourceSummary.kinds.includes("postgui_hal"), true); +assert.equal(sourceSummary.kinds.includes("icon_manifest"), true); +assert.equal(sourceSummary.kinds.includes("python_gui"), true); +assert.equal(sourceSummary.promotionAllowed, false); +assert.equal(sourceSummary.semanticBoundary, "profile_source_map_only_not_runtime_proof"); +assert.ok(sourceSummary.references.some((reference) => reference.path.endsWith("gmoccapy_XYZAB.ini"))); +assert.ok(sourceSummary.references.some((reference) => reference.path.endsWith("gmoccapy_postgui.hal"))); +assert.ok(sourceSummary.references.some((reference) => reference.path.endsWith("gmoccapy-button-icons.json"))); + +const adapter = createLinuxCncBoundaryAdapter({ profile }); +assert.equal(adapter.profileId, "gmoccapy-xyzab"); +assert.equal(adapter.profileSummary.coordinates, "XYZAB"); +assert.equal(adapter.profileSummary.jointCount, 5); +assert.equal(adapter.profileSummary.mdiCommandCount, 0); +assert.equal(adapter.profileSummary.remapCount, 2); +assert.equal(adapter.profileSummary.toolCount, 17); +assert.equal(adapter.profileSummary.feedbackNetCount, 5); +assert.equal(adapter.profileSummary.halFileCount, 4); +assert.equal(adapter.promotionAllowed, false); +assert.equal(adapter.linuxCncKinematicsReady, false); + +const readiness = createLinuxCncBoundaryReadiness(adapter); +assert.equal(readiness.ready, false); +assert.equal(readiness.promotionAllowed, false); +assert.equal(readiness.missing.includes("kinematics runtime"), true); + +const frame = buildRtcpFrame({ + axisPose: { x: 10, y: 20, z: -5, a: 30, b: 45, c: 99 }, + activeLine: 10, + profile, +}); +assert.equal(frame.profileId, "gmoccapy-xyzab"); +assert.deepEqual(frame.jointPose.map((joint) => joint.axis), ["X", "Y", "Z", "A", "B"]); +assert.equal(frame.jointPose[4].value, 45); +assert.equal(frame.readiness.linuxCncKinematicsReady, false); +assert.equal(frame.readiness.promotionAllowed, false); + +const store = createSimulationStore(); +store.dispatch({ type: "SET_PROFILE", profileId: "gmoccapy-xyzab" }); +assert.equal(store.getState().machineProfile, "gmoccapy-xyzab"); +assert.equal(store.getState().profile.tcpCapable, false); +assert.equal(store.getState().rtcpState, "off"); +store.dispatch({ type: "SET_KINS_TYPE", kinsType: "tcp-xyzac" }); +assert.equal(store.getState().kinsType, "identity"); +assert.equal(store.getState().rtcpState, "off"); +assert.equal(store.getState().operatorMessage, "kinematics tcp-xyzac blocked: gmoccapy-xyzab is not TCP capable"); +store.dispatch({ type: "SET_RTCP", enabled: true }); +assert.equal(store.getState().rtcpState, "off"); +assert.equal(store.getState().operatorMessage, "RTCP blocked: gmoccapy-xyzab is trivkins coordinates=xyzab reference only"); + +const preconditions = validateRunPreconditions(store.getState(), { + requireTaskHalRuntime: false, + requireTaskHalSession: false, +}); +assert.equal(preconditions.ok, false); +assert.equal(preconditions.operatorMessage, "run blocked: unsupported five-axis profile gmoccapy-xyzab"); + +console.log("gmoccapy_xyzab_profile_smoke=ok"); diff --git a/web-rtcp-5axis-sim-plan/tests/node/verify_profile_boundary.mjs b/web-rtcp-5axis-sim-plan/tests/node/verify_profile_boundary.mjs index 906bc1d..dda20aa 100644 --- a/web-rtcp-5axis-sim-plan/tests/node/verify_profile_boundary.mjs +++ b/web-rtcp-5axis-sim-plan/tests/node/verify_profile_boundary.mjs @@ -30,7 +30,7 @@ assert.equal(xyzacTrtProfile.halPins.includes("motion.switchkins-type"), true); assert.equal(xyzacTrtProfile.halPins.includes("xyzac-trt-kins.tool-offset"), true); assert.equal(xyzacTrtProfile.promotionAllowed, false); assert.equal(xyzacTrtProfile.linuxCncKinematicsReady, false); -assert.deepEqual(fiveAxisProfiles.map(({ id }) => id), ["xyzac-trt", "xyzbc-trt"]); +assert.deepEqual(fiveAxisProfiles.map(({ id }) => id), ["xyzac-trt", "xyzbc-trt", "gmoccapy-xyzab"]); const xyzbcTrtProfile = getFiveAxisProfile("xyzbc-trt"); assert.equal(xyzbcTrtProfile.id, "xyzbc-trt"); @@ -59,6 +59,19 @@ assert.equal(xyzbcSourceSummary.referenceCount >= 7, true); assert.ok(xyzbcSourceSummary.references.some((reference) => reference.path.endsWith("xyzbc-trt.ini"))); assert.ok(xyzbcSourceSummary.references.some((reference) => reference.path.endsWith("xyzbc-trt-kins.c"))); +const gmoccapyXyzabProfile = getFiveAxisProfile("gmoccapy-xyzab"); +assert.equal(gmoccapyXyzabProfile.id, "gmoccapy-xyzab"); +assert.deepEqual(gmoccapyXyzabProfile.coordinates, ["X", "Y", "Z", "A", "B"]); +assert.equal(gmoccapyXyzabProfile.kinematics, "trivkins coordinates=xyzab"); +assert.equal(gmoccapyXyzabProfile.tcpCapable, false); +assert.equal(gmoccapyXyzabProfile.rtcpProof, false); +assert.equal(gmoccapyXyzabProfile.promotionAllowed, false); +assert.equal(gmoccapyXyzabProfile.hal.postguiRequiresHalcompReady, true); +const gmoccapySourceSummary = createProfileSourceReferenceSummary("gmoccapy-xyzab"); +assert.equal(gmoccapySourceSummary.referenceCount >= 10, true); +assert.ok(gmoccapySourceSummary.references.some((reference) => reference.path.endsWith("gmoccapy_XYZAB.ini"))); +assert.ok(gmoccapySourceSummary.references.some((reference) => reference.path.endsWith("gmoccapy_postgui.hal"))); + const panelSummary = createPyvcpHalBindingSummary(xyzacTrtPyvcpPanelSchema); assert.equal(panelSummary.schemaId, "xyzac-trt-switchkins-pyvcp"); assert.equal(panelSummary.controlCount, 5); diff --git a/web-rtcp-5axis-sim-plan/tests/node/verify_rtcp_store.mjs b/web-rtcp-5axis-sim-plan/tests/node/verify_rtcp_store.mjs index b8a7d90..10b1355 100644 --- a/web-rtcp-5axis-sim-plan/tests/node/verify_rtcp_store.mjs +++ b/web-rtcp-5axis-sim-plan/tests/node/verify_rtcp_store.mjs @@ -261,7 +261,10 @@ assert.equal(kinematicsState.rtcpFrame.readiness.linuxCncKinematicsReady, false) const store = createSimulationStore(); let state; -assert.equal(store.getState().availableProfiles.length, 2); +assert.deepEqual( + store.getState().availableProfiles.map((profile) => profile.id), + ["xyzac-trt", "xyzbc-trt", "gmoccapy-xyzab"], +); store.dispatch({ type: "SET_PROFILE", profileId: "xyzbc-trt" }); assert.equal(store.getState().machineProfile, "xyzbc-trt"); assert.equal(store.getState().profile.traj.coordinates, "XYZBC"); diff --git a/work/working4/01-function-content.md b/work/working4/01-function-content.md new file mode 100644 index 0000000..10ef401 --- /dev/null +++ b/work/working4/01-function-content.md @@ -0,0 +1,98 @@ +# 01 功能内容 + +生成日期:2026-06-26 + +## 1. 目标 + +使用 `working3` 中的 gmoccapy_XYZAB 执行链路分析和按钮图标资料,完善 +`web-rtcp-5axis-sim-plan` 的 gmoccapy 风格 Web 五轴仿真功能。 + +本阶段目标不是把 LinuxCNC GTK/gmoccapy 原程序移植到浏览器,也不是让浏览器直接运行 +LinuxCNC native NML/HAL 进程。目标是把 gmoccapy_XYZAB 的运行条件、按钮语义、NML/HAL +通信模型和图标资产转化为 Web 仿真项目可实施、可验证、可追溯的功能包。 + +## 2. 当前项目现状 + +`web-rtcp-5axis-sim-plan` 已具备这些基础能力: + +- gmoccapy 风格 Web shell:标题栏、预览区、DRO、G-code 面板、右侧模式栏、信息面板、override、主轴/冷却、底部控制栏。 +- 五轴 profile:当前已有 `xyzac-trt`、`xyzbc-trt`。 +- LinuxCNC source-derived runtime:已有 kinematics、interpreter、task/HAL runtime 接入和 worker fallback。 +- machine-file staging:可加载 LinuxCNC vendored 源程序。 +- RUN 主链路验证:已有 run preconditions、feedback loop、linear unit、browser evidence 等测试文档和证据。 +- 已有追溯矩阵:`docs/traceability-matrix.md` 记录了 Web 实现和 LinuxCNC 来源的边界。 + +## 3. working3 新增价值 + +`working3` 提供了两类资料,本阶段已将其转化为项目内 profile、runtime model、UI 图标、 +task gate、测试和 QA 证据: + +### 3.1 gmoccapy_XYZAB 执行与通信链路 + +输入文件: + +```text +/home/meswork/cnc_wams/work/working3/gmoccapy_XYZAB_execution_analysis.md +``` + +可转化为 Web 功能的关键点: + +- `gmoccapy_XYZAB.ini` 是 LinuxCNC 运行配置,不是单独程序。 +- 启动链路包括 `linuxcncsvr`、realtime/RTAPI/HAL、`milltask`、`halui`、HALFILE、`halcmd start`、`gmoccapy -ini`。 +- GUI 主要通过 `linuxcnc.command()`、`linuxcnc.stat()`、`linuxcnc.error_channel()` 与 `milltask` 通信。 +- HAL 侧通过 `gmoccapy.*` pins、`POSTGUI_HALFILE`、`halui`、`iocontrol`、`motmod`、`spindle_sim` 等连接状态和外部控制。 +- 当前 XYZAB 配置为 `trivkins coordinates=xyzab`,`JOINTS=5`,属于仿真回环机,不是 TCP/RTCP 运动学。 +- `NO_FORCE_HOMING = 0`,自动运行和 MDI 必须经过急停复位、上电、回零、模式切换、解释器空闲等互锁。 + +### 3.2 gmoccapy 按钮图标和控制清单 + +输入文件: + +```text +/home/meswork/cnc_wams/work/working3/gmoccapy_button_icons/button_icon_inventory.md +/home/meswork/cnc_wams/work/working3/gmoccapy_button_icons/button_icon_inventory.csv +/home/meswork/cnc_wams/work/working3/gmoccapy_button_icons/files/ +``` + +清单规模: + +- 清单行总数:211。 +- 有图标或图像的按钮/状态:116。 +- 纯文字或无图标按钮/状态:95。 +- 已复制图标文件:112 个。 +- 覆盖右侧主状态栏、底部主按钮栏、Auto 程序运行栏、MDI/宏、回零、Touch Off、Jog、主轴冷却、预览、编辑页、刀具页、文件选择页、内嵌 ToolEdit/OffsetPage、设置页控件。 + +## 4. 本阶段功能包状态 + +| 功能包 | 内容 | 当前状态 | 完成后效果 | +| --- | --- | --- | --- | +| F-XYZAB-01 gmoccapy_XYZAB 参考 profile | 把 `gmoccapy_XYZAB.ini` 的坐标、HALFILE、POSTGUI_HALFILE、`trivkins xyzab`、回零策略整理为 Web profile/source map。 | 已完成 | Web UI 可切换到 XYZAB 参考配置,并清楚标注其为 trivkins 仿真 profile。 | +| F-XYZAB-02 启动链路和通信诊断 | 在信息面板展示 LinuxCNC native 启动阶段、NML command/status/error、HAL/postgui 通信边界。 | 已完成 | 用户能看到 Web 仿真与 native gmoccapy 的通信差异,不把 UI 行为误认为真实 NML/HAL 进程。 | +| F-XYZAB-03 G-code 执行互锁强化 | 按 gmoccapy_XYZAB 的三层保护补齐 RUN/MDI/JOG/HOME/SPINDLE/COOLANT gate 说明和测试。 | 已完成 | RUN/MDI 等按钮 disabled 原因可解释,Node/browser 测试覆盖典型非法状态。 | +| F-XYZAB-04 按钮语义和图标资产映射 | 从 CSV 生成 Web 可消费按钮 manifest,并把核心 icon 接入右侧栏、底部栏、Auto 栏、预览栏、文件栏。 | 已完成 | UI 从文字按钮升级为 gmoccapy 风格图标按钮,active/inactive 状态可验证。 | +| F-XYZAB-05 HAL pin 与 postgui 状态面板 | 展示 `gmoccapy.*` pins、spindle feedback、tool offset、program progress、HALUI 等诊断状态。 | 已完成 | 信息面板可解释哪些是 NML 状态,哪些是 HAL pin 状态,哪些是 Web 仿真状态。 | +| F-XYZAB-06 宏/MDI/Tool/Touch 工作流 | 参考 gmoccapy 宏和工具页按钮逻辑,补齐 Web 侧宏按钮、MDI 历史、Tool/Touch 操作互锁。 | 边界内完成 | W4 验收覆盖 MDI gate、home/tool/touch 图标和互锁;宏编辑和 MDI 历史扩展未作为本阶段新增验收项。 | +| F-XYZAB-07 验收证据自动化 | 为新增 profile、按钮、互锁、图标、HAL 诊断补 Node/browser/PDF/截图证据。 | 已完成 | 每个功能都有命令、页面、JSON、截图或 PDF 证据。 | + +## 5. 不做事项 + +本阶段不做: + +- 不移植 GTK、Glade、Python gmoccapy runtime。 +- 不启动 native `linuxcncsvr`、`milltask`、`halui`、`motmod` 作为浏览器运行依赖。 +- 不把 `gmoccapy_XYZAB` 的 `trivkins` profile 声称为 RTCP/TCP 运动学 proof。 +- 不用 JavaScript 自行发明 G-code 解释器、刀补、REMAP 或运动规划语义。 +- 不把 icon 清单复制到 UI 后就认定控制语义完成,按钮仍必须通过 task policy 和 runtime 证据验收。 + +## 6. 已满足的成功定义 + +本阶段收口时满足: + +- 代码中有 `gmoccapy-xyzab` 或等价 reference profile,并显示 `XYZAB`、`trivkins`、HALFILE、POSTGUI_HALFILE、`NO_FORCE_HOMING=0` 等来源信息。 +- UI 核心按钮使用 `working3` 清单中的图标或 manifest,且 active/inactive 状态可被浏览器测试识别。 +- RUN、MDI、JOG、HOME、ESTOP、POWER、SPINDLE、COOLANT 的 gate 与 gmoccapy_XYZAB 文档一致。 +- HAL/postgui 诊断能区分 NML 命令、NML 状态、HAL pin、Web task/HAL simulation status。 +- `npm --prefix web-rtcp-5axis-sim-plan/app run build` 通过。 +- `npm --prefix web-rtcp-5axis-sim-plan/app run smoke:node` 通过。 +- 浏览器 smoke 覆盖 profile 切换、按钮 active 图标、canvas 非空、RUN blocked reason 和 HAL diagnostics;source-derived RTCP 运行证据仍由既有 `xyzac-trt`、`xyzbc-trt` 验收链路承担。 +- `05-acceptance-evidence.md` 已追加实际 JSON、截图、PDF 和报告路径。 diff --git a/work/working4/02-program-development-steps.md b/work/working4/02-program-development-steps.md new file mode 100644 index 0000000..97c790f --- /dev/null +++ b/work/working4/02-program-development-steps.md @@ -0,0 +1,316 @@ +# 02 程序开发详细步骤 + +生成日期:2026-06-26 + +## 1. 开发原则 + +- 先复用现有 `app/src` 架构:`profiles`、`runtime`、`state`、`ui`、`visualization`、`tests`。 +- 不引入 React/Vue 等 UI 框架。 +- 不把 gmoccapy native Python/GTK 代码作为浏览器依赖。 +- 图标资产可以使用 `working3/gmoccapy_button_icons/files/`,但按钮控制语义必须由现有 store/task policy/runtime 驱动。 +- 每个阶段必须同步更新 `04-task-matrix.md` 和 `03-progress-ledger.md`。 + +当前状态:阶段 A 到 G 已按 `04-task-matrix.md` 收口为 `done`。本文件保留为复现步骤和后续变更清单。 + +## 2. 阶段 A:资料和资产落库 + +目标:把 `working3` 资料变成项目内可追溯输入,而不是散落引用。 + +主要新增或更新文件: + +```text +web-rtcp-5axis-sim-plan/docs/gmoccapy-xyzab-reference.md +web-rtcp-5axis-sim-plan/app/src/ui-reference/gmoccapy-button-icons.json +web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/ +web-rtcp-5axis-sim-plan/docs/traceability-matrix.md +``` + +实施步骤: + +1. 新建 `docs/gmoccapy-xyzab-reference.md`,摘要吸收 `gmoccapy_XYZAB_execution_analysis.md`。 +2. 将 `button_icon_inventory.csv` 转换为 JSON manifest,保留字段:分类、button_id、label、tooltip、icon_name、requested_size、source_type、copied_file、signals、notes。 +3. 将核心按钮图标复制到 `app/src/assets/gmoccapy-icons/`,至少覆盖:estop、power、manual、mdi、auto、settings、home、tool、touch、open、run、stop、pause、step、reload、fullscreen、spindle、coolant、view/zoom。 +4. 在 manifest 中记录原始来源和 `working3` 复制文件路径。 +5. 更新 `docs/traceability-matrix.md`,新增 gmoccapy_XYZAB 和按钮 icon 追溯记录。 + +验收命令: + +```bash +find web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons -maxdepth 1 -type f | wc -l +node -e "JSON.parse(require('fs').readFileSync('web-rtcp-5axis-sim-plan/app/src/ui-reference/gmoccapy-button-icons.json','utf8')); console.log('icon_manifest_json=ok')" +git diff --check -- web-rtcp-5axis-sim-plan +``` + +验收标准: + +- JSON manifest 可解析。 +- 图标文件存在,文件名稳定,不依赖 `working3` 运行时路径。 +- 文档明确图标只证明 UI 资产来源,不证明按钮控制语义。 + +## 3. 阶段 B:新增 gmoccapy_XYZAB reference profile + +目标:在 Web 项目中建立 XYZAB/gmoccapy 参考 profile,表达 native INI/HAL 拓扑。 + +主要新增或更新文件: + +```text +web-rtcp-5axis-sim-plan/app/src/profiles/gmoccapy-xyzab.js +web-rtcp-5axis-sim-plan/app/src/profiles/index.js +web-rtcp-5axis-sim-plan/app/src/profiles/source-reference-map.js +web-rtcp-5axis-sim-plan/tests/node/verify_gmoccapy_xyzab_profile.mjs +``` + +实施步骤: + +1. 新增 profile id:`gmoccapy-xyzab`。 +2. 设置坐标:`["X", "Y", "Z", "A", "B"]`。 +3. 设置 kinematics:`trivkins coordinates=xyzab`,并标记 `tcpCapable=false`、`rtcpProof=false`。 +4. 记录 INI 来源:`linuxcnc/configs/sim/gmoccapy/gmoccapy_XYZAB.ini`。 +5. 记录 HALFILE:`core_sim_XYZAB.hal`、`spindle_sim.hal`、`simulated_home.hal`。 +6. 记录 POSTGUI_HALFILE:`gmoccapy_postgui.hal`。 +7. 记录 `TASK=milltask`、`EMCMOT=motmod`、`HALUI=halui`、`CYCLE_TIME=100`、`SERVO_PERIOD=1000000`。 +8. 加入 `fiveAxisProfiles` 列表,但 UI 文案必须显示它是 gmoccapy/trivkins 参考机型。 +9. Node 测试断言 profile 坐标、joint 数、HAL files、postgui、no-force-homing gate、semantic boundary。 + +验收命令: + +```bash +node web-rtcp-5axis-sim-plan/tests/node/verify_gmoccapy_xyzab_profile.mjs +npm --prefix web-rtcp-5axis-sim-plan/app run build +``` + +验收标准: + +- `gmoccapy-xyzab` 可通过 profile selector 选择。 +- 信息面板显示 `XYZAB`、`trivkins`、`gmoccapy_XYZAB.ini`、HALFILE、POSTGUI_HALFILE。 +- 不显示 `RTCP proof ready`,除非后续接入真实 source-derived TCP 运动学。 + +## 4. 阶段 C:NML/HAL 通信边界诊断 + +目标:让 Web UI 能解释 gmoccapy native 与 Web 仿真的通信差异。 + +主要新增或更新文件: + +```text +web-rtcp-5axis-sim-plan/app/src/runtime/gmoccapy-communication-model.js +web-rtcp-5axis-sim-plan/app/src/ui/gmoccapy-shell.js +web-rtcp-5axis-sim-plan/app/src/styles/gmoccapy.css +web-rtcp-5axis-sim-plan/tests/node/verify_gmoccapy_communication_model.mjs +``` + +实施步骤: + +1. 建立 communication model 数据结构: + - native command path:`gmoccapy -> linuxcnc.command -> NML emcCommand -> milltask`。 + - native status path:`milltask -> NML emcStatus/emcError -> stat/error poll`。 + - native HAL path:`gmoccapy.* pins <-> HAL shared memory`。 + - Web path:`button -> store dispatch -> task policy/runtime -> status snapshot -> UI/Three.js`。 +2. 在 info tabs 中新增 `gmoccapy comms` 或合并到 RTCP diagnostics。 +3. 对每个 action 显示 native equivalent command,例如 `STATE_ON`、`MODE_AUTO`、`AUTO_RUN`、`JOG_CONTINUOUS`。 +4. 显示 postgui 顺序:`halcomp.ready()` 后才能执行 POSTGUI_HALFILE。 +5. Node 测试断言主要命令链路和 HAL/postgui 说明存在。 + +验收命令: + +```bash +node web-rtcp-5axis-sim-plan/tests/node/verify_gmoccapy_communication_model.mjs +``` + +验收标准: + +- UI 能区分 NML command、NML status/error、HAL pin、Web runtime feedback。 +- 文案不暗示浏览器直接连接 native NML buffer 或 HAL shared memory。 + +## 5. 阶段 D:按钮图标和语义映射 + +目标:将当前文字按钮升级为 gmoccapy 风格 icon button,同时保持 task policy gate。 + +主要新增或更新文件: + +```text +web-rtcp-5axis-sim-plan/app/src/ui/gmoccapy-icon-registry.js +web-rtcp-5axis-sim-plan/app/src/ui/gmoccapy-shell.js +web-rtcp-5axis-sim-plan/app/src/styles/gmoccapy.css +web-rtcp-5axis-sim-plan/tests/node/verify_gmoccapy_icon_manifest.mjs +web-rtcp-5axis-sim-plan/tests/browser/gmoccapy_shell_smoke.html +``` + +实施步骤: + +1. 从 JSON manifest 建立 `getGmoccapyIcon(buttonId, stateVariant)`。 +2. 右侧主状态栏接入: + - `tbtn_estop`:`main_switch_on/off`。 + - `tbtn_on`:`power_off/on`。 + - `rbt_manual`、`rbt_mdi`、`rbt_auto`:inactive/active 图标。 + - `tbtn_setup`、`tbtn_user_tabs`。 +3. 底部栏接入: + - exit、homing、tool、touch、fullscreen、open、reload、run、stop、pause、step。 +4. Spindle/Coolant 接入: + - spindle forward/reverse/stop active 状态。 + - flood/mist active/inactive 状态。 +5. Preview toolbar 接入: + - view x/y/z/p、zoom in/out、toolpath、dimensions。 +6. 保留按钮 `aria-label`、title 和 disabled reason,不能只显示图标。 +7. browser smoke 增加断言:核心按钮存在 `data-icon-name`、active variant 和 disabled reason。 + +验收命令: + +```bash +node web-rtcp-5axis-sim-plan/tests/node/verify_gmoccapy_icon_manifest.mjs +npm --prefix web-rtcp-5axis-sim-plan/app run build +bash web-rtcp-5axis-sim-plan/tests/browser/verify_gmoccapy_shell_browser.sh +``` + +验收标准: + +- 核心按钮有图标、tooltip 或 aria-label。 +- active/inactive 状态随 store 状态变化。 +- RUN disabled 时仍显示 blocked reason。 +- 图标未加载时有稳定文本 fallback。 + +## 6. 阶段 E:G-code 执行互锁和按钮 gate 扩展 + +目标:按 gmoccapy_XYZAB 的执行条件补齐 Web gate 和测试。 + +主要新增或更新文件: + +```text +web-rtcp-5axis-sim-plan/app/src/state/linuxcnc-task-policy.js +web-rtcp-5axis-sim-plan/app/src/state/store.js +web-rtcp-5axis-sim-plan/tests/node/verify_gmoccapy_xyzab_gates.mjs +web-rtcp-5axis-sim-plan/tests/browser/gmoccapy_shell_smoke.html +``` + +实施步骤: + +1. RUN gate 覆盖: + - INI loaded。 + - machine-file opened。 + - not estop。 + - machine on。 + - all homed when `NO_FORCE_HOMING=0`。 + - mode auto。 + - interpreter idle。 + - task/HAL runtime ready when required。 +2. MDI gate 覆盖: + - machine on。 + - all homed when `NO_FORCE_HOMING=0`。 + - mode mdi 或可安全切换 MDI。 + - interpreter idle 或允许队列追加。 +3. JOG gate 覆盖: + - machine on。 + - mode manual。 + - not running。 + - axis/joint available。 +4. HOME gate 覆盖: + - machine on。 + - not running。 + - no joint already homing。 +5. SPINDLE/COOLANT/OVERRIDE gate 覆盖: + - estop/off 状态禁用。 + - auto/mdi reading/waiting 时限制手动覆盖主轴方向。 +6. Stop/Abort 必须在多数状态下可用,并清理 pause/start_line/active UI 状态。 +7. 增加每个 gate 的 operatorMessage,供按钮 title 和证据 JSON 使用。 + +验收命令: + +```bash +node web-rtcp-5axis-sim-plan/tests/node/verify_gmoccapy_xyzab_gates.mjs +node web-rtcp-5axis-sim-plan/tests/node/verify_run_preconditions.mjs +node web-rtcp-5axis-sim-plan/tests/node/verify_run_feedback_loop.mjs +``` + +验收标准: + +- 非法状态有明确 blocked reason。 +- 合法状态 RUN/MDI/JOG/HOME 可通过。 +- 原有 `verify_run_preconditions.mjs` 不回归。 + +## 7. 阶段 F:HAL pin/postgui 诊断面板 + +目标:把 gmoccapy_XYZAB 的 HAL pin 和 postgui 连接以 Web 诊断方式展示。 + +主要新增或更新文件: + +```text +web-rtcp-5axis-sim-plan/app/src/runtime/gmoccapy-hal-model.js +web-rtcp-5axis-sim-plan/app/src/ui/gmoccapy-shell.js +web-rtcp-5axis-sim-plan/tests/node/verify_gmoccapy_hal_model.mjs +``` + +实施步骤: + +1. 建立 HAL model 分类: + - hard buttons:`gmoccapy.h-button.*`、`gmoccapy.v-button.*`。 + - jog pins:`gmoccapy.jog.axis.*`、`gmoccapy.jog.jog-inc-*`。 + - override pins:feed/spindle/jog/rapid counts 和 direct-value。 + - tool pins:tooloffset、toolchange、diameter。 + - program pins:length、current-line、progress。 + - error/message pins。 +2. 建立 postgui nets: + - spindle feedback bar。 + - spindle at-speed LED。 + - tooloffset x/z。 + - simulated tool-change loop。 +3. UI 显示 `native pin name`、`web source`、`current value`、`semantic boundary`。 +4. Node 测试断言关键 pins 和 postgui nets 存在。 + +验收命令: + +```bash +node web-rtcp-5axis-sim-plan/tests/node/verify_gmoccapy_hal_model.mjs +``` + +验收标准: + +- 诊断面板清楚显示哪些是 native gmoccapy pins,哪些是 Web runtime 映射。 +- tool-change loop 被标记为 simulation loop,不表示真实人工换刀。 + +## 8. 阶段 G:浏览器证据和报告 + +目标:为本功能包生成可复查证据。 + +主要新增或更新文件: + +```text +qa/web-rtcp-5axis-site-test/ +qa/web-rtcp-5axis-site-test/output/gmoccapy-xyzab-function-report.json +qa/web-rtcp-5axis-site-test/output/gmoccapy-xyzab-function-report.pdf +qa/web-rtcp-5axis-site-test/output/gmoccapy-xyzab/ +work/working4/05-acceptance-evidence.md +``` + +实施步骤: + +1. 增加页面自动化用例: + - profile 切换到 `gmoccapy-xyzab`。 + - 检查 DRO 显示 X/Y/Z/A/B。 + - 检查 `trivkins`、`NO_FORCE_HOMING=0`、HALFILE、POSTGUI_HALFILE。 + - 检查按钮图标 active/inactive。 + - 检查 RUN blocked reason。 + - 完成一次合法状态 RUN 或模拟 RUN。 +2. 保存截图: + - loaded。 + - profile selected。 + - run blocked。 + - run ready。 + - running。 + - HAL diagnostics。 +3. 保存 JSON report。 +4. 输出 JSON 和 PDF 报告;本阶段已生成 `gmoccapy-xyzab-function-report.json` 和 `.pdf`。 +5. 更新 `05-acceptance-evidence.md`。 + +验收命令: + +```bash +npm --prefix web-rtcp-5axis-sim-plan/app run build +npm --prefix web-rtcp-5axis-sim-plan/app run smoke:node +bash web-rtcp-5axis-sim-plan/tests/browser/verify_gmoccapy_shell_browser.sh +node qa/web-rtcp-5axis-site-test/capture-gmoccapy-xyzab-function-cases.mjs +``` + +验收标准: + +- JSON report 中所有 case 为 PASS。 +- 截图文件存在且页面非空。 +- PDF 或替代报告路径写入 `05-acceptance-evidence.md`。 diff --git a/work/working4/03-progress-ledger.md b/work/working4/03-progress-ledger.md new file mode 100644 index 0000000..55f8533 --- /dev/null +++ b/work/working4/03-progress-ledger.md @@ -0,0 +1,512 @@ +# 03 推进台账 + +生成日期:2026-06-26 + +说明:本台账保留历史推进记录。早期条目中的“遗留问题”和“下一步”已由后续 W4-IMPL-002 +和 W4-DOC-002 收口;当前状态以 `04-task-matrix.md` 和 `05-acceptance-evidence.md` 为准。 + +## 1. 台账规则 + +每轮结束必须追加一条记录,格式保持一致: + +```text +轮次: +日期: +目标: +做了什么: +改了哪些文件: +验证了什么: +结果: +遗留问题: +下一步: +``` + +如果一轮只写文档,没有改代码,也必须明确写出“未改代码”。如果运行了测试,必须记录命令和结果。如果没有运行测试,必须说明原因。 + +## 2. 当前台账 + +### W4-DOC-001 + +日期:2026-06-26 + +目标: + +使用 `working3` 资料,为 `web-rtcp-5axis-sim-plan` 下一阶段功能完善建立文档包。 + +做了什么: + +- 梳理 `working3/gmoccapy_XYZAB_execution_analysis.md`,提取 gmoccapy_XYZAB native 启动顺序、NML command/status/error、HAL/postgui、G-code 运行互锁和按钮控制逻辑。 +- 梳理 `working3/gmoccapy_button_icons/`,确认按钮清单、CSV、112 个图标资源和 211 行按钮/状态记录。 +- 对照 `web-rtcp-5axis-sim-plan` 当前 README、docs、working_run、app/src、tests,确认已有 gmoccapy shell、xyzac/xyzbc profile、kinematics/interpreter/task-HAL runtime 和 RUN 验证。 +- 建立 `working4` 文档集,覆盖功能内容、开发步骤、推进台账、任务矩阵、验收证据、决策记录。 + +改了哪些文件: + +```text +/home/meswork/cnc_wams/work/working4/README.md +/home/meswork/cnc_wams/work/working4/01-function-content.md +/home/meswork/cnc_wams/work/working4/02-program-development-steps.md +/home/meswork/cnc_wams/work/working4/03-progress-ledger.md +/home/meswork/cnc_wams/work/working4/04-task-matrix.md +/home/meswork/cnc_wams/work/working4/05-acceptance-evidence.md +/home/meswork/cnc_wams/work/working4/06-decision-records.md +``` + +验证了什么: + +- 验证 `working3` 输入文件存在。 +- 验证 `working4` 起始为空,可作为本轮输出目录。 +- 验证目标项目已有构建、Node smoke、browser smoke、QA evidence 目录和相关文档。 +- 本轮以文档生成为主,未修改 `web-rtcp-5axis-sim-plan/app/src` 代码。 + +结果: + +- 文档规划完成。 +- 任务矩阵建立,后续实施可按任务编号推进,避免重复做。 + +遗留问题: + +- 尚未把 `working3` 图标复制到 app assets。 +- 尚未新增 `gmoccapy-xyzab` profile。 +- 尚未新增图标 manifest、HAL diagnostics、XYZAB gate 测试和浏览器报告。 + +下一步: + +从 `04-task-matrix.md` 的 `W4-A01` 开始,将资料和图标资产落库。 + +### W4-IMPL-001 + +日期:2026-06-26 + +目标: + +按 `working4` 从 W4-A01 开始实施资料落库、gmoccapy_XYZAB reference profile、通信/HAL 诊断模型和 Node 验收。 + +做了什么: + +- 新增 `docs/gmoccapy-xyzab-reference.md`,记录 native 启动顺序、NML command/status/error、HAL/postgui、互锁和图标资产边界。 +- 将 `working3/gmoccapy_button_icons/button_icon_inventory.csv` 转成 `app/src/ui-reference/gmoccapy-button-icons.json`,保留 211 行清单。 +- 将 `working3/gmoccapy_button_icons/files/` 的 112 个 PNG/SVG 图标复制到 `app/src/assets/gmoccapy-icons/`。 +- 新增 `gmoccapy-xyzab` profile,坐标为 XYZAB,标记 `trivkins coordinates=xyzab`、`tcpCapable=false`、`rtcpProof=false`、`promotionAllowed=false`。 +- 新增 gmoccapy communication model 和 HAL/postgui model。 +- 在 UI/store 层阻止 `gmoccapy-xyzab` 这种 reference-only profile 被切到 TCP/RTCP。 +- 修正 fallback RTCP frame 的 joint pose 轴映射,使 XYZAB 显示 B 轴而不是误用 C 轴。 +- 新增并接入 Node 测试:XYZAB profile、icon manifest、communication model、HAL model。 +- 更新 `docs/traceability-matrix.md`、`04-task-matrix.md`、`05-acceptance-evidence.md`。 + +改了哪些文件: + +```text +/home/meswork/cnc_wams/web-rtcp-5axis-sim-plan/docs/gmoccapy-xyzab-reference.md +/home/meswork/cnc_wams/web-rtcp-5axis-sim-plan/docs/traceability-matrix.md +/home/meswork/cnc_wams/web-rtcp-5axis-sim-plan/app/package.json +/home/meswork/cnc_wams/web-rtcp-5axis-sim-plan/app/src/ui-reference/gmoccapy-button-icons.json +/home/meswork/cnc_wams/web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/ +/home/meswork/cnc_wams/web-rtcp-5axis-sim-plan/app/src/profiles/gmoccapy-xyzab.js +/home/meswork/cnc_wams/web-rtcp-5axis-sim-plan/app/src/profiles/index.js +/home/meswork/cnc_wams/web-rtcp-5axis-sim-plan/app/src/profiles/source-reference-map.js +/home/meswork/cnc_wams/web-rtcp-5axis-sim-plan/app/src/runtime/gmoccapy-communication-model.js +/home/meswork/cnc_wams/web-rtcp-5axis-sim-plan/app/src/runtime/gmoccapy-hal-model.js +/home/meswork/cnc_wams/web-rtcp-5axis-sim-plan/app/src/runtime/rtcp-frame.js +/home/meswork/cnc_wams/web-rtcp-5axis-sim-plan/app/src/state/store.js +/home/meswork/cnc_wams/web-rtcp-5axis-sim-plan/app/src/ui/gmoccapy-shell.js +/home/meswork/cnc_wams/web-rtcp-5axis-sim-plan/tests/node/verify_gmoccapy_xyzab_profile.mjs +/home/meswork/cnc_wams/web-rtcp-5axis-sim-plan/tests/node/verify_gmoccapy_icon_manifest.mjs +/home/meswork/cnc_wams/web-rtcp-5axis-sim-plan/tests/node/verify_gmoccapy_communication_model.mjs +/home/meswork/cnc_wams/web-rtcp-5axis-sim-plan/tests/node/verify_gmoccapy_hal_model.mjs +/home/meswork/cnc_wams/web-rtcp-5axis-sim-plan/tests/node/verify_profile_boundary.mjs +/home/meswork/cnc_wams/web-rtcp-5axis-sim-plan/tests/node/verify_rtcp_store.mjs +/home/meswork/cnc_wams/work/working4/03-progress-ledger.md +/home/meswork/cnc_wams/work/working4/04-task-matrix.md +/home/meswork/cnc_wams/work/working4/05-acceptance-evidence.md +``` + +验证了什么: + +```bash +node web-rtcp-5axis-sim-plan/tests/node/verify_gmoccapy_xyzab_profile.mjs +node web-rtcp-5axis-sim-plan/tests/node/verify_gmoccapy_icon_manifest.mjs +node web-rtcp-5axis-sim-plan/tests/node/verify_gmoccapy_communication_model.mjs +node web-rtcp-5axis-sim-plan/tests/node/verify_gmoccapy_hal_model.mjs +node web-rtcp-5axis-sim-plan/tests/node/verify_profile_boundary.mjs +node web-rtcp-5axis-sim-plan/tests/node/verify_rtcp_store.mjs +npm --prefix web-rtcp-5axis-sim-plan/app run build +npm --prefix web-rtcp-5axis-sim-plan/app run smoke:node +bash web-rtcp-5axis-sim-plan/tests/browser/verify_gmoccapy_shell_browser.sh +bash web-rtcp-5axis-sim-plan/tests/browser/verify_gmoccapy_dist_browser.sh +git diff --check -- web-rtcp-5axis-sim-plan work/working4 +``` + +结果: + +- 新增 Node 测试全部通过。 +- `npm run build` 通过。 +- `npm run smoke:node` 通过。 +- browser shell smoke 和 dist browser smoke 均通过。 +- `git diff --check` 通过。 + +遗留问题: + +- 尚未建立 icon registry,也未将图标接入实际按钮 DOM。 +- communication/HAL model 已有数据和测试,但尚未接入信息面板页面。 +- 尚未新增 gmoccapy_XYZAB gate 独立测试。 +- 尚未生成 QA JSON/PDF/截图报告。 + +下一步: + +继续 `W4-U01`,建立 `app/src/ui/gmoccapy-icon-registry.js`,并将 manifest 资产接入右侧栏、底部栏、Auto 栏、spindle/coolant 和 preview controls。 + +### W4-IMPL-002 + +日期:2026-06-26 + +目标: + +继续 `working4` 的 UI/icon、gmoccapy_XYZAB gate、browser smoke 和 QA 报告任务。 + +做了什么: + +- 新增 `gmoccapy-icon-registry.js`,为核心 gmoccapy 按钮提供 icon name、asset path、variant 和 fallback。 +- 将右侧状态栏、底部控制栏、preview toolbar、spindle/coolant 控件接入 gmoccapy 图标,并保留 `aria-label`、`data-icon-name`、blocked reason。 +- 将 gmoccapy communication model 和 HAL/postgui model 接入信息面板,显示 NML command/status、Web runtime path、postgui 顺序和 HAL pins/nets。 +- 扩展 `linuxcnc-task-policy.js`,为 `gmoccapy-xyzab` RUN gate 增加 INI、machine-file、opened program、interp idle、task/HAL runtime ready 检查;补齐 MDI、JOG/HOME、spindle/coolant/override gate。 +- 在 store 中新增 spindle direction 行为,并对 coolant/spindle/override 操作应用 gate。 +- 新增 icon registry 和 gmoccapy_XYZAB gate Node 测试。 +- 更新 browser smoke,断言核心按钮 icon 和 gmoccapy NML/HAL diagnostics。 +- 新增 QA capture 脚本,生成 gmoccapy_XYZAB JSON/PDF 报告和 6 张截图。 +- 更新 `04-task-matrix.md` 和 `05-acceptance-evidence.md`。 + +改了哪些文件: + +```text +/home/meswork/cnc_wams/web-rtcp-5axis-sim-plan/app/package.json +/home/meswork/cnc_wams/web-rtcp-5axis-sim-plan/app/src/ui/gmoccapy-icon-registry.js +/home/meswork/cnc_wams/web-rtcp-5axis-sim-plan/app/src/ui/gmoccapy-shell.js +/home/meswork/cnc_wams/web-rtcp-5axis-sim-plan/app/src/styles/gmoccapy.css +/home/meswork/cnc_wams/web-rtcp-5axis-sim-plan/app/src/state/linuxcnc-task-policy.js +/home/meswork/cnc_wams/web-rtcp-5axis-sim-plan/app/src/state/store.js +/home/meswork/cnc_wams/web-rtcp-5axis-sim-plan/tests/node/verify_gmoccapy_icon_registry.mjs +/home/meswork/cnc_wams/web-rtcp-5axis-sim-plan/tests/node/verify_gmoccapy_xyzab_gates.mjs +/home/meswork/cnc_wams/web-rtcp-5axis-sim-plan/tests/browser/gmoccapy_shell_smoke.html +/home/meswork/cnc_wams/qa/web-rtcp-5axis-site-test/capture-gmoccapy-xyzab-function-cases.mjs +/home/meswork/cnc_wams/work/working4/03-progress-ledger.md +/home/meswork/cnc_wams/work/working4/04-task-matrix.md +/home/meswork/cnc_wams/work/working4/05-acceptance-evidence.md +``` + +验证了什么: + +```bash +node --check web-rtcp-5axis-sim-plan/app/src/ui/gmoccapy-shell.js +node --check web-rtcp-5axis-sim-plan/app/src/state/store.js +node --check web-rtcp-5axis-sim-plan/app/src/state/linuxcnc-task-policy.js +node --check qa/web-rtcp-5axis-site-test/capture-gmoccapy-xyzab-function-cases.mjs +node web-rtcp-5axis-sim-plan/tests/node/verify_gmoccapy_icon_registry.mjs +node web-rtcp-5axis-sim-plan/tests/node/verify_gmoccapy_xyzab_gates.mjs +node web-rtcp-5axis-sim-plan/tests/node/verify_rtcp_store.mjs +node web-rtcp-5axis-sim-plan/tests/node/verify_run_preconditions.mjs +npm --prefix web-rtcp-5axis-sim-plan/app run build +bash web-rtcp-5axis-sim-plan/tests/browser/verify_gmoccapy_shell_browser.sh +node qa/web-rtcp-5axis-site-test/capture-gmoccapy-xyzab-function-cases.mjs +``` + +结果: + +- 新增 Node 测试全部通过。 +- `verify_rtcp_store` 和 `verify_run_preconditions` 回归通过。 +- 静态 build 通过。 +- browser shell smoke 通过。 +- QA capture 返回 `gmoccapy_xyzab_function_status=PASS`,最新 job_id 为 `xyzab-20260626190724-7b80b3aa`,生成 JSON、PDF 和 6 张截图。 + +遗留问题: + +- `gmoccapy-xyzab` 仍为 `trivkins` reference-only profile,不提供 TCP/RTCP proof。 +- 本轮 QA 证明 profile、图标、diagnostics 和 blocked gate,不证明 native `linuxcncsvr/milltask/HAL` 实机运行。 + +下一步: + +完整 `npm --prefix web-rtcp-5axis-sim-plan/app run smoke:node`、build、browser smoke、dist browser smoke、QA capture 和 `git diff --check` 已作为本轮最终回归执行。 + +### W4-DOC-002 + +日期:2026-06-26 + +目标: + +继续收口 `working4`,消除状态文档中仍停留在初始规划阶段的过期描述。 + +做了什么: + +- 更新 `README.md`,明确 `working4` 当前是已实施、已验证、已归档状态,不再描述为仅生成规划文档。 +- 更新 `01-function-content.md`,将 F-XYZAB-01 到 F-XYZAB-07 的状态对齐到当前完成情况,并保留 `gmoccapy-xyzab` reference-only 边界。 +- 更新 `02-program-development-steps.md`,标明阶段 A 到 G 已收口,QA capture JSON/PDF 已生成。 +- 更新 `02-program-development-steps.md` 的阶段文件清单措辞,从规划口径调整为已归档的主要新增/更新文件。 +- 更新 `04-task-matrix.md`,新增 W4-D08 状态文档收口任务并标记 `done`。 +- 更新 `05-acceptance-evidence.md`,修正“只创建文档、没有 job_id/report_id”的旧说明,并补充 W4-U01、W4-V04、W4-V05 证据行。 + +改了哪些文件: + +```text +/home/meswork/cnc_wams/work/working4/README.md +/home/meswork/cnc_wams/work/working4/01-function-content.md +/home/meswork/cnc_wams/work/working4/02-program-development-steps.md +/home/meswork/cnc_wams/work/working4/03-progress-ledger.md +/home/meswork/cnc_wams/work/working4/04-task-matrix.md +/home/meswork/cnc_wams/work/working4/05-acceptance-evidence.md +``` + +验证了什么: + +```bash +rg -n "\\| W4-[A-Z0-9-]+ \\| (todo|in_progress|blocked|deferred) \\|" work/working4/04-task-matrix.md +node -e "const r=JSON.parse(require('fs').readFileSync('qa/web-rtcp-5axis-site-test/output/gmoccapy-xyzab-function-report.json','utf8')); if(r.status!=='PASS') process.exit(1); console.log(r.status, r.steps.length, r.checks.length)" +git diff --check -- web-rtcp-5axis-sim-plan qa/web-rtcp-5axis-site-test work/working4 +``` + +结果: + +- `04-task-matrix.md` 未发现 `todo`、`in_progress`、`blocked` 或 `deferred` 的任务行。 +- 过期状态扫描未发现当前 README、功能内容、开发步骤或验收证据中的待实施/待验证旧口径;命中项仅为状态词定义、README 的“当前没有待执行任务”说明,以及早期台账的历史遗留记录。 +- QA JSON 保持 `PASS`,包含 6 个步骤和 10 个检查。 +- `git diff --check -- web-rtcp-5axis-sim-plan qa/web-rtcp-5axis-site-test work/working4` 返回 0。 + +遗留问题: + +- `gmoccapy-xyzab` 仍为 `trivkins` reference-only profile,不提供 TCP/RTCP proof。 +- 本阶段不证明 native `linuxcncsvr/milltask/HAL` 实机运行。 + +下一步: + +- `working4` 当前无剩余任务;后续新增工作需先在 `04-task-matrix.md` 新增任务编号。 + +### W4-DOC-003 + +日期:2026-06-26 + +目标: + +继续完成 `working4` 收口,清理剩余会让读者误判为规划阶段的措辞。 + +做了什么: + +- 更新 `README.md` 文档清单说明,将“要完善/应改”口径改为“已完善/已改”口径。 +- 更新 `02-program-development-steps.md`,将各阶段“建议新增或更新文件”统一改为“主要新增或更新文件”。 +- 更新 `03-progress-ledger.md` 说明,明确早期条目的“遗留问题/下一步”是历史记录,当前状态以矩阵和验收证据为准。 +- 更新 `04-task-matrix.md`,将 W4-D01 验收标准改为后续维护入口,将 W4-T07 验收标准改为已输出 JSON、PDF 和截图。 + +改了哪些文件: + +```text +/home/meswork/cnc_wams/work/working4/README.md +/home/meswork/cnc_wams/work/working4/02-program-development-steps.md +/home/meswork/cnc_wams/work/working4/03-progress-ledger.md +/home/meswork/cnc_wams/work/working4/04-task-matrix.md +``` + +验证了什么: + +```bash +rg -n "\\| W4-[A-Z0-9-]+ \\| (todo|in_progress|blocked|deferred) \\|" work/working4/04-task-matrix.md +rg -n "待实施|待验证|待生成|PDF 任务保持 todo|本轮只创建文档|没有生成新的 job_id|后续新增:|建议新增|建议新增或更新|必要时输出 PDF|后续执行入口|拟完善功能包|TODO" work/working4/README.md work/working4/01-function-content.md work/working4/02-program-development-steps.md work/working4/04-task-matrix.md work/working4/05-acceptance-evidence.md +node -e "const r=JSON.parse(require('fs').readFileSync('qa/web-rtcp-5axis-site-test/output/gmoccapy-xyzab-function-report.json','utf8')); if(r.status!=='PASS') process.exit(1); console.log('qa_report_status='+r.status); console.log('qa_report_steps='+r.steps.length); console.log('qa_report_checks='+r.checks.length);" +git diff --check -- web-rtcp-5axis-sim-plan qa/web-rtcp-5axis-site-test work/working4 +``` + +结果: + +- 未发现未完成 W4 任务行。 +- 当前状态文档未发现规划阶段残留关键词。 +- QA JSON 保持 `PASS`,包含 6 个步骤和 10 个检查。 +- `git diff --check` 返回 0。 + +遗留问题: + +- 无新的 `working4` 剩余任务。 +- 保留既定边界:`gmoccapy-xyzab` 是 `trivkins` reference-only profile,不证明 TCP/RTCP 或 native LinuxCNC realtime 执行。 + +下一步: + +- 当前无需继续执行;后续新增需求先在 `04-task-matrix.md` 新增任务编号。 + +### W4-DOC-004 + +日期:2026-06-26 + +目标: + +继续复核 `working4` 验收证据,确认 QA report 编号字段与归档表一致。 + +做了什么: + +- 重新扫描 `04-task-matrix.md`,确认没有未完成 W4 任务行。 +- 重新扫描当前状态文档,确认没有规划阶段残留关键词。 +- 读取 `gmoccapy-xyzab-function-report.json`,确认报告字段为 `jobId` 和 `reportId`。 +- 读取 QA capture 脚本,确认控制台输出为 `gmoccapy_xyzab_function_job_id` 和 `gmoccapy_xyzab_function_report_id`,来源是同一组 report 字段。 +- 更新 `05-acceptance-evidence.md`,说明 JSON camelCase 字段与归档表 `job_id/report_id` 标签的对应关系。 + +改了哪些文件: + +```text +/home/meswork/cnc_wams/work/working4/03-progress-ledger.md +/home/meswork/cnc_wams/work/working4/05-acceptance-evidence.md +``` + +验证了什么: + +```bash +rg -n "\\| W4-[A-Z0-9-]+ \\| (todo|in_progress|blocked|deferred) \\|" work/working4/04-task-matrix.md +rg -n "待实施|待验证|待生成|PDF 任务保持 todo|本轮只创建文档|没有生成新的 job_id|后续新增:|建议新增|建议新增或更新|必要时输出 PDF|后续执行入口|拟完善功能包|TODO" work/working4/README.md work/working4/01-function-content.md work/working4/02-program-development-steps.md work/working4/04-task-matrix.md work/working4/05-acceptance-evidence.md +node -e "const r=JSON.parse(require('fs').readFileSync('qa/web-rtcp-5axis-site-test/output/gmoccapy-xyzab-function-report.json','utf8')); if(r.status!=='PASS') process.exit(1); console.log(r.jobId, r.reportId, r.status, r.steps.length, r.checks.length)" +git diff --check -- web-rtcp-5axis-sim-plan qa/web-rtcp-5axis-site-test work/working4 +``` + +结果: + +- 未发现未完成 W4 任务行。 +- 当前状态文档未发现规划阶段残留关键词。 +- QA JSON 保持 `PASS`,包含 `jobId=xyzab-20260626190724-7b80b3aa`、`reportId=report-xyzab-20260626190724-7b80b3aa`、6 个步骤和 10 个检查。 +- `git diff --check` 返回 0。 + +遗留问题: + +- 无新的 `working4` 剩余任务。 +- 保留既定边界:`gmoccapy-xyzab` 是 `trivkins` reference-only profile,不证明 TCP/RTCP 或 native LinuxCNC realtime 执行。 + +下一步: + +- 当前无需继续执行;后续新增需求先在 `04-task-matrix.md` 新增任务编号。 + +### W4-DOC-005 + +日期:2026-06-26 + +目标: + +建立 `working4` 一眼可读的最终收口入口,避免完成状态分散在 README、任务矩阵、验收证据和台账中。 + +做了什么: + +- 新增 `07-final-closure.md`,汇总收口结论、最终证据、QA identifiers、最终校验命令、保留边界和后续变更规则。 +- 更新 `README.md`,将 `07-final-closure.md` 标为最终收口入口,并加入文档清单和后续维护步骤。 +- 更新 `04-task-matrix.md`,新增 W4-D09 并标记 `done`。 + +改了哪些文件: + +```text +/home/meswork/cnc_wams/work/working4/07-final-closure.md +/home/meswork/cnc_wams/work/working4/README.md +/home/meswork/cnc_wams/work/working4/03-progress-ledger.md +/home/meswork/cnc_wams/work/working4/04-task-matrix.md +``` + +验证了什么: + +```bash +rg -n "\\| W4-[A-Z0-9-]+ \\| (todo|in_progress|blocked|deferred) \\|" work/working4/04-task-matrix.md +# stale wording scan command is recorded in 07-final-closure.md +node -e "const r=JSON.parse(require('fs').readFileSync('qa/web-rtcp-5axis-site-test/output/gmoccapy-xyzab-function-report.json','utf8')); if(r.status!=='PASS') process.exit(1); console.log(r.jobId, r.reportId, r.status, r.steps.length, r.checks.length)" +git diff --check -- web-rtcp-5axis-sim-plan qa/web-rtcp-5axis-site-test work/working4 +``` + +结果: + +- 未发现未完成 W4 任务行。 +- 当前状态文档未发现规划阶段残留关键词;`07-final-closure.md` 中的示例扫描命令已使用 escaped pattern 和拆分 token,避免自命中。 +- QA JSON 保持 `PASS`,包含 `jobId=xyzab-20260626190724-7b80b3aa`、`reportId=report-xyzab-20260626190724-7b80b3aa`、6 个步骤和 10 个检查。 +- `git diff --check` 返回 0。 + +遗留问题: + +- 无新的 `working4` 剩余任务。 +- 保留既定边界:`gmoccapy-xyzab` 是 `trivkins` reference-only profile,不证明 TCP/RTCP 或 native LinuxCNC realtime 执行。 + +下一步: + +- `working4` 已有最终收口入口;后续新增需求先在 `04-task-matrix.md` 新增任务编号,并同步更新 `07-final-closure.md`。 + +### W4-VERIFY-006 + +日期:2026-06-26 + +目标: + +接续上一轮中断后的 `working4` 收口状态,重新运行关键验收链路,确认当前代码、报告和最终证据仍一致。 + +做了什么: + +- 读取 `AGENTS.md` 和 `working4` README、任务矩阵、推进台账、最终收口说明,确认当前范围和日志规则。 +- 扫描 `04-task-matrix.md`,确认没有未完成 W4 任务行。 +- 扫描当前状态文档,确认没有规划阶段残留关键词。 +- 重新运行 build、Node smoke、gmoccapy shell browser smoke、dist browser smoke 和 QA capture。 +- QA capture 重新生成 `gmoccapy-xyzab-function-report.json`、`.pdf` 和截图目录内容。 +- 更新 `05-acceptance-evidence.md` 和 `07-final-closure.md`,将当前最终证据编号对齐到最新 QA report。 + +改了哪些文件: + +```text +/home/meswork/cnc_wams/work/working4/03-progress-ledger.md +/home/meswork/cnc_wams/work/working4/05-acceptance-evidence.md +/home/meswork/cnc_wams/work/working4/07-final-closure.md +``` + +验证了什么: + +```bash +rg -n "\\| W4-[A-Z0-9-]+ \\| (todo|in_progress|blocked|deferred) \\|" work/working4/04-task-matrix.md +TD_WORD="$(printf '%s%s' TO DO)"; STALE_W4_PATTERN="$(printf '\\u5f85\\u5b9e\\u65bd|\\u5f85\\u9a8c\\u8bc1|\\u5f85\\u751f\\u6210|PDF \\u4efb\\u52a1\\u4fdd\\u6301 todo|\\u672c\\u8f6e\\u53ea\\u521b\\u5efa\\u6587\\u6863|\\u6ca1\\u6709\\u751f\\u6210\\u65b0\\u7684 job_id|\\u540e\\u7eed\\u65b0\\u589e\\uff1a|\\u5efa\\u8bae\\u65b0\\u589e|\\u5efa\\u8bae\\u65b0\\u589e\\u6216\\u66f4\\u65b0|\\u5fc5\\u8981\\u65f6\\u8f93\\u51fa PDF|\\u540e\\u7eed\\u6267\\u884c\\u5165\\u53e3|\\u62df\\u5b8c\\u5584\\u529f\\u80fd\\u5305|%s' "$TD_WORD")"; rg -n "$STALE_W4_PATTERN" work/working4/README.md work/working4/01-function-content.md work/working4/02-program-development-steps.md work/working4/04-task-matrix.md work/working4/05-acceptance-evidence.md work/working4/07-final-closure.md +node -e "const r=JSON.parse(require('fs').readFileSync('qa/web-rtcp-5axis-site-test/output/gmoccapy-xyzab-function-report.json','utf8')); if(r.status!=='PASS') process.exit(1); console.log(r.jobId, r.reportId, r.status, r.steps.length, r.checks.length)" +npm --prefix web-rtcp-5axis-sim-plan/app run build +npm --prefix web-rtcp-5axis-sim-plan/app run smoke:node +bash web-rtcp-5axis-sim-plan/tests/browser/verify_gmoccapy_shell_browser.sh +bash web-rtcp-5axis-sim-plan/tests/browser/verify_gmoccapy_dist_browser.sh +node qa/web-rtcp-5axis-site-test/capture-gmoccapy-xyzab-function-cases.mjs +git diff --check -- web-rtcp-5axis-sim-plan qa/web-rtcp-5axis-site-test work/working4 +``` + +结果: + +- 未发现未完成 W4 任务行。 +- 当前状态文档未发现规划阶段残留关键词。 +- `npm --prefix web-rtcp-5axis-sim-plan/app run build` 返回 0,输出 `gmoccapy_static_build=ok`。 +- `npm --prefix web-rtcp-5axis-sim-plan/app run smoke:node` 返回 0,覆盖既有 smoke 和新增 gmoccapy_XYZAB profile/icon/communication/HAL/gate smoke。 +- gmoccapy shell browser smoke 返回 `gmoccapy_shell_smoke=ok`。 +- dist browser smoke 返回 `gmoccapy_dist_smoke=ok`。 +- QA capture 返回 `gmoccapy_xyzab_function_status=PASS`,最新 `job_id=xyzab-20260626214346-f4b4aa36`,`report_id=report-xyzab-20260626214346-f4b4aa36`,生成 JSON、PDF 和 6 张截图。 +- `git diff --check -- web-rtcp-5axis-sim-plan qa/web-rtcp-5axis-site-test work/working4` 返回 0。 + +遗留问题: + +- 无新的 `working4` 剩余任务。 +- 保留既定边界:`gmoccapy-xyzab` 是 `trivkins` reference-only profile,不证明 TCP/RTCP 或 native LinuxCNC realtime 执行。 + +下一步: + +- 当前无需继续执行;后续新增需求先在 `04-task-matrix.md` 新增任务编号,并同步更新 `05-acceptance-evidence.md` 和 `07-final-closure.md`。 + +## 3. 后续追加模板 + +### W4-XXX + +日期: + +目标: + +做了什么: + +改了哪些文件: + +```text + +``` + +验证了什么: + +```bash + +``` + +结果: + +遗留问题: + +下一步: diff --git a/work/working4/04-task-matrix.md b/work/working4/04-task-matrix.md new file mode 100644 index 0000000..8f8ac79 --- /dev/null +++ b/work/working4/04-task-matrix.md @@ -0,0 +1,86 @@ +# 04 任务矩阵 + +生成日期:2026-06-26 + +状态取值: + +- `done`:已完成并有证据。 +- `in_progress`:正在做。 +- `todo`:未开始。 +- `blocked`:被外部条件阻塞。 +- `deferred`:暂缓,不影响当前阶段验收。 + +## 1. 文档任务 + +| 任务编号 | 状态 | 任务 | 产物 | 验收标准 | +| --- | --- | --- | --- | --- | +| W4-D01 | done | 建立 working4 文档索引 | `README.md` | 列出 01-07 文档和后续维护入口。 | +| W4-D02 | done | 编写功能内容文档 | `01-function-content.md` | 覆盖目标、现状、working3 新价值、功能包、不做事项、成功定义。 | +| W4-D03 | done | 编写开发步骤文档 | `02-program-development-steps.md` | 按阶段列出应改文件、步骤、命令、验收标准。 | +| W4-D04 | done | 建立推进台账 | `03-progress-ledger.md` | 包含 W4-DOC-001 和后续追加模板。 | +| W4-D05 | done | 建立任务矩阵 | `04-task-matrix.md` | 所有后续任务有编号、状态、验收标准。 | +| W4-D06 | done | 建立验收证据文档 | `05-acceptance-evidence.md` | 记录现有证据、实际 QA 证据和验收边界。 | +| W4-D07 | done | 建立决策记录 | `06-decision-records.md` | 记录边界、技术路线、验收策略。 | +| W4-D08 | done | 收口 working4 状态文档 | `README.md`、`01-function-content.md`、`02-program-development-steps.md`、`05-acceptance-evidence.md` | 规划口径与已完成实施、QA 证据和验收边界一致。 | +| W4-D09 | done | 建立最终收口说明 | `07-final-closure.md` | 汇总完成结论、最终证据、保留边界和后续变更规则。 | + +## 2. 资料和资产任务 + +| 任务编号 | 状态 | 任务 | 主要文件 | 验收标准 | +| --- | --- | --- | --- | --- | +| W4-A01 | done | 建立 gmoccapy_XYZAB reference 文档 | `web-rtcp-5axis-sim-plan/docs/gmoccapy-xyzab-reference.md` | 文档覆盖 native 启动、NML、HAL、postgui、互锁、按钮控制逻辑。 | +| W4-A02 | done | 生成按钮图标 JSON manifest | `app/src/ui-reference/gmoccapy-button-icons.json` | JSON 可解析,记录 211 行清单并保留来源路径。 | +| W4-A03 | done | 复制核心 gmoccapy 图标到 app assets | `app/src/assets/gmoccapy-icons/` | 已复制 112 个图标,覆盖主状态栏、底部栏、Auto 栏、spindle/coolant、preview。 | +| W4-A04 | done | 更新追溯矩阵 | `docs/traceability-matrix.md` | 新增 gmoccapy_XYZAB、button icon manifest、communication model、HAL diagnostics 追溯项。 | + +## 3. Profile 和 runtime model 任务 + +| 任务编号 | 状态 | 任务 | 主要文件 | 验收标准 | +| --- | --- | --- | --- | --- | +| W4-P01 | done | 新增 `gmoccapy-xyzab` profile | `app/src/profiles/gmoccapy-xyzab.js`、`app/src/profiles/index.js` | profile 可选择,坐标为 XYZAB,标记 `trivkins`、`tcpCapable=false` 和 `rtcpProof=false`。 | +| W4-P02 | done | 新增 XYZAB source reference map | `app/src/profiles/source-reference-map.js` | 包含 `gmoccapy_XYZAB.ini`、`core_sim_XYZAB.hal`、`spindle_sim.hal`、`simulated_home.hal`、`gmoccapy_postgui.hal`。 | +| W4-P03 | done | 新增 gmoccapy communication model | `app/src/runtime/gmoccapy-communication-model.js` | 能列出 native NML command/status/error、HAL pin、Web runtime 映射。 | +| W4-P04 | done | 新增 gmoccapy HAL model | `app/src/runtime/gmoccapy-hal-model.js` | 能列出关键 `gmoccapy.*` pins 和 postgui nets。 | + +## 4. UI 和按钮任务 + +| 任务编号 | 状态 | 任务 | 主要文件 | 验收标准 | +| --- | --- | --- | --- | --- | +| W4-U01 | done | 建立 icon registry | `app/src/ui/gmoccapy-icon-registry.js` | `getGmoccapyIcon(buttonId, variant)` 可返回 icon path/name/fallback。 | +| W4-U02 | done | 右侧主状态栏接入 icon | `app/src/ui/gmoccapy-shell.js`、`app/src/styles/gmoccapy.css` | estop/power/manual/mdi/auto/settings/user tabs 有 active/inactive 图标。 | +| W4-U03 | done | 底部和 Auto 控制栏接入 icon | `gmoccapy-shell.js`、`gmoccapy.css` | open/reload/run/stop/pause/step/home/tool/touch/fullscreen 有图标和 aria-label。 | +| W4-U04 | done | spindle/coolant/preview 接入 icon | `gmoccapy-shell.js`、`gmoccapy.css` | spindle forward/reverse/stop、flood/mist、view/zoom/toolpath/dimensions 有图标或 fallback。 | +| W4-U05 | done | 信息面板展示 communication/HAL diagnostics | `gmoccapy-shell.js` | UI 可见 NML/HAL/Web runtime 边界和 postgui 顺序。 | + +## 5. Gate 和业务语义任务 + +| 任务编号 | 状态 | 任务 | 主要文件 | 验收标准 | +| --- | --- | --- | --- | --- | +| W4-G01 | done | RUN gate 对齐 gmoccapy_XYZAB | `app/src/state/linuxcnc-task-policy.js`、`store.js` | 覆盖 INI、machine-file、estop、power、home、auto、interp idle、runtime ready。 | +| W4-G02 | done | MDI gate 对齐 gmoccapy_XYZAB | `linuxcnc-task-policy.js`、`store.js` | 未上电、未回零、运行中等状态有明确 blocked reason。 | +| W4-G03 | done | JOG/HOME gate 对齐 gmoccapy_XYZAB | `linuxcnc-task-policy.js`、`store.js` | manual/on/not-running 状态规则可测。 | +| W4-G04 | done | spindle/coolant/override gate 对齐 gmoccapy_XYZAB | `linuxcnc-task-policy.js`、`gmoccapy-shell.js` | 急停/下电禁用,运行中限制手动主轴方向覆盖。 | +| W4-G05 | done | Stop/Abort 清理 UI 状态 | `store.js`、`gmoccapy-shell.js` | Stop 后 pause/start_line/active run state 清理,browser 可测。 | + +## 6. 测试和证据任务 + +| 任务编号 | 状态 | 任务 | 主要文件 | 验收标准 | +| --- | --- | --- | --- | --- | +| W4-T01 | done | 新增 XYZAB profile Node 测试 | `tests/node/verify_gmoccapy_xyzab_profile.mjs` | 断言坐标、HALFILE、POSTGUI、trivkins、boundary。 | +| W4-T02 | done | 新增 icon manifest Node 测试 | `tests/node/verify_gmoccapy_icon_manifest.mjs` | manifest 可解析,核心按钮均有 icon 或 fallback。 | +| W4-T03 | done | 新增 communication model Node 测试 | `tests/node/verify_gmoccapy_communication_model.mjs` | NML/HAL/Web 映射完整。 | +| W4-T04 | done | 新增 HAL model Node 测试 | `tests/node/verify_gmoccapy_hal_model.mjs` | 关键 pins 和 postgui nets 存在。 | +| W4-T05 | done | 新增 gate Node 测试 | `tests/node/verify_gmoccapy_xyzab_gates.mjs` | RUN/MDI/JOG/HOME/SPINDLE/COOLANT 合法和非法状态均覆盖。 | +| W4-T06 | done | 更新 browser smoke | `tests/browser/gmoccapy_shell_smoke.html` | 覆盖 profile 切换、icon active、blocked reason、HAL diagnostics。 | +| W4-T07 | done | 新增 QA 截图和报告脚本 | `qa/web-rtcp-5axis-site-test/capture-gmoccapy-xyzab-function-cases.mjs` | 输出 JSON、PDF 和截图。 | +| W4-T08 | done | 更新验收证据文档 | `work/working4/05-acceptance-evidence.md` | 追加实际命令、JSON、PDF、截图和资产路径。 | + +## 7. 全局验收任务 + +| 任务编号 | 状态 | 任务 | 命令 | 验收标准 | +| --- | --- | --- | --- | --- | +| W4-V01 | done | 静态构建 | `npm --prefix web-rtcp-5axis-sim-plan/app run build` | 返回 0。 | +| W4-V02 | done | Node smoke | `npm --prefix web-rtcp-5axis-sim-plan/app run smoke:node` | 返回 0,原有测试不回归。 | +| W4-V03 | done | Browser smoke | `bash web-rtcp-5axis-sim-plan/tests/browser/verify_gmoccapy_shell_browser.sh` | 返回 0,页面非空,canvas 非空。 | +| W4-V04 | done | Dist browser smoke | `bash web-rtcp-5axis-sim-plan/tests/browser/verify_gmoccapy_dist_browser.sh` | 返回 0。 | +| W4-V05 | done | 文档和空白检查 | `git diff --check -- web-rtcp-5axis-sim-plan qa/web-rtcp-5axis-site-test work/working4` | 返回 0。 | diff --git a/work/working4/05-acceptance-evidence.md b/work/working4/05-acceptance-evidence.md new file mode 100644 index 0000000..1b30e6c --- /dev/null +++ b/work/working4/05-acceptance-evidence.md @@ -0,0 +1,306 @@ +# 05 验收证据 + +生成日期:2026-06-26 + +## 1. 证据规则 + +每个功能完成时必须至少提供一种证据: + +- 命令输出:Node、npm build、browser smoke、QA capture。 +- 页面证据:本地 URL、云端 URL、页面状态说明。 +- JSON:机器可读 PASS/FAIL 报告。 +- 截图:关键页面状态。 +- PDF/DOCX/Markdown 报告:适合人工归档的报告。 +- job_id/report_id:如果由 CI、云端任务或报告生成器产生,必须记录。 + +本目录先由文档规划创建;后续 W4-IMPL-001、W4-IMPL-002 和收口检查已补齐实现、QA 证据和最新 +job_id/report_id。 + +注:QA JSON 内部字段使用 camelCase:`jobId`、`reportId`;控制台输出和本归档表使用 +`job_id`、`report_id` 标签,两者指向同一组编号。 + +## 2. 本轮文档证据 + +本轮输入资料确认: + +```bash +find /home/meswork/cnc_wams/work/working3 -maxdepth 3 -type f | sort +find /home/meswork/cnc_wams/web-rtcp-5axis-sim-plan -maxdepth 3 -type f | sort +find /home/meswork/cnc_wams/work/working4 -maxdepth 2 -type f -print | sort +``` + +本轮读取的核心资料: + +```text +/home/meswork/cnc_wams/work/working3/gmoccapy_XYZAB_execution_analysis.md +/home/meswork/cnc_wams/work/working3/gmoccapy_button_icons/README.md +/home/meswork/cnc_wams/work/working3/gmoccapy_button_icons/button_icon_inventory.md +/home/meswork/cnc_wams/work/working3/gmoccapy_button_icons/button_icon_inventory.csv +/home/meswork/cnc_wams/web-rtcp-5axis-sim-plan/README.md +/home/meswork/cnc_wams/web-rtcp-5axis-sim-plan/docs/technical-roadmap.md +/home/meswork/cnc_wams/web-rtcp-5axis-sim-plan/docs/traceability-matrix.md +/home/meswork/cnc_wams/web-rtcp-5axis-sim-plan/app/src/main.js +/home/meswork/cnc_wams/web-rtcp-5axis-sim-plan/app/src/ui/gmoccapy-shell.js +/home/meswork/cnc_wams/web-rtcp-5axis-sim-plan/app/src/state/store.js +``` + +本轮输出文件: + +```text +/home/meswork/cnc_wams/work/working4/README.md +/home/meswork/cnc_wams/work/working4/01-function-content.md +/home/meswork/cnc_wams/work/working4/02-program-development-steps.md +/home/meswork/cnc_wams/work/working4/03-progress-ledger.md +/home/meswork/cnc_wams/work/working4/04-task-matrix.md +/home/meswork/cnc_wams/work/working4/05-acceptance-evidence.md +/home/meswork/cnc_wams/work/working4/06-decision-records.md +/home/meswork/cnc_wams/work/working4/07-final-closure.md +``` + +## 3. 可复用的现有项目证据 + +### 3.1 Node 和 build 命令 + +项目已有命令: + +```bash +npm --prefix web-rtcp-5axis-sim-plan/app run build +npm --prefix web-rtcp-5axis-sim-plan/app run smoke:node +bash web-rtcp-5axis-sim-plan/tests/browser/verify_gmoccapy_shell_browser.sh +bash web-rtcp-5axis-sim-plan/tests/browser/verify_gmoccapy_dist_browser.sh +``` + +`smoke:node` 当前覆盖: + +```text +verify_linuxcnc_kinematics_runtime.mjs +verify_linuxcnc_interpreter_runtime.mjs +verify_linuxcnc_ini_runtime.mjs +verify_run_preconditions.mjs +verify_run_feedback_loop.mjs +verify_linuxcnc_task_hal_runtime.mjs +verify_native_task_hal_audit.mjs +verify_full_linuxcnc_5axis_source.mjs +verify_real_linuxcnc_5axis_program_cases.mjs +verify_full_execution_boundary.mjs +verify_machine_file_staging.mjs +verify_five_axis_session.mjs +verify_rtcp_store.mjs +verify_profile_boundary.mjs +verify_linear_unit_conversion.mjs +``` + +### 3.2 项目内已有 JSON/截图/PDF/DOCX + +可复用证据路径: + +```text +/home/meswork/cnc_wams/web-rtcp-5axis-sim-plan/build/readiness/native-task-hal-readiness.json +/home/meswork/cnc_wams/web-rtcp-5axis-sim-plan/working_run/run-feedback-evidence/run-feedback-local.json +/home/meswork/cnc_wams/web-rtcp-5axis-sim-plan/working_run/run-feedback-evidence/run-feedback-local.png +/home/meswork/cnc_wams/qa/web-rtcp-5axis-site-test/output/toolpath-preview-cases.json +/home/meswork/cnc_wams/qa/web-rtcp-5axis-site-test/output/run-preconditions-feedback.json +/home/meswork/cnc_wams/qa/web-rtcp-5axis-site-test/output/meter-scene-evidence.json +/home/meswork/cnc_wams/qa/web-rtcp-5axis-site-test/output/native-task-hal-comparison-report.json +/home/meswork/cnc_wams/qa/web-rtcp-5axis-site-test/output/native-task-hal-comparison-report.md +/home/meswork/cnc_wams/qa/web-rtcp-5axis-site-test/output/button-control-evidence-report.json +/home/meswork/cnc_wams/qa/web-rtcp-5axis-site-test/output/button-control-evidence-report.pdf +/home/meswork/cnc_wams/qa/web-rtcp-5axis-site-test/output/cloud-button-control-evidence-report.json +/home/meswork/cnc_wams/qa/web-rtcp-5axis-site-test/output/cloud-button-control-evidence-report.pdf +/home/meswork/cnc_wams/qa/web-rtcp-5axis-site-test/output/test-linuxcnc-source-run-report.json +/home/meswork/cnc_wams/qa/web-rtcp-5axis-site-test/output/test-linuxcnc-source-run-report-2026-06-22.docx +/home/meswork/cnc_wams/qa/web-rtcp-5axis-site-test/output/test-linuxcnc-source-run-report-2026-06-23.docx +``` + +云端 RUN 截图目录: + +```text +/home/meswork/cnc_wams/qa/web-rtcp-5axis-site-test/output/cloud-run-after-deploy/ +/home/meswork/cnc_wams/qa/web-rtcp-5axis-site-test/output/cloud-run-stop-after-deploy/ +/home/meswork/cnc_wams/qa/web-rtcp-5axis-site-test/output/cloud-run-debug/ +/home/meswork/cnc_wams/qa/web-rtcp-5axis-site-test/output/cloud-run-debug-current/ +``` + +## 4. working4 已生成的证据 + +| 任务 | 证据类型 | 目标路径 | 状态 | +| --- | --- | --- | --- | +| W4-A02 icon manifest | JSON | `web-rtcp-5axis-sim-plan/app/src/ui-reference/gmoccapy-button-icons.json` | 已生成,211 行清单 | +| W4-P01 XYZAB profile | Node output | `tests/node/verify_gmoccapy_xyzab_profile.mjs` 控制台输出 | 已通过 | +| W4-P03 communication model | Node output | `tests/node/verify_gmoccapy_communication_model.mjs` 控制台输出 | 已通过 | +| W4-P04 HAL model | Node output | `tests/node/verify_gmoccapy_hal_model.mjs` 控制台输出 | 已通过 | +| W4-U01 icon registry | Node output | `tests/node/verify_gmoccapy_icon_registry.mjs` 控制台输出 | 已通过 | +| W4-G01 到 W4-G05 gate | Node output | `tests/node/verify_gmoccapy_xyzab_gates.mjs` 控制台输出 | 已通过 | +| W4-U02 到 W4-U05 UI | Browser screenshot | `qa/web-rtcp-5axis-site-test/output/gmoccapy-xyzab/*.png` | 已生成 6 张截图 | +| W4-T07 QA report | JSON/PDF | `qa/web-rtcp-5axis-site-test/output/gmoccapy-xyzab-function-report.json`、`.pdf` | 已生成,PASS | +| W4-V01 build | 命令输出 | `npm --prefix ... run build` | 已通过 | +| W4-V02 node smoke | 命令输出 | `npm --prefix ... run smoke:node` | 已通过 | +| W4-V03 browser smoke | 命令输出和截图 | `verify_gmoccapy_shell_browser.sh` | 已通过 | +| W4-V04 dist browser smoke | 命令输出 | `verify_gmoccapy_dist_browser.sh` | 已通过 | +| W4-V05 whitespace check | 命令输出 | `git diff --check -- web-rtcp-5axis-sim-plan qa/web-rtcp-5axis-site-test work/working4` | 已通过 | + +## 5. W4-IMPL-001 实施证据 + +日期:2026-06-26 + +本轮新增和更新的关键产物: + +```text +web-rtcp-5axis-sim-plan/docs/gmoccapy-xyzab-reference.md +web-rtcp-5axis-sim-plan/app/src/ui-reference/gmoccapy-button-icons.json +web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons/ +web-rtcp-5axis-sim-plan/app/src/profiles/gmoccapy-xyzab.js +web-rtcp-5axis-sim-plan/app/src/runtime/gmoccapy-communication-model.js +web-rtcp-5axis-sim-plan/app/src/runtime/gmoccapy-hal-model.js +web-rtcp-5axis-sim-plan/tests/node/verify_gmoccapy_xyzab_profile.mjs +web-rtcp-5axis-sim-plan/tests/node/verify_gmoccapy_icon_manifest.mjs +web-rtcp-5axis-sim-plan/tests/node/verify_gmoccapy_communication_model.mjs +web-rtcp-5axis-sim-plan/tests/node/verify_gmoccapy_hal_model.mjs +``` + +资产证据: + +```bash +find web-rtcp-5axis-sim-plan/app/src/assets/gmoccapy-icons -maxdepth 1 -type f | wc -l +# 112 + +node -e "const m=JSON.parse(require('fs').readFileSync('web-rtcp-5axis-sim-plan/app/src/ui-reference/gmoccapy-button-icons.json','utf8')); console.log(m.rowCount,m.copiedIconCount)" +# 211 112 +``` + +新增 Node 测试证据: + +```bash +node web-rtcp-5axis-sim-plan/tests/node/verify_gmoccapy_xyzab_profile.mjs +# gmoccapy_xyzab_profile_smoke=ok + +node web-rtcp-5axis-sim-plan/tests/node/verify_gmoccapy_icon_manifest.mjs +# gmoccapy_icon_manifest_smoke=ok + +node web-rtcp-5axis-sim-plan/tests/node/verify_gmoccapy_communication_model.mjs +# gmoccapy_communication_model_smoke=ok + +node web-rtcp-5axis-sim-plan/tests/node/verify_gmoccapy_hal_model.mjs +# gmoccapy_hal_model_smoke=ok +``` + +全局验收命令: + +```bash +npm --prefix web-rtcp-5axis-sim-plan/app run build +# gmoccapy_static_build=ok + +npm --prefix web-rtcp-5axis-sim-plan/app run smoke:node +# linear_unit_conversion_smoke=ok +# 全链路返回 0,并包含 gmoccapy_xyzab_profile/icon_manifest/communication_model/hal_model smoke。 + +bash web-rtcp-5axis-sim-plan/tests/browser/verify_gmoccapy_shell_browser.sh +# gmoccapy_shell_smoke=ok + +bash web-rtcp-5axis-sim-plan/tests/browser/verify_gmoccapy_dist_browser.sh +# gmoccapy_dist_smoke=ok + +git diff --check -- web-rtcp-5axis-sim-plan work/working4 +# 返回 0 +``` + +## 6. job_id 和 report_id 台账 + +### 6.1 W4-IMPL-002 UI/gate/QA 证据 + +日期:2026-06-26 + +本轮新增和更新的关键产物: + +```text +web-rtcp-5axis-sim-plan/app/src/ui/gmoccapy-icon-registry.js +web-rtcp-5axis-sim-plan/app/src/ui/gmoccapy-shell.js +web-rtcp-5axis-sim-plan/app/src/styles/gmoccapy.css +web-rtcp-5axis-sim-plan/app/src/state/linuxcnc-task-policy.js +web-rtcp-5axis-sim-plan/app/src/state/store.js +web-rtcp-5axis-sim-plan/tests/node/verify_gmoccapy_icon_registry.mjs +web-rtcp-5axis-sim-plan/tests/node/verify_gmoccapy_xyzab_gates.mjs +web-rtcp-5axis-sim-plan/tests/browser/gmoccapy_shell_smoke.html +qa/web-rtcp-5axis-site-test/capture-gmoccapy-xyzab-function-cases.mjs +``` + +新增 Node 测试证据: + +```bash +node web-rtcp-5axis-sim-plan/tests/node/verify_gmoccapy_icon_registry.mjs +# gmoccapy_icon_registry_smoke=ok + +node web-rtcp-5axis-sim-plan/tests/node/verify_gmoccapy_xyzab_gates.mjs +# gmoccapy_xyzab_gates_smoke=ok + +node web-rtcp-5axis-sim-plan/tests/node/verify_rtcp_store.mjs +# rtcp_store_smoke=ok + +node web-rtcp-5axis-sim-plan/tests/node/verify_run_preconditions.mjs +# run_preconditions_ini_profile_smoke=ok +# run_preconditions_kinematics_smoke=ok +# run_preconditions_machine_file_smoke=ok +``` + +Build/browser/QA 证据: + +```bash +npm --prefix web-rtcp-5axis-sim-plan/app run build +# gmoccapy_static_build=ok + +bash web-rtcp-5axis-sim-plan/tests/browser/verify_gmoccapy_shell_browser.sh +# gmoccapy_shell_smoke=ok + +node qa/web-rtcp-5axis-site-test/capture-gmoccapy-xyzab-function-cases.mjs +# gmoccapy_xyzab_function_status=PASS +# gmoccapy_xyzab_function_job_id=xyzab-20260626214346-f4b4aa36 +# gmoccapy_xyzab_function_report_id=report-xyzab-20260626214346-f4b4aa36 +``` + +QA 报告路径: + +```text +/home/meswork/cnc_wams/qa/web-rtcp-5axis-site-test/output/gmoccapy-xyzab-function-report.json +/home/meswork/cnc_wams/qa/web-rtcp-5axis-site-test/output/gmoccapy-xyzab-function-report.pdf +/home/meswork/cnc_wams/qa/web-rtcp-5axis-site-test/output/gmoccapy-xyzab/01-loaded.png +/home/meswork/cnc_wams/qa/web-rtcp-5axis-site-test/output/gmoccapy-xyzab/02-profile-selected.png +/home/meswork/cnc_wams/qa/web-rtcp-5axis-site-test/output/gmoccapy-xyzab/03-run-blocked-power.png +/home/meswork/cnc_wams/qa/web-rtcp-5axis-site-test/output/gmoccapy-xyzab/04-run-blocked-reference-evidence.png +/home/meswork/cnc_wams/qa/web-rtcp-5axis-site-test/output/gmoccapy-xyzab/05-controls-active.png +/home/meswork/cnc_wams/qa/web-rtcp-5axis-site-test/output/gmoccapy-xyzab/06-hal-diagnostics.png +``` + +QA JSON 检查结果: + +```text +PASS XYZAB profile selected +PASS Reference profile blocks RTCP promotion +PASS RUN blocked before power +PASS RUN blocked by reference evidence +PASS Core icons rendered +PASS Spindle/coolant state updates +PASS NML command diagnostic +PASS Web runtime diagnostic +PASS HAL postgui diagnostic +PASS Screenshots are nonblank +``` + +### 6.2 job_id/report_id 表 + +归档表: + +| 日期 | job_id | report_id | 来源 | 对应任务 | 结果 | 证据路径 | +| --- | --- | --- | --- | --- | --- | --- | +| 2026-06-26 | N/A | N/A | 本轮文档生成和状态收口 | W4-D01 到 W4-D09 | done | `/home/meswork/cnc_wams/work/working4/` | +| 2026-06-26 | N/A | N/A | 本轮本地实施 | W4-A01 到 W4-A04、W4-P01 到 W4-P04、W4-T01 到 W4-T04、W4-V01 到 W4-V05 | done | `web-rtcp-5axis-sim-plan/app/src/`、`docs/`、`tests/node/` | +| 2026-06-26 | xyzab-20260626190724-7b80b3aa | report-xyzab-20260626190724-7b80b3aa | 本轮 QA capture | W4-U01 到 W4-U05、W4-G01 到 W4-G05、W4-T05 到 W4-T07 | PASS | `qa/web-rtcp-5axis-site-test/output/gmoccapy-xyzab-function-report.json`、`.pdf`、`output/gmoccapy-xyzab/` | +| 2026-06-26 | xyzab-20260626214346-f4b4aa36 | report-xyzab-20260626214346-f4b4aa36 | 继续复核 QA capture | W4-U01 到 W4-U05、W4-G01 到 W4-G05、W4-T05 到 W4-T07、W4-V01 到 W4-V05 | PASS | `qa/web-rtcp-5axis-site-test/output/gmoccapy-xyzab-function-report.json`、`.pdf`、`output/gmoccapy-xyzab/` | + +## 7. 验收缺口 + +当前缺口: + +- `gmoccapy-xyzab` 仍是 `trivkins` reference-only profile,不是 RTCP/TCP proof;真实 RTCP promotion 仍只来自 source-derived `xyzac-trt`、`xyzbc-trt`。 +- 本轮 QA 对 `gmoccapy-xyzab` 证明 profile、图标、diagnostics 和 gate blocked reason,不证明 native `linuxcncsvr/milltask/HAL` 实机运行。 + +本轮新增证据已补齐原先 UI icon、communication/HAL diagnostics、XYZAB gate 和 QA JSON/PDF 缺口。 diff --git a/work/working4/06-decision-records.md b/work/working4/06-decision-records.md new file mode 100644 index 0000000..a6b8c5c --- /dev/null +++ b/work/working4/06-decision-records.md @@ -0,0 +1,182 @@ +# 06 决策记录 + +生成日期:2026-06-26 + +## ADR-001:working3 作为参考输入,不直接作为 runtime 依赖 + +状态:accepted + +决策: + +`working3` 中的 Markdown、CSV 和图标文件是功能完善的参考输入。后续实现时应把需要长期使用的资料复制或转换到 `web-rtcp-5axis-sim-plan` 内部目录,而不是让应用运行时依赖 `work/working3`。 + +原因: + +- `work/working3` 是资料整理目录,不是产品运行目录。 +- Web 应用需要稳定的 assets、manifest 和 source map。 +- 这样可以在追溯矩阵中明确来源,同时避免后续清理 `work/` 时破坏应用。 + +后续影响: + +- 图标必须落到 `app/src/assets/gmoccapy-icons/` 或等价目录。 +- CSV 必须转换为 JSON manifest 或构建期可解析资产。 + +## ADR-002:不移植 native gmoccapy GTK/Glade runtime + +状态:accepted + +决策: + +Web 项目只参考 gmoccapy 的布局、按钮、互锁和通信模型,不把 `gmoccapy.py`、GTK、Glade、Python REMAP runtime 直接搬进浏览器。 + +原因: + +- 项目目标是 Web 仿真产品,不是替代 LinuxCNC native GUI。 +- 浏览器不能等同 native NML buffer、HAL shared memory 和 Linux realtime thread。 +- 当前项目已有原生 HTML/CSS/ES module shell,继续复用成本最低。 + +后续影响: + +- 文档和 UI 必须用 `semanticBoundary` 说明 Web 模拟边界。 +- Python GUI runtime 一直保持 `reference only`。 + +## ADR-003:gmoccapy_XYZAB 是 trivkins 参考 profile,不是 RTCP proof + +状态:accepted + +决策: + +新增 `gmoccapy-xyzab` 时,必须标记为 `trivkins coordinates=xyzab` 的 gmoccapy 参考机型,不得标记为 RTCP/TCP 运动学 proof。 + +原因: + +- `gmoccapy_XYZAB.ini` 的运动学是 `trivkins`。 +- RTCP/TCP 运动学 proof 当前来自 `xyzac-trt`、`xyzbc-trt` 等 source-derived kinematics runtime。 +- 把 XYZAB trivkins 误标为 RTCP 会污染验收标准。 + +后续影响: + +- UI 可以显示 XYZAB 轴和 gmoccapy native 启动链路。 +- RTCP badge 对该 profile 应显示 `not TCP proof` 或等价说明,除非后续接入真实 TCP 运动学。 + +## ADR-004:NML/HAL 通信以诊断模型展示,控制仍走 Web store/task policy/runtime + +状态:accepted + +决策: + +Web UI 显示 gmoccapy native 的 NML/HAL 通信路径,但按钮点击仍走现有 `store.dispatch`、`linuxcnc-task-policy`、runtime status snapshot。 + +原因: + +- 当前浏览器应用没有 native NML buffer。 +- 现有 store/task policy/runtime 已覆盖 RUN、MDI、JOG、HOME、task/HAL status loop。 +- 诊断模型能帮助用户理解 native gmoccapy,但不会制造虚假的 native 连接。 + +后续影响: + +- 每个按钮可显示 native equivalent command,例如 `STATE_ON`、`MODE_AUTO`、`AUTO_RUN`。 +- 证据中必须区分 native reference 和 Web execution。 + +## ADR-005:按钮图标不能替代按钮语义验收 + +状态:accepted + +决策: + +图标接入只算 UI 资产验收。按钮是否正确,必须通过 task policy、store、runtime 和 browser action 证据验收。 + +原因: + +- `working3` 图标清单只说明图标来源、按钮名、tooltip 和信号线索。 +- 真正的执行安全依赖 machine state、mode、interp state、home state、runtime readiness。 +- 防止“看起来像 gmoccapy”但控制逻辑不正确。 + +后续影响: + +- 每个核心按钮至少要有 icon 证据和 gate/action 证据。 +- browser smoke 应断言 active icon 和 disabled reason。 + +## ADR-006:G-code 执行互锁按三层保护建模 + +状态:accepted + +决策: + +RUN/MDI/JOG/HOME 等 gate 按 gmoccapy_XYZAB 文档中的三层保护建模: + +1. UI 按钮敏感状态。 +2. Action/task policy gate。 +3. runtime 或 LinuxCNC source-derived boundary 最终校验。 + +原因: + +- gmoccapy native 本身不是只靠一个按钮判断。 +- LinuxCNC 后台会再次拒绝非法命令。 +- Web 侧需要给用户可读 blocked reason,同时保持 runtime 校验。 + +后续影响: + +- 测试必须覆盖非法状态和合法状态。 +- Stop/Abort 的可用范围应大于 Run/MDI/Jog。 + +## ADR-007:POSTGUI_HALFILE 必须作为顺序约束记录 + +状态:accepted + +决策: + +HAL/postgui 诊断中必须记录:`gmoccapy_postgui.hal` 只能在 `gmoccapy.halcomp.ready()` 后执行。 + +原因: + +- postgui 文件引用 `gmoccapy.*` pins,普通 HALFILE 阶段这些 pins 尚不存在。 +- 这是 gmoccapy native 启动顺序中的关键边界。 +- Web 侧如果展示 HAL model,也要保留这个顺序概念。 + +后续影响: + +- HAL model 中 postgui nets 独立于普通 HALFILE。 +- 文档和 UI 不应把 postgui pin 连接混入实时 HAL 启动前阶段。 + +## ADR-008:新增功能必须 evidence-first promotion + +状态:accepted + +决策: + +任何新增功能不能只凭代码合入认定完成,必须补齐 `05-acceptance-evidence.md` 中对应证据。 + +原因: + +- 当前项目已经形成 Node smoke、browser smoke、QA JSON、截图、PDF/DOCX 的证据链。 +- gmoccapy_XYZAB 功能涉及 UI、profile、HAL、NML、gate、图标,多边界容易误判。 +- 证据优先可以防止重复做和回归。 + +后续影响: + +- `04-task-matrix.md` 中没有证据的任务不得标为 `done`。 +- 文档、代码、测试、报告必须一起更新。 + +## ADR-009:gmoccapy_XYZAB profile 必须阻断 TCP/RTCP 切换 + +状态:accepted + +决策: + +`gmoccapy-xyzab` profile 虽然进入 profile selector,但必须标记 +`tcpCapable=false`、`rtcpProof=false`,并在 UI 和 store 层阻断 `tcp-*` kinsType +或 `SET_RTCP enabled`。 + +原因: + +- `gmoccapy_XYZAB.ini` 的真实运动学是 `trivkins coordinates=xyzab`。 +- 当前 Web 项目的 source-derived TCP/RTCP proof 来自 `xyzac-trt` 和 `xyzbc-trt`。 +- 如果 selector 允许 XYZAB reference profile 打开 TCP,会造成“参考配置可运行 RTCP”的误判。 + +后续影响: + +- 侧栏 TCP 按钮在 `gmoccapy-xyzab` 下应 disabled,并给出 reference-only 原因。 +- `store.dispatch({ type: "SET_KINS_TYPE", kinsType: "tcp-..." })` 和 + `SET_RTCP enabled` 必须保持防护,即使未来 UI 改动也不能绕过。 +- 如果未来接入真实 XYZAB TCP kinematics,应新增独立 runtime proof 和测试后再修改该决策。 diff --git a/work/working4/07-final-closure.md b/work/working4/07-final-closure.md new file mode 100644 index 0000000..6bd7a76 --- /dev/null +++ b/work/working4/07-final-closure.md @@ -0,0 +1,86 @@ +# 07 最终收口说明 + +生成日期:2026-06-26 + +## 1. 收口结论 + +`working4` 当前已完成。`04-task-matrix.md` 中 W4-D、W4-A、W4-P、W4-U、W4-G、 +W4-T、W4-V 任务均为 `done`,当前没有 `todo`、`in_progress`、`blocked` 或 +`deferred` 任务行。 + +本阶段已完成: + +- `gmoccapy-xyzab` reference profile 和 source reference map。 +- gmoccapy button icon manifest、核心图标资产和 icon registry。 +- gmoccapy native NML/HAL/postgui communication diagnostics。 +- RUN、MDI、JOG、HOME、spindle、coolant、override gate 对齐。 +- Node smoke、browser smoke、dist browser smoke、QA JSON/PDF/截图证据。 +- 文档矩阵、推进台账、验收证据和决策记录归档。 + +## 2. 最终证据 + +QA report: + +```text +/home/meswork/cnc_wams/qa/web-rtcp-5axis-site-test/output/gmoccapy-xyzab-function-report.json +/home/meswork/cnc_wams/qa/web-rtcp-5axis-site-test/output/gmoccapy-xyzab-function-report.pdf +``` + +QA identifiers: + +```text +jobId/job_id=xyzab-20260626214346-f4b4aa36 +reportId/report_id=report-xyzab-20260626214346-f4b4aa36 +status=PASS +steps=6 +checks=10 +generatedAt=2026-06-26T21:43:46.310Z +``` + +截图目录: + +```text +/home/meswork/cnc_wams/qa/web-rtcp-5axis-site-test/output/gmoccapy-xyzab/ +``` + +最终校验命令: + +```bash +rg -n "\\| W4-[A-Z0-9-]+ \\| (todo|in_progress|blocked|deferred) \\|" work/working4/04-task-matrix.md +TD_WORD="$(printf '%s%s' TO DO)" +STALE_W4_PATTERN="$(printf '\\u5f85\\u5b9e\\u65bd|\\u5f85\\u9a8c\\u8bc1|\\u5f85\\u751f\\u6210|PDF \\u4efb\\u52a1\\u4fdd\\u6301 todo|\\u672c\\u8f6e\\u53ea\\u521b\\u5efa\\u6587\\u6863|\\u6ca1\\u6709\\u751f\\u6210\\u65b0\\u7684 job_id|\\u540e\\u7eed\\u65b0\\u589e\\uff1a|\\u5efa\\u8bae\\u65b0\\u589e|\\u5efa\\u8bae\\u65b0\\u589e\\u6216\\u66f4\\u65b0|\\u5fc5\\u8981\\u65f6\\u8f93\\u51fa PDF|\\u540e\\u7eed\\u6267\\u884c\\u5165\\u53e3|\\u62df\\u5b8c\\u5584\\u529f\\u80fd\\u5305|%s' "$TD_WORD")" +rg -n "$STALE_W4_PATTERN" work/working4/README.md work/working4/01-function-content.md work/working4/02-program-development-steps.md work/working4/04-task-matrix.md work/working4/05-acceptance-evidence.md work/working4/07-final-closure.md +node -e "const r=JSON.parse(require('fs').readFileSync('qa/web-rtcp-5axis-site-test/output/gmoccapy-xyzab-function-report.json','utf8')); if(r.status!=='PASS') process.exit(1); console.log(r.jobId, r.reportId, r.status, r.steps.length, r.checks.length)" +npm --prefix web-rtcp-5axis-sim-plan/app run build +npm --prefix web-rtcp-5axis-sim-plan/app run smoke:node +bash web-rtcp-5axis-sim-plan/tests/browser/verify_gmoccapy_shell_browser.sh +bash web-rtcp-5axis-sim-plan/tests/browser/verify_gmoccapy_dist_browser.sh +node qa/web-rtcp-5axis-site-test/capture-gmoccapy-xyzab-function-cases.mjs +git diff --check -- web-rtcp-5axis-sim-plan qa/web-rtcp-5axis-site-test work/working4 +``` + +最终校验结果: + +- 未发现未完成 W4 任务行。 +- 当前状态文档未发现规划阶段残留关键词。 +- `npm run build`、`npm run smoke:node`、gmoccapy shell browser smoke 和 dist browser smoke 均返回 0。 +- QA capture 重新生成 JSON/PDF/截图,状态为 `PASS`,包含 6 个步骤和 10 个检查。 +- `git diff --check` 返回 0。 + +## 3. 保留边界 + +- `gmoccapy-xyzab` 是 `trivkins coordinates=xyzab` reference-only profile。 +- 本阶段不把 `gmoccapy-xyzab` 声称为 TCP/RTCP proof。 +- 本阶段不证明 native `linuxcncsvr`、`milltask`、HAL realtime thread 或 gmoccapy GTK runtime 实机运行。 +- 真实 RTCP promotion 仍来自 source-derived `xyzac-trt`、`xyzbc-trt` 等已有验收链路。 + +## 4. 后续变更规则 + +后续如继续扩展 `working4` 范围,必须先在 `04-task-matrix.md` 新增任务编号,不应复用已完成的 W4-D/W4-A/W4-P/W4-U/W4-G/W4-T/W4-V 任务作为未完成项。 + +每个新增任务必须同步更新: + +- `03-progress-ledger.md` +- `04-task-matrix.md` +- `05-acceptance-evidence.md` +- 本文件的最终证据或保留边界 diff --git a/work/working4/README.md b/work/working4/README.md new file mode 100644 index 0000000..1c83d6e --- /dev/null +++ b/work/working4/README.md @@ -0,0 +1,59 @@ +# working4 文档索引 + +生成日期:2026-06-26 + +本目录用于承接 `/home/meswork/cnc_wams/work/working3` 的资料,规划、实施并归档 +`/home/meswork/cnc_wams/web-rtcp-5axis-sim-plan` 的 gmoccapy_XYZAB 功能完善工作。 + +截至 2026-06-26,`04-task-matrix.md` 中 W4-D、W4-A、W4-P、W4-U、W4-G、W4-T、W4-V +任务均已收口为 `done`。`07-final-closure.md` 是本阶段最终收口入口。 + +当前状态: + +- 已完成:gmoccapy_XYZAB reference profile、图标 manifest/assets、communication/HAL diagnostics、task gate、browser smoke、QA JSON/PDF/截图证据。 +- 保留边界:`gmoccapy-xyzab` 仍是 `trivkins` reference-only profile,不作为 TCP/RTCP proof,也不证明 native `linuxcncsvr/milltask/HAL` 实机运行。 +- 后续变更:需要先在 `04-task-matrix.md` 新增任务编号,再按 `03-progress-ledger.md` 和 `05-acceptance-evidence.md` 追加证据。 + +## 文档清单 + +| 编号 | 文件 | 用途 | +| --- | --- | --- | +| 01 | `01-function-content.md` | 功能内容:说明已完善功能、资料来源、边界和成功定义。 | +| 02 | `02-program-development-steps.md` | 程序开发详细步骤:记录各阶段已改文件、实现动作、命令和验收口径。 | +| 03 | `03-progress-ledger.md` | 推进台账:记录每轮做了什么、改了哪些文件、验证了什么、下一步是什么。 | +| 04 | `04-task-matrix.md` | 任务矩阵:统一任务编号、状态、验收标准,防止重复做。 | +| 05 | `05-acceptance-evidence.md` | 验收证据:命令、页面、job_id、report_id、PDF、截图、JSON 等证据路径。 | +| 06 | `06-decision-records.md` | 决策记录:记录为什么这么做,后续变更时不重复争论。 | +| 07 | `07-final-closure.md` | 最终收口说明:汇总完成结论、最终证据、保留边界和后续变更规则。 | + +## 资料输入 + +主要输入资料: + +```text +/home/meswork/cnc_wams/work/working3/gmoccapy_XYZAB_execution_analysis.md +/home/meswork/cnc_wams/work/working3/gmoccapy_button_icons/README.md +/home/meswork/cnc_wams/work/working3/gmoccapy_button_icons/button_icon_inventory.md +/home/meswork/cnc_wams/work/working3/gmoccapy_button_icons/button_icon_inventory.csv +/home/meswork/cnc_wams/work/working3/gmoccapy_button_icons/files/ +``` + +目标项目现有资料和代码: + +```text +/home/meswork/cnc_wams/web-rtcp-5axis-sim-plan/README.md +/home/meswork/cnc_wams/web-rtcp-5axis-sim-plan/docs/ +/home/meswork/cnc_wams/web-rtcp-5axis-sim-plan/working_run/ +/home/meswork/cnc_wams/web-rtcp-5axis-sim-plan/app/src/ +/home/meswork/cnc_wams/web-rtcp-5axis-sim-plan/tests/ +``` + +## 后续维护入口 + +当前没有待执行的 `todo` 或 `in_progress` 任务。后续如新增工作,先打开: + +1. `04-task-matrix.md`,新增任务编号、状态和验收标准。 +2. `02-program-development-steps.md`,按对应阶段复用或扩展代码和测试步骤。 +3. `03-progress-ledger.md`,每轮结束追加台账。 +4. `05-acceptance-evidence.md`,补齐命令、截图、JSON、PDF 和报告编号。 +5. `07-final-closure.md`,更新最终证据或保留边界。