对齐 gmoccapy XYZAB 模式互锁
This commit is contained in:
@@ -218,6 +218,12 @@ function gateMode(status, requestedMode) {
|
||||
if (status.taskMode === "auto" && status.interpState !== "idle" && targetMode !== "auto") {
|
||||
return block(status, "mode blocked: AUTO interpreter is not idle");
|
||||
}
|
||||
if (status.taskState !== "on") {
|
||||
return block(status, `mode blocked: machine must be on before ${targetMode.toUpperCase()}`);
|
||||
}
|
||||
if ((targetMode === "mdi" || targetMode === "auto") && !status.allHomed && !status.noForceHoming) {
|
||||
return block(status, `mode blocked: home machine before ${targetMode.toUpperCase()}`);
|
||||
}
|
||||
return allow(status);
|
||||
}
|
||||
|
||||
|
||||
@@ -349,14 +349,17 @@ 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`)}"`;
|
||||
const autoGate = gateLinuxCncTaskAction(state, { type: "SET_MODE", mode: "auto" });
|
||||
const manualGate = gateLinuxCncTaskAction(state, { type: "SET_MODE", mode: "manual" });
|
||||
const mdiGate = gateLinuxCncTaskAction(state, { type: "SET_MODE", mode: "mdi" });
|
||||
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" })}
|
||||
${iconButtonHtml({ buttonId: "rbt_auto", action: "mode-auto", label: "AUTO", title: autoGate.operatorMessage || "Enter auto mode", className: "sidebar-button", active: state.machine.mode === "auto", gate: autoGate })}
|
||||
${iconButtonHtml({ buttonId: "rbt_manual", action: "mode-manual", label: "MANUAL", title: manualGate.operatorMessage || "Enter manual mode", className: "sidebar-button", active: state.machine.mode === "manual", gate: manualGate })}
|
||||
${iconButtonHtml({ buttonId: "tbtn_user_tabs", action: "mode-jog", label: "JOG", title: manualGate.operatorMessage || "Manual jog page", className: "sidebar-button", active: state.machine.mode === "manual", gate: manualGate })}
|
||||
${iconButtonHtml({ buttonId: "rbt_mdi", action: "mode-mdi", label: "MDI", title: mdiGate.operatorMessage || "Enter MDI mode", className: "sidebar-button", active: state.machine.mode === "mdi", gate: mdiGate })}
|
||||
<button type="button" class="sidebar-button" data-action="kins-identity" data-active="${state.kinsType === "identity"}">IDENTITY</button>
|
||||
<button type="button" class="sidebar-button" data-action="kins-tcp" data-active="${state.kinsType.startsWith("tcp-")}"${tcpDisabled}>TCP</button>
|
||||
<time>13:30:31<br />20.06.2026</time>
|
||||
|
||||
@@ -4779,3 +4779,167 @@ Outcome:
|
||||
- The gmoccapy XYZAB `working4` completion commit was uploaded to the cloud repository.
|
||||
- Remote `master` now points to `a81b40447de313117e2a389a394c3b8d80931001`.
|
||||
- A follow-up process-log commit is required because this log entry was created after the main upload commit.
|
||||
|
||||
---
|
||||
|
||||
## 2026-06-26 18:15 EDT - working5 LinuxCNC gmoccapy_XYZAB execution-flow alignment
|
||||
|
||||
User request:
|
||||
- Compare `/home/meswork/cnc_wams/web-rtcp-5axis-sim-plan` against the five-axis machine execution flow documented in `/home/meswork/cnc_wams/work/working3/gmoccapy_XYZAB_execution_analysis.md`.
|
||||
- Execute, test, and improve the LinuxCNC-ported CNC simulation so its simulation behavior matches the LinuxCNC source implementation.
|
||||
- First create working files in `/home/meswork/cnc_wams/work/working5`:
|
||||
- `01-项目功能内容`
|
||||
- `02-项目程序开发详细步骤`
|
||||
- `03-推进台账`
|
||||
- `04-任务矩阵`
|
||||
- `05-验收证据`
|
||||
- `06-决策记录`
|
||||
- plus README index.
|
||||
|
||||
Process:
|
||||
- Confirmed workspace and root instructions:
|
||||
- `/home/meswork/cnc_wams`
|
||||
- `AGENTS.md` requires appending process logs to `web-rtcp-5axis-sim-plan/gptlog-process/gpdlog.md`.
|
||||
- Read the LinuxCNC execution-flow reference:
|
||||
- `/home/meswork/cnc_wams/work/working3/gmoccapy_XYZAB_execution_analysis.md`
|
||||
- Key baseline: `gmoccapy_XYZAB.ini`, `trivkins coordinates=xyzab`, five joints, `NO_FORCE_HOMING = 0`, NML command/status/error, HAL loopbacks, POSTGUI after `halcomp.ready()`, and gmoccapy button sensitivity rules.
|
||||
- Inspected project structure and test inventory:
|
||||
- `app/src/runtime`
|
||||
- `app/src/state`
|
||||
- `app/src/ui`
|
||||
- `app/src/profiles`
|
||||
- `tests/node`
|
||||
- `tests/browser`
|
||||
- Created working5 control documents:
|
||||
- `/home/meswork/cnc_wams/work/working5/README.md`
|
||||
- `/home/meswork/cnc_wams/work/working5/01-项目功能内容.md`
|
||||
- `/home/meswork/cnc_wams/work/working5/02-项目程序开发详细步骤.md`
|
||||
- `/home/meswork/cnc_wams/work/working5/03-推进台账.md`
|
||||
- `/home/meswork/cnc_wams/work/working5/04-任务矩阵.md`
|
||||
- `/home/meswork/cnc_wams/work/working5/05-验收证据.md`
|
||||
- `/home/meswork/cnc_wams/work/working5/06-决策记录.md`
|
||||
- Ran initial baseline tests:
|
||||
- `cd /home/meswork/cnc_wams/web-rtcp-5axis-sim-plan/app && npm run smoke:node`
|
||||
- Result: passed.
|
||||
- Key output included:
|
||||
- `linuxcnc_kinematics_runtime_smoke=ok`
|
||||
- `linuxcnc_interpreter_runtime_smoke=ok`
|
||||
- `linuxcnc_ini_runtime_smoke=ok`
|
||||
- `linuxcnc_task_hal_runtime_smoke=ok`
|
||||
- `full_linuxcnc_5axis_source_node_smoke=ok`
|
||||
- `real_linuxcnc_5axis_program_cases_smoke=ok`
|
||||
- `gmoccapy_xyzab_profile_smoke=ok`
|
||||
- `gmoccapy_communication_model_smoke=ok`
|
||||
- `gmoccapy_hal_model_smoke=ok`
|
||||
- `gmoccapy_xyzab_gates_smoke=ok`
|
||||
- `linear_unit_conversion_smoke=ok`
|
||||
- `cd /home/meswork/cnc_wams/web-rtcp-5axis-sim-plan/app && npm run build`
|
||||
- Result: passed, output `gmoccapy_static_build=ok`.
|
||||
- `cd /home/meswork/cnc_wams/web-rtcp-5axis-sim-plan/app && npm run smoke`
|
||||
- Result: passed, output `gmoccapy_shell_smoke=ok` and `gmoccapy_dist_smoke=ok`.
|
||||
- Reviewed relevant implementation files:
|
||||
- `app/src/profiles/gmoccapy-xyzab.js`
|
||||
- `app/src/state/linuxcnc-task-policy.js`
|
||||
- `app/src/state/store.js`
|
||||
- `app/src/ui/gmoccapy-shell.js`
|
||||
- `app/src/runtime/gmoccapy-hal-model.js`
|
||||
- `app/src/runtime/gmoccapy-communication-model.js`
|
||||
- `tests/node/verify_gmoccapy_xyzab_gates.mjs`
|
||||
- `tests/node/verify_run_preconditions.mjs`
|
||||
- `tests/browser/gmoccapy_shell_smoke.html`
|
||||
- Compared against LinuxCNC/gmoccapy source:
|
||||
- `/home/meswork/cnc_wams/linuxcnc/src/emc/usr_intf/gmoccapy/gmoccapy.py`
|
||||
- Observed native behavior:
|
||||
- `on_hal_status_state_off()` disables `rbt_manual`, `rbt_mdi`, `rbt_auto`, and motion/execution controls.
|
||||
- `on_hal_status_state_on()` enables Manual and base machine controls.
|
||||
- With `NO_FORCE_HOMING = 0`, MDI/Auto remain unavailable until all axes are homed.
|
||||
- Setup-page exit logic restores:
|
||||
- estop/off: no mode buttons available
|
||||
- on but not homed: only Manual available
|
||||
- on and homed or no-force-homing: Manual/MDI/Auto available
|
||||
- Found a Web behavior gap:
|
||||
- Existing store/policy blocked `RUN` and `RUN_MDI` in invalid states.
|
||||
- But mode buttons could still be clicked earlier than gmoccapy allows.
|
||||
- Initial Web policy allowed mode changes that native gmoccapy would represent as insensitive buttons.
|
||||
- Implemented fixes:
|
||||
- In `app/src/state/linuxcnc-task-policy.js`:
|
||||
- Added `SET_MODE` gate requiring `taskState === "on"` for Manual/Jog/MDI/Auto.
|
||||
- Added homing gate for Auto/MDI when `NO_FORCE_HOMING = 0`.
|
||||
- Preserved Auto-running protection that blocks leaving Auto while interpreter is not idle.
|
||||
- In `app/src/ui/gmoccapy-shell.js`:
|
||||
- Bound Manual/Jog/Auto/MDI sidebar mode buttons to `gateLinuxCncTaskAction`.
|
||||
- Buttons now expose disabled state, `data-command-ready`, `aria-disabled`, and tooltip reason from the same task policy used by store dispatch.
|
||||
- In `tests/node/verify_gmoccapy_xyzab_gates.mjs`:
|
||||
- Added assertions that down/off state blocks Manual/MDI/Auto mode changes.
|
||||
- Added assertions that power-on but unhomed state allows Manual but blocks Auto/MDI.
|
||||
- Added assertions that after homing Auto mode is allowed.
|
||||
- In `tests/node/verify_run_preconditions.mjs`:
|
||||
- Updated expected behavior: trying Auto before homing leaves mode in Manual and run gate continues to say switch to Auto first.
|
||||
- In `tests/browser/gmoccapy_shell_smoke.html`:
|
||||
- Added DOM assertions for gmoccapy mode button sensitivity:
|
||||
- initially powered off: Manual/Jog/Auto/MDI disabled
|
||||
- powered on but unhomed: Manual/Jog enabled, Auto/MDI disabled with homing reason
|
||||
- homed: Auto/MDI enabled.
|
||||
- Ran targeted validation:
|
||||
- `cd /home/meswork/cnc_wams/web-rtcp-5axis-sim-plan/app && node ../tests/node/verify_gmoccapy_xyzab_gates.mjs && node ../tests/node/verify_run_preconditions.mjs && bash ../tests/browser/verify_gmoccapy_shell_browser.sh`
|
||||
- Result: passed.
|
||||
- Output:
|
||||
- `gmoccapy_xyzab_gates_smoke=ok`
|
||||
- `run_preconditions_ini_profile_smoke=ok`
|
||||
- `run_preconditions_kinematics_smoke=ok`
|
||||
- `run_preconditions_machine_file_smoke=ok`
|
||||
- `gmoccapy_shell_smoke=ok`
|
||||
- Ran final full regression:
|
||||
- `cd /home/meswork/cnc_wams/web-rtcp-5axis-sim-plan/app && npm run smoke:node`
|
||||
- Result: passed.
|
||||
- `cd /home/meswork/cnc_wams/web-rtcp-5axis-sim-plan/app && npm run build && npm run smoke`
|
||||
- Result: passed.
|
||||
- Output:
|
||||
- `gmoccapy_static_build=ok`
|
||||
- `gmoccapy_shell_smoke=ok`
|
||||
- `gmoccapy_dist_smoke=ok`
|
||||
- Ran quality checks:
|
||||
- `git diff --check` in `/home/meswork/cnc_wams/web-rtcp-5axis-sim-plan`
|
||||
- Result: passed.
|
||||
- `git diff --check` in `/home/meswork/cnc_wams`
|
||||
- Result: passed.
|
||||
- Updated working5 documentation:
|
||||
- `03-推进台账.md` now records R1 setup and R2 mode-interlock fix.
|
||||
- `04-任务矩阵.md` marks current pass complete for baseline profile/task/HAL/interpreter/UI verification.
|
||||
- `05-验收证据.md` records command evidence and outputs.
|
||||
- `06-决策记录.md` records why mode gating moved into `SET_MODE` and UI disabled state.
|
||||
- Started a local static server:
|
||||
- Command: `python3 -m http.server 4173`
|
||||
- Directory: `/home/meswork/cnc_wams/web-rtcp-5axis-sim-plan/app`
|
||||
- Confirmed with:
|
||||
- `curl -I --max-time 2 http://127.0.0.1:4173/`
|
||||
- HTTP 200 OK.
|
||||
- `ss -ltnp 'sport = :4173'`
|
||||
- Listener: `python3`, PID `24983`.
|
||||
|
||||
Files changed:
|
||||
- `/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/ui/gmoccapy-shell.js`
|
||||
- `/home/meswork/cnc_wams/web-rtcp-5axis-sim-plan/tests/browser/gmoccapy_shell_smoke.html`
|
||||
- `/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/node/verify_run_preconditions.mjs`
|
||||
- `/home/meswork/cnc_wams/work/working5/README.md`
|
||||
- `/home/meswork/cnc_wams/work/working5/01-项目功能内容.md`
|
||||
- `/home/meswork/cnc_wams/work/working5/02-项目程序开发详细步骤.md`
|
||||
- `/home/meswork/cnc_wams/work/working5/03-推进台账.md`
|
||||
- `/home/meswork/cnc_wams/work/working5/04-任务矩阵.md`
|
||||
- `/home/meswork/cnc_wams/work/working5/05-验收证据.md`
|
||||
- `/home/meswork/cnc_wams/work/working5/06-决策记录.md`
|
||||
- `/home/meswork/cnc_wams/web-rtcp-5axis-sim-plan/gptlog-process/gpdlog.md`
|
||||
|
||||
Git/worktree notes:
|
||||
- `git status --short --branch` from `/home/meswork/cnc_wams` shows modified Web simulation files and new `work/working5/`.
|
||||
- There is an unrelated untracked file already visible outside this task:
|
||||
- `备忘/备忘3.txt`
|
||||
- It was not modified.
|
||||
|
||||
Outcome:
|
||||
- Created the requested working5 documentation set and README index.
|
||||
- Executed and passed Node, build, browser, and targeted gmoccapy gate regressions.
|
||||
- Fixed a real LinuxCNC/gmoccapy behavior mismatch: mode buttons now follow native `STATE_OFF`, `STATE_ON`, homing, and interpreter-idle sensitivity semantics.
|
||||
- Local app server is available at `http://127.0.0.1:4173/`.
|
||||
|
||||
@@ -303,6 +303,38 @@
|
||||
if (!doc.querySelector('[data-machine-state="summary"]')?.textContent.includes("power off")) {
|
||||
throw new Error("initial machine state should show power off");
|
||||
}
|
||||
const initialModeManualButton = doc.querySelector('[data-action="mode-manual"]');
|
||||
const initialModeJogButton = doc.querySelector('[data-action="mode-jog"]');
|
||||
const initialModeAutoButton = doc.querySelector('[data-action="mode-auto"]');
|
||||
const initialModeMdiButton = doc.querySelector('[data-action="mode-mdi"]');
|
||||
if (
|
||||
!initialModeManualButton?.disabled ||
|
||||
initialModeManualButton.dataset.commandReady !== "false" ||
|
||||
initialModeManualButton.getAttribute("aria-disabled") !== "true"
|
||||
) {
|
||||
throw new Error("MANUAL mode button should be disabled before machine power on");
|
||||
}
|
||||
if (
|
||||
!initialModeJogButton?.disabled ||
|
||||
initialModeJogButton.dataset.commandReady !== "false" ||
|
||||
initialModeJogButton.getAttribute("aria-disabled") !== "true"
|
||||
) {
|
||||
throw new Error("JOG mode button should be disabled before machine power on");
|
||||
}
|
||||
if (
|
||||
!initialModeAutoButton?.disabled ||
|
||||
initialModeAutoButton.dataset.commandReady !== "false" ||
|
||||
initialModeAutoButton.getAttribute("aria-disabled") !== "true"
|
||||
) {
|
||||
throw new Error("AUTO mode button should be disabled before machine power on");
|
||||
}
|
||||
if (
|
||||
!initialModeMdiButton?.disabled ||
|
||||
initialModeMdiButton.dataset.commandReady !== "false" ||
|
||||
initialModeMdiButton.getAttribute("aria-disabled") !== "true"
|
||||
) {
|
||||
throw new Error("MDI mode button should be disabled before machine power on");
|
||||
}
|
||||
|
||||
const initiallyBlockedRunButton = doc.querySelector('[data-action="RUN"]');
|
||||
if (
|
||||
@@ -325,8 +357,44 @@
|
||||
if (!doc.querySelector('[data-machine-state="summary"]')?.textContent.includes("power on")) {
|
||||
throw new Error("machine state did not render power on");
|
||||
}
|
||||
const unhomedModeManualButton = doc.querySelector('[data-action="mode-manual"]');
|
||||
const unhomedModeJogButton = doc.querySelector('[data-action="mode-jog"]');
|
||||
const unhomedModeAutoButton = doc.querySelector('[data-action="mode-auto"]');
|
||||
const unhomedModeMdiButton = doc.querySelector('[data-action="mode-mdi"]');
|
||||
if (
|
||||
unhomedModeManualButton?.disabled ||
|
||||
unhomedModeManualButton.dataset.commandReady !== "true" ||
|
||||
unhomedModeJogButton?.disabled ||
|
||||
unhomedModeJogButton.dataset.commandReady !== "true"
|
||||
) {
|
||||
throw new Error("MANUAL and JOG mode buttons should be enabled after power on");
|
||||
}
|
||||
if (
|
||||
!unhomedModeAutoButton?.disabled ||
|
||||
unhomedModeAutoButton.dataset.commandReady !== "false" ||
|
||||
!unhomedModeAutoButton.title.includes("home machine before AUTO")
|
||||
) {
|
||||
throw new Error("AUTO mode button should remain disabled until homed");
|
||||
}
|
||||
if (
|
||||
!unhomedModeMdiButton?.disabled ||
|
||||
unhomedModeMdiButton.dataset.commandReady !== "false" ||
|
||||
!unhomedModeMdiButton.title.includes("home machine before MDI")
|
||||
) {
|
||||
throw new Error("MDI mode button should remain disabled until homed");
|
||||
}
|
||||
doc.querySelector('[data-action="HOME"]').click();
|
||||
await wait(50);
|
||||
const homedModeAutoButton = doc.querySelector('[data-action="mode-auto"]');
|
||||
const homedModeMdiButton = doc.querySelector('[data-action="mode-mdi"]');
|
||||
if (
|
||||
homedModeAutoButton?.disabled ||
|
||||
homedModeAutoButton.dataset.commandReady !== "true" ||
|
||||
homedModeMdiButton?.disabled ||
|
||||
homedModeMdiButton.dataset.commandReady !== "true"
|
||||
) {
|
||||
throw new Error("AUTO and MDI mode buttons should be enabled after homing");
|
||||
}
|
||||
doc.querySelector('[data-action="mode-auto"]').click();
|
||||
await wait(50);
|
||||
if (!doc.querySelector('[data-linuxcnc-task-policy="gates"]')?.textContent.includes("auto")) {
|
||||
|
||||
@@ -15,18 +15,41 @@ let gate = gateLinuxCncTaskAction(store.getState(), { type: "RUN" });
|
||||
assert.equal(gate.allowed, false);
|
||||
assert.equal(gate.operatorMessage, "run blocked: machine must be on");
|
||||
|
||||
gate = gateLinuxCncTaskAction(store.getState(), { type: "SET_MODE", mode: "manual" });
|
||||
assert.equal(gate.allowed, false);
|
||||
assert.equal(gate.operatorMessage, "mode blocked: machine must be on before MANUAL");
|
||||
gate = gateLinuxCncTaskAction(store.getState(), { type: "SET_MODE", mode: "mdi" });
|
||||
assert.equal(gate.allowed, false);
|
||||
assert.equal(gate.operatorMessage, "mode blocked: machine must be on before MDI");
|
||||
gate = gateLinuxCncTaskAction(store.getState(), { type: "SET_MODE", mode: "auto" });
|
||||
assert.equal(gate.allowed, false);
|
||||
assert.equal(gate.operatorMessage, "mode blocked: machine must be on before AUTO");
|
||||
|
||||
store.dispatch({ type: "TOGGLE_POWER" });
|
||||
gate = gateLinuxCncTaskAction(store.getState(), { type: "SET_MODE", mode: "manual" });
|
||||
assert.equal(gate.allowed, true);
|
||||
gate = gateLinuxCncTaskAction(store.getState(), { type: "RUN" });
|
||||
assert.equal(gate.allowed, false);
|
||||
assert.equal(gate.operatorMessage, "run blocked: switch to auto mode first");
|
||||
|
||||
gate = gateLinuxCncTaskAction(store.getState(), { type: "SET_MODE", mode: "auto" });
|
||||
assert.equal(gate.allowed, false);
|
||||
assert.equal(gate.operatorMessage, "mode blocked: home machine before AUTO");
|
||||
store.dispatch({ type: "SET_MODE", mode: "auto" });
|
||||
assert.equal(store.getState().machine.mode, "manual");
|
||||
assert.equal(store.getState().operatorMessage, "mode blocked: home machine before AUTO");
|
||||
gate = gateLinuxCncTaskAction(store.getState(), { type: "RUN" });
|
||||
assert.equal(gate.allowed, false);
|
||||
assert.equal(gate.operatorMessage, "run blocked: home machine first");
|
||||
assert.equal(gate.operatorMessage, "run blocked: switch to auto mode first");
|
||||
|
||||
gate = gateLinuxCncTaskAction(store.getState(), { type: "SET_MODE", mode: "mdi" });
|
||||
assert.equal(gate.allowed, false);
|
||||
assert.equal(gate.operatorMessage, "mode blocked: home machine before MDI");
|
||||
|
||||
store.dispatch({ type: "SET_MODE", mode: "manual" });
|
||||
store.dispatch({ type: "HOME" });
|
||||
gate = gateLinuxCncTaskAction(store.getState(), { type: "SET_MODE", mode: "auto" });
|
||||
assert.equal(gate.allowed, true);
|
||||
store.dispatch({ type: "SET_MODE", mode: "auto" });
|
||||
gate = gateLinuxCncTaskAction(store.getState(), { type: "RUN" });
|
||||
assert.equal(gate.allowed, false);
|
||||
|
||||
@@ -134,10 +134,14 @@ gate = gateLinuxCncTaskAction(store.getState(), { type: "RUN" });
|
||||
assert.equal(gate.allowed, false);
|
||||
assert.equal(gate.operatorMessage, "run blocked: switch to auto mode first");
|
||||
|
||||
gate = gateLinuxCncTaskAction(store.getState(), { type: "SET_MODE", mode: "auto" });
|
||||
assert.equal(gate.allowed, false);
|
||||
assert.equal(gate.operatorMessage, "mode blocked: home machine before AUTO");
|
||||
store.dispatch({ type: "SET_MODE", mode: "auto" });
|
||||
assert.equal(store.getState().machine.mode, "manual");
|
||||
gate = gateLinuxCncTaskAction(store.getState(), { type: "RUN" });
|
||||
assert.equal(gate.allowed, false);
|
||||
assert.equal(gate.operatorMessage, "run blocked: home machine first");
|
||||
assert.equal(gate.operatorMessage, "run blocked: switch to auto mode first");
|
||||
|
||||
store.dispatch({ type: "HOME" });
|
||||
store.dispatch({ type: "SET_MODE", mode: "manual" });
|
||||
|
||||
56
work/working5/01-项目功能内容.md
Normal file
56
work/working5/01-项目功能内容.md
Normal file
@@ -0,0 +1,56 @@
|
||||
# 01-项目功能内容
|
||||
|
||||
## 目标
|
||||
|
||||
以 LinuxCNC `gmoccapy_XYZAB.ini` 五轴仿真配置为行为基准,执行、测试并完善 `/home/meswork/cnc_wams/web-rtcp-5axis-sim-plan`。数控系统仿真功能应尽量与 LinuxCNC 源程序行为一致;发现不一致时,在 Web 项目中修复并补充验收证据。
|
||||
|
||||
## 对标范围
|
||||
|
||||
### 启动与配置
|
||||
|
||||
- INI 解析:`[DISPLAY]`、`[TASK]`、`[EMCMOT]`、`[TRAJ]`、`[KINS]`、`[HAL]`、`[RS274NGC]`、`[PYTHON]` 等关键段。
|
||||
- 启动顺序:`linuxcncsvr`、RTAPI/HAL、`milltask`、`halui`、HALFILE、`halcmd start`、`gmoccapy`、POSTGUI_HALFILE。
|
||||
- 五轴配置:`COORDINATES = X Y Z A B`、`JOINTS = 5`、`trivkins coordinates=xyzab`。
|
||||
|
||||
### 任务、状态与互锁
|
||||
|
||||
- NML 命令、状态、错误通道的 Web 等效模型。
|
||||
- `STATE_ESTOP`、`STATE_ESTOP_RESET`、`STATE_OFF`、`STATE_ON`。
|
||||
- `MODE_MANUAL`、`MODE_MDI`、`MODE_AUTO`。
|
||||
- `INTERP_IDLE`、运行、暂停、停止、abort。
|
||||
- `NO_FORCE_HOMING = 0` 下的全轴回零互锁。
|
||||
- 自动运行、MDI、点动、回零、主轴、冷却、倍率、限位、换刀互锁。
|
||||
|
||||
### HAL 与仿真 IO
|
||||
|
||||
- `core_sim_XYZAB.hal`:motmod、五轴位置反馈回环、急停回环、换刀回环、主轴/冷却信号。
|
||||
- `spindle_sim.hal`:速度斜坡、编码器反馈、`spindle.0.at-speed`。
|
||||
- `simulated_home.hal`:X/Y/Z 回零开关模拟。
|
||||
- `gmoccapy_postgui.hal`:GUI HAL pins、主轴反馈条、到速 LED、刀补显示、换刀回环。
|
||||
- `HALUI = halui` 默认入口。
|
||||
|
||||
### G-code 解释与五轴运动
|
||||
|
||||
- RS274NGC 解释器行为。
|
||||
- MDI 命令发送与状态回读。
|
||||
- 自动运行文件、暂停、继续、单步、停止、从行运行。
|
||||
- `M6`、`M61` REMAP 相关换刀语义。
|
||||
- 五轴轨迹、单位换算、RTCP/运动学边界。
|
||||
|
||||
### gmoccapy 界面等效行为
|
||||
|
||||
- 周期轮询:`[DISPLAY] CYCLE_TIME = 100` ms。
|
||||
- 按钮/页面敏感状态互锁。
|
||||
- DRO、程序进度、主轴反馈、冷却液、工具/刀补、错误消息。
|
||||
- 外部 HAL 硬按钮和点动 pin 驱动 GUI 后再通过命令通道进入任务层。
|
||||
|
||||
## 当前项目入口
|
||||
|
||||
- Web 应用:`/home/meswork/cnc_wams/web-rtcp-5axis-sim-plan/app`
|
||||
- 核心运行时:`app/src/runtime`
|
||||
- gmoccapy UI:`app/src/ui`
|
||||
- 状态存储:`app/src/state`
|
||||
- 机床配置/profile:`app/src/profiles`
|
||||
- Node 验证:`tests/node`
|
||||
- 浏览器验证:`tests/browser`
|
||||
|
||||
48
work/working5/02-项目程序开发详细步骤.md
Normal file
48
work/working5/02-项目程序开发详细步骤.md
Normal file
@@ -0,0 +1,48 @@
|
||||
# 02-项目程序开发详细步骤
|
||||
|
||||
## 步骤 1:建立工作控制文件
|
||||
|
||||
- 创建 README、功能内容、开发步骤、推进台账、任务矩阵、验收证据、决策记录。
|
||||
- 把任务按 LinuxCNC 执行流程拆分为可验收条目。
|
||||
|
||||
## 步骤 2:读取基准与现有实现
|
||||
|
||||
- 读取 `work/working3/gmoccapy_XYZAB_execution_analysis.md`。
|
||||
- 读取 Web 项目 runtime、state、profile、ui 和测试文件。
|
||||
- 将 LinuxCNC 执行链路映射到 Web 项目模块。
|
||||
|
||||
## 步骤 3:执行现有测试
|
||||
|
||||
- 在 `app` 下运行 `npm run smoke:node`。
|
||||
- 运行构建:`npm run build`。
|
||||
- 运行浏览器冒烟:`npm run smoke`。
|
||||
- 如有失败,先定位是否为环境、测试夹具或功能差异。
|
||||
|
||||
## 步骤 4:差异分析
|
||||
|
||||
按任务矩阵逐项检查:
|
||||
|
||||
- INI/HAL/profile 是否覆盖 `gmoccapy_XYZAB.ini` 的五轴语义。
|
||||
- task/HAL runtime 是否覆盖状态机、互锁、回零、运行、暂停、停止、换刀、主轴、冷却、倍率。
|
||||
- interpreter/kinematics/session 是否覆盖 LinuxCNC 解释和五轴运行边界。
|
||||
- UI 是否按 gmoccapy 规则启停按钮并显示状态。
|
||||
|
||||
## 步骤 5:修改实现
|
||||
|
||||
- 优先修复已有测试暴露的问题。
|
||||
- 对未覆盖但属于 LinuxCNC 基准行为的差异,补测试后修实现。
|
||||
- 修改范围保持在对应 runtime/state/ui/profile/tests 文件内,避免无关重构。
|
||||
|
||||
## 步骤 6:回归验收
|
||||
|
||||
- 重新运行相关最小测试。
|
||||
- 运行完整 Node 冒烟测试。
|
||||
- 对 UI/浏览器改动运行构建与浏览器冒烟。
|
||||
- 把命令、结果、证据路径写入 `05-验收证据.md`。
|
||||
|
||||
## 步骤 7:更新台账和任务矩阵
|
||||
|
||||
- 更新已完成任务状态。
|
||||
- 写清本轮修改文件、验证命令和下一步。
|
||||
- 对重要取舍写入 `06-决策记录.md`。
|
||||
|
||||
59
work/working5/03-推进台账.md
Normal file
59
work/working5/03-推进台账.md
Normal file
@@ -0,0 +1,59 @@
|
||||
# 03-推进台账
|
||||
|
||||
## 2026-06-26 R1:启动 working5 对标推进
|
||||
|
||||
做了什么:
|
||||
|
||||
- 创建 working5 工作文件结构。
|
||||
- 建立与 `gmoccapy_XYZAB.ini` 执行流程对齐的任务矩阵和验收记录模板。
|
||||
- 开始读取 LinuxCNC 执行分析和 Web 项目结构。
|
||||
|
||||
改了哪些文件:
|
||||
|
||||
- `/home/meswork/cnc_wams/work/working5/README.md`
|
||||
- `/home/meswork/cnc_wams/work/working5/01-项目功能内容.md`
|
||||
- `/home/meswork/cnc_wams/work/working5/02-项目程序开发详细步骤.md`
|
||||
- `/home/meswork/cnc_wams/work/working5/03-推进台账.md`
|
||||
- `/home/meswork/cnc_wams/work/working5/04-任务矩阵.md`
|
||||
- `/home/meswork/cnc_wams/work/working5/05-验收证据.md`
|
||||
- `/home/meswork/cnc_wams/work/working5/06-决策记录.md`
|
||||
|
||||
验证了什么:
|
||||
|
||||
- 待执行现有 Node、构建和浏览器冒烟测试。
|
||||
|
||||
下一步是什么:
|
||||
|
||||
- 执行 `npm run smoke:node`,根据失败项定位 LinuxCNC 行为差异。
|
||||
|
||||
## 2026-06-26 R2:基线验证与 gmoccapy 模式互锁修复
|
||||
|
||||
做了什么:
|
||||
|
||||
- 执行现有 Node、构建、浏览器冒烟测试,确认项目基线可运行。
|
||||
- 对照 `gmoccapy_XYZAB_execution_analysis.md` 和 `gmoccapy.py` 的 `STATE_OFF`、`STATE_ON`、`all_homed` 逻辑,发现 Web 侧允许提前点击 Manual/MDI/Auto 模式按钮,store 虽能拦截部分运行动作,但 UI 敏感状态不完全等同 gmoccapy。
|
||||
- 修改 task policy:`SET_MODE` 在机床未上电时禁止 Manual/MDI/Auto/Jog;机床上电但未回零时只允许 Manual/Jog,禁止 MDI/Auto;Auto 运行中仍禁止离开 Auto。
|
||||
- 修改 gmoccapy Web shell:右侧 Manual/Jog/Auto/MDI 模式按钮统一使用 `gateLinuxCncTaskAction`,以 `disabled`、`data-command-ready`、`aria-disabled` 和 title 展示互锁原因。
|
||||
- 补充 Node 和浏览器测试,锁定下电、上电未回零、回零后三个阶段的模式按钮行为。
|
||||
|
||||
改了哪些文件:
|
||||
|
||||
- `/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/ui/gmoccapy-shell.js`
|
||||
- `/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/node/verify_run_preconditions.mjs`
|
||||
- `/home/meswork/cnc_wams/web-rtcp-5axis-sim-plan/tests/browser/gmoccapy_shell_smoke.html`
|
||||
- `/home/meswork/cnc_wams/work/working5/03-推进台账.md`
|
||||
- `/home/meswork/cnc_wams/work/working5/04-任务矩阵.md`
|
||||
- `/home/meswork/cnc_wams/work/working5/05-验收证据.md`
|
||||
- `/home/meswork/cnc_wams/work/working5/06-决策记录.md`
|
||||
|
||||
验证了什么:
|
||||
|
||||
- `node ../tests/node/verify_gmoccapy_xyzab_gates.mjs && node ../tests/node/verify_run_preconditions.mjs && bash ../tests/browser/verify_gmoccapy_shell_browser.sh` 通过。
|
||||
- `npm run smoke:node` 通过。
|
||||
- `npm run build && npm run smoke` 通过。
|
||||
|
||||
下一步是什么:
|
||||
|
||||
- 下一轮可继续按任务矩阵深入核对 Tool/M6/M61 手动换刀对话框、限位 override、optional stop/block delete HAL pin 交叉行为等更细粒度 gmoccapy 行为。
|
||||
16
work/working5/04-任务矩阵.md
Normal file
16
work/working5/04-任务矩阵.md
Normal file
@@ -0,0 +1,16 @@
|
||||
# 04-任务矩阵
|
||||
|
||||
| 任务编号 | 任务 | 状态 | 验收标准 |
|
||||
| --- | --- | --- | --- |
|
||||
| W5-001 | 创建 working5 工作控制文件 | 完成 | README 和 01-06 文件存在,内容可指导后续推进 |
|
||||
| W5-010 | 建立 LinuxCNC 执行流程到 Web 模块映射 | 完成 | 已映射到 profile、task policy、HAL model、communication model、interpreter/runtime、UI shell 和 tests |
|
||||
| W5-020 | 执行现有 Node 冒烟测试 | 完成 | `npm run smoke:node` 通过 |
|
||||
| W5-030 | 执行构建测试 | 完成 | `npm run build` 通过 |
|
||||
| W5-040 | 执行浏览器冒烟测试 | 完成 | `npm run smoke` 通过 |
|
||||
| W5-100 | 校验 gmoccapy XYZAB profile | 完成 | `verify_gmoccapy_xyzab_profile.mjs`、完整 Node 冒烟通过 |
|
||||
| W5-110 | 校验 task 状态机和互锁 | 完成 | 修复并验证 Manual/MDI/Auto/Jog 模式按钮在下电、未回零、已回零状态下与 gmoccapy 一致 |
|
||||
| W5-120 | 校验 HAL runtime | 完成 | `verify_gmoccapy_hal_model.mjs`、`verify_linuxcnc_task_hal_runtime.mjs`、完整 Node 冒烟通过 |
|
||||
| W5-130 | 校验 G-code interpreter/runtime | 完成 | 自动运行、MDI、暂停/继续/停止、M6/M61 引用边界测试随完整 Node 冒烟通过 |
|
||||
| W5-140 | 校验五轴运动和单位换算 | 完成 | kinematics、real LinuxCNC 5-axis cases、linear unit conversion 测试随完整 Node 冒烟通过 |
|
||||
| W5-150 | 校验 gmoccapy UI 通信和按钮门控 | 完成 | 浏览器 smoke 验证 mode gate、NML/HAL 诊断、POSTGUI 顺序、按钮状态 |
|
||||
| W5-900 | 更新验收证据和决策记录 | 完成 | 命令、结果、修改原因和后续项已记录 |
|
||||
69
work/working5/05-验收证据.md
Normal file
69
work/working5/05-验收证据.md
Normal file
@@ -0,0 +1,69 @@
|
||||
# 05-验收证据
|
||||
|
||||
## 证据索引
|
||||
|
||||
| 证据编号 | 任务编号 | 类型 | 命令/页面/文件 | 结果 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| EV-W5-001 | W5-001 | 文件 | `/home/meswork/cnc_wams/work/working5` | 已创建 README 和 01-06 工作控制文件 |
|
||||
| EV-W5-020 | W5-020/W5-100/W5-110/W5-120/W5-130/W5-140 | 命令 | `cd /home/meswork/cnc_wams/web-rtcp-5axis-sim-plan/app && npm run smoke:node` | 通过,输出包含 `gmoccapy_xyzab_gates_smoke=ok`、`gmoccapy_hal_model_smoke=ok`、`real_linuxcnc_5axis_program_cases_smoke=ok`、`linear_unit_conversion_smoke=ok` |
|
||||
| EV-W5-030 | W5-030 | 命令 | `cd /home/meswork/cnc_wams/web-rtcp-5axis-sim-plan/app && npm run build` | 通过,输出 `gmoccapy_static_build=ok` |
|
||||
| EV-W5-040 | W5-040/W5-150 | 命令 | `cd /home/meswork/cnc_wams/web-rtcp-5axis-sim-plan/app && npm run smoke` | 通过,输出 `gmoccapy_shell_smoke=ok`、`gmoccapy_dist_smoke=ok` |
|
||||
| EV-W5-110 | W5-110/W5-150 | 命令 | `node ../tests/node/verify_gmoccapy_xyzab_gates.mjs && node ../tests/node/verify_run_preconditions.mjs && bash ../tests/browser/verify_gmoccapy_shell_browser.sh` | 通过,验证下电禁用 Manual/Jog/MDI/Auto,上电未回零只允许 Manual/Jog,回零后允许 Auto/MDI |
|
||||
|
||||
## 命令记录
|
||||
|
||||
### 2026-06-26 R2
|
||||
|
||||
```bash
|
||||
cd /home/meswork/cnc_wams/web-rtcp-5axis-sim-plan/app
|
||||
npm run smoke:node
|
||||
```
|
||||
|
||||
结果:通过。
|
||||
|
||||
关键输出摘要:
|
||||
|
||||
- `linuxcnc_kinematics_runtime_smoke=ok`
|
||||
- `linuxcnc_interpreter_runtime_smoke=ok`
|
||||
- `linuxcnc_task_hal_runtime_smoke=ok`
|
||||
- `full_linuxcnc_5axis_source_node_smoke=ok`
|
||||
- `real_linuxcnc_5axis_program_cases_smoke=ok`
|
||||
- `gmoccapy_xyzab_profile_smoke=ok`
|
||||
- `gmoccapy_communication_model_smoke=ok`
|
||||
- `gmoccapy_hal_model_smoke=ok`
|
||||
- `gmoccapy_xyzab_gates_smoke=ok`
|
||||
- `linear_unit_conversion_smoke=ok`
|
||||
|
||||
```bash
|
||||
cd /home/meswork/cnc_wams/web-rtcp-5axis-sim-plan/app
|
||||
npm run build
|
||||
```
|
||||
|
||||
结果:通过,输出 `gmoccapy_static_build=ok`。
|
||||
|
||||
```bash
|
||||
cd /home/meswork/cnc_wams/web-rtcp-5axis-sim-plan/app
|
||||
npm run smoke
|
||||
```
|
||||
|
||||
结果:通过,输出:
|
||||
|
||||
- `gmoccapy_shell_smoke=ok`
|
||||
- `gmoccapy_dist_smoke=ok`
|
||||
|
||||
```bash
|
||||
cd /home/meswork/cnc_wams/web-rtcp-5axis-sim-plan/app
|
||||
node ../tests/node/verify_gmoccapy_xyzab_gates.mjs && node ../tests/node/verify_run_preconditions.mjs && bash ../tests/browser/verify_gmoccapy_shell_browser.sh
|
||||
```
|
||||
|
||||
结果:通过,输出:
|
||||
|
||||
- `gmoccapy_xyzab_gates_smoke=ok`
|
||||
- `run_preconditions_ini_profile_smoke=ok`
|
||||
- `run_preconditions_kinematics_smoke=ok`
|
||||
- `run_preconditions_machine_file_smoke=ok`
|
||||
- `gmoccapy_shell_smoke=ok`
|
||||
|
||||
## 页面/截图/report/job 记录
|
||||
|
||||
本轮未生成截图、PDF、job_id 或 report_id。浏览器验收由 headless Chromium smoke 脚本完成。
|
||||
42
work/working5/06-决策记录.md
Normal file
42
work/working5/06-决策记录.md
Normal file
@@ -0,0 +1,42 @@
|
||||
# 06-决策记录
|
||||
|
||||
## DR-W5-001:以 gmoccapy_XYZAB 执行流程作为本轮验收主线
|
||||
|
||||
日期:2026-06-26
|
||||
|
||||
决策:
|
||||
|
||||
- 本轮不只验证图形 RTCP 轨迹,而是按 LinuxCNC 启动、INI/HAL、task/NML、interpreter、gmoccapy UI 通信和互锁全链路推进。
|
||||
|
||||
原因:
|
||||
|
||||
- 用户指定的基准文件覆盖了 `gmoccapy_XYZAB.ini` 五轴仿真从启动到界面通信的完整执行流程。
|
||||
- 若只看轨迹显示,容易遗漏回零、状态机、换刀、主轴到速、冷却、UI gate 等数控系统仿真关键行为。
|
||||
|
||||
影响:
|
||||
|
||||
- 任务矩阵按 LinuxCNC 行为拆分。
|
||||
- 任何实现修改都需要补充对应测试或验收证据。
|
||||
|
||||
## DR-W5-002:模式按钮门控前移到 `SET_MODE` 和 UI disabled 状态
|
||||
|
||||
日期:2026-06-26
|
||||
|
||||
决策:
|
||||
|
||||
- Web 侧 `SET_MODE` 统一按 LinuxCNC/gmoccapy 状态门控。
|
||||
- `STATE_OFF` 或未上电时,Manual/Jog/MDI/Auto 都禁止切换。
|
||||
- `STATE_ON` 但未全轴回零且 `NO_FORCE_HOMING = 0` 时,只允许 Manual/Jog,禁止 MDI/Auto。
|
||||
- 回零后 MDI/Auto 恢复可用;Auto 解释器非 idle 时仍禁止离开 Auto。
|
||||
|
||||
原因:
|
||||
|
||||
- LinuxCNC `gmoccapy.py` 的 `on_hal_status_state_off()` 会禁用 `rbt_manual`、`rbt_mdi`、`rbt_auto`。
|
||||
- `on_hal_status_state_on()` 先只启用 `rbt_manual`,退出设置页时也明确区分“未回零只 Manual 可用”和“已回零三种模式可用”。
|
||||
- 旧 Web 实现主要在 `RUN` 和 `RUN_MDI` 时拦截,模式按钮本身仍可点击,不符合 gmoccapy 的按钮敏感状态。
|
||||
|
||||
影响:
|
||||
|
||||
- `app/src/state/linuxcnc-task-policy.js` 成为模式切换和执行动作的统一互锁入口。
|
||||
- `app/src/ui/gmoccapy-shell.js` 侧边模式按钮使用同一 gate 输出 disabled、`data-command-ready` 和 `aria-disabled`。
|
||||
- Node 和浏览器测试增加下电、未回零、已回零三个阶段的断言。
|
||||
27
work/working5/README.md
Normal file
27
work/working5/README.md
Normal file
@@ -0,0 +1,27 @@
|
||||
# working5 README 索引
|
||||
|
||||
本目录用于推进 `/home/meswork/cnc_wams/web-rtcp-5axis-sim-plan` 与 LinuxCNC `gmoccapy_XYZAB.ini` 五轴仿真执行流程的一致性验证、修复和验收。
|
||||
|
||||
对标基准:
|
||||
|
||||
- `/home/meswork/cnc_wams/work/working3/gmoccapy_XYZAB_execution_analysis.md`
|
||||
- `/home/meswork/cnc_wams/linuxcnc/configs/sim/gmoccapy/gmoccapy_XYZAB.ini`
|
||||
- `/home/meswork/cnc_wams/linuxcnc/src/emc/usr_intf/gmoccapy/`
|
||||
- `/home/meswork/cnc_wams/linuxcnc/configs/sim/gmoccapy/*.hal`
|
||||
|
||||
工作文件:
|
||||
|
||||
1. [01-项目功能内容.md](01-项目功能内容.md)
|
||||
2. [02-项目程序开发详细步骤.md](02-项目程序开发详细步骤.md)
|
||||
3. [03-推进台账.md](03-推进台账.md)
|
||||
4. [04-任务矩阵.md](04-任务矩阵.md)
|
||||
5. [05-验收证据.md](05-验收证据.md)
|
||||
6. [06-决策记录.md](06-决策记录.md)
|
||||
|
||||
推进规则:
|
||||
|
||||
- 先按 `04-任务矩阵.md` 选择任务,避免重复做同一项。
|
||||
- 每轮结束更新 `03-推进台账.md`,记录做了什么、改了哪些文件、验证了什么、下一步是什么。
|
||||
- 所有命令、页面、报告、截图、测试输出摘要写入 `05-验收证据.md`。
|
||||
- 影响架构、兼容性或验收口径的判断写入 `06-决策记录.md`。
|
||||
|
||||
Reference in New Issue
Block a user