# 02-项目程序开发详细步骤 ## 开发原则 1. 以 LinuxCNC 源码语义为准:`axis -> emcmodule.cc -> emctaskmain.cc -> taskintf.cc -> motion`。 2. Run 按钮只发送命令并渲染状态,不直接把 Web 状态改成 running。 3. WASM wrapper 可以适配 ABI,但不能发明第二套 CNC task 状态机。 4. 每一步都要有 Node WASM 测试、Web Node 测试或浏览器 trace 证据。 5. 每轮结束必须更新推进台账、任务矩阵和验收证据。 ## 步骤 1:建立 Run 状态门禁表 目标文件: - `wasm-port/runtime/core/linuxcnc_wrap/linuxcnc_task_hal_wasm.cpp` - `wasm-port/tests/wasm/node/verify_task_state_matrix.mjs` - `web-rtcp-5axis-xyzbc-trt-sim-plan/app/src/state/linuxcnc-task-policy.js` 开发动作: 1. 固化 LinuxCNC 风格枚举: - task state:`ESTOP`、`ESTOP_RESET`、`ON` - task mode:`MANUAL`、`AUTO`、`MDI` - interp state:`IDLE`、`READING`、`PAUSED`、`WAITING` 2. 增加 `task_accepts_command(state, mode, interp, command)` 或等价函数。 3. 对 `EMC_TASK_PLAN_RUN` 实现硬门禁: - 必须 `state=ON` - 必须 `mode=AUTO` - 必须 `interpState=IDLE` - 必须 homed 或 `no_force_homing` - 必须有已打开程序或可用 canonical plan 4. Web policy 使用同一组条件做按钮 enable/disable,但最终以 WASM 返回为准。 验收: - ESTOP 下 Run 返回拒绝。 - ESTOP_RESET 下 Run 返回拒绝。 - ON/MANUAL 下 Run 需要先切 AUTO。 - ON/AUTO/IDLE 且未 homed 时 Run 返回未回零错误。 - ON/AUTO/IDLE 且 homed、有程序时 Run 被接受。 ## 步骤 2:补齐程序 open 与 canonical plan 边界 目标文件: - `wasm-port/runtime/core/linuxcnc_wrap/linuxcnc_task_hal_wasm.cpp` - `wasm-port/runtime/sdk/src/linuxcnc-task-hal.js` - `web-rtcp-5axis-xyzbc-trt-sim-plan/app/src/runtime/linuxcnc-task-hal-runtime.js` - `web-rtcp-5axis-xyzbc-trt-sim-plan/app/src/state/store.js` 开发动作: 1. 明确 task/HAL session 的程序来源: - 当前 G-code 文件路径或虚拟文件名。 - LinuxCNC interpreter canonical events。 - motion plan id/version。 2. 移除或隔离从 G-code 文本正则派生 motion 的 fallback。 3. 无 canonical plan 时,Run 返回明确错误,例如 `INTERPRETER_PLAN_REQUIRED`。 4. status JSON 输出: - `task.file` - `task.programOpen` - `task.programStartLine` - `task.planId` - `task.errorText` 验收: - 未 open 程序时 Run 不进入 running。 - 有 canonical plan 时 Run 记录 `programStartLine`。 - Web 能显示或记录拒绝原因,store 不伪造 running。 ## 步骤 3:实现 Run 命令后的 task 状态变化 目标文件: - `wasm-port/runtime/core/linuxcnc_wrap/linuxcnc_task_hal_wasm.cpp` - `wasm-port/runtime/core/linuxcnc_wrap/linuxcnc_motion_runtime.c` - `wasm-port/tests/wasm/node/verify_task_hal_wasm.mjs` 开发动作: 1. `EMC_TASK_PLAN_RUN` 分支对齐 LinuxCNC: - 清 `taskPaused` - 清 `singleStepping` - 清 step 相关等待状态 - 设置 `programStartLine` - 设置 `interpState=READING` - 设置 `execState=EXEC` 或等价执行态 2. 把 canonical motion events 下发到 motion runtime 队列。 3. motion runtime 输出: - `queueDepth` - `activeDepth` - `motion.id` - `motion.programLine` - `motion.currentVel` 4. 执行完成后 task 状态回到: - `interpState=IDLE` - `execState=DONE` - `taskPaused=false` 验收: - Run 后读 status 可见 `READING` 或执行中的 `WAITING`。 - motion queue 开始消费。 - current line 或 motion id 单调推进。 - 完成后进入 done/idle。 ## 步骤 4:Web store 改为 task/HAL status 投影 目标文件: - `web-rtcp-5axis-xyzbc-trt-sim-plan/app/src/state/store.js` - `web-rtcp-5axis-xyzbc-trt-sim-plan/app/src/runtime/linuxcnc-task-hal-runtime.js` - `web-rtcp-5axis-xyzbc-trt-sim-plan/tests/node/verify_run_feedback_loop.mjs` 开发动作: 1. 点击 Run 后只做: - policy 检查 - `taskHalRuntime.sendCommand(MODE_AUTO)` - `taskHalRuntime.sendCommand(EMC_TASK_PLAN_RUN)` - `runCycles/readStatus` 2. `runState` 映射规则: - `interpState=READING/WAITING` 且未 paused -> `running` - `interpState=PAUSED` 或 `motion.paused=true` -> `paused` - `interpState=IDLE` 且 exec done -> `idle/done` - 有 error -> `error` 3. 删除或隔离点击 Run 后直接写 `running` 的分支。 4. 当前行、DRO、TCP、RTCP 显示优先使用 task/HAL status 和 kinematics runtime 的结果。 验收: - WASM 拒绝 Run 时 Web 不进入 running。 - WASM 接受 Run 后 Web 才进入 running。 - status loop 中断或错误时 UI 进入明确错误态,不保持假 running。 ## 步骤 5:Home 过程态补齐为 Run 前置条件 目标文件: - `wasm-port/runtime/core/linuxcnc_wrap/linuxcnc_task_hal_wasm.cpp` - `wasm-port/runtime/core/linuxcnc_wrap/linuxcnc_motion_runtime.c` - `web-rtcp-5axis-xyzbc-trt-sim-plan/app/src/state/store.js` - `web-rtcp-5axis-xyzbc-trt-sim-plan/tests/node/verify_run_feedback_loop.mjs` 开发动作: 1. joint status 增加: - `homing` - `homed` - `homeState` 2. Home All 后不要立即只写 `allHomed=true`,应经历至少一个可观测过程态。 3. Run 前使用 `allHomed || noForceHoming`。 4. OFF/ESTOP 时按当前模型清理 volatile home;如果暂不能区分 volatile,必须在 status 和决策记录中标注简化。 验收: - 未 homed Run 被拒绝。 - Home 过程中 Run 被拒绝。 - Home 完成后 Run 可进入执行。 ## 步骤 6:执行过程 Pause/Resume/Step 回归 目标文件: - `wasm-port/tests/wasm/node/verify_task_hal_wasm.mjs` - `web-rtcp-5axis-xyzbc-trt-sim-plan/tests/node/verify_run_feedback_loop.mjs` - `web-rtcp-5axis-xyzbc-trt-sim-plan/tools/trace-pause-position-json.mjs` - `web-rtcp-5axis-xyzbc-trt-sim-plan/tools/verify-estop-power-home-run-pause-50ms.mjs` 开发动作: 1. 在 Run 成功后执行 Pause,断言: - `task.interpState=PAUSED` - `task.taskPaused=true` - `motion.paused=true` 2. Resume 后断言: - 恢复 `interpResumeState` - `taskPaused=false` - `motion.paused=false` 3. Step 后断言: - `singleStepping=true` 或 step 过程字段可观测 - 只推进一个 motion id/程序行 - 回到 paused 验收: - working8 已有暂停证据继续通过。 - working9 新增 Run 前置、Run 后执行推进、Run 中暂停/恢复/单步证据。 ## 步骤 7:构建与回归命令 WASM 推荐命令: ```bash cd /home/mes123456/cnc_wams/wasm-port ./tools/build_task_hal_wasm.sh node tests/wasm/node/verify_task_hal_wasm.mjs node tests/wasm/node/verify_task_state_matrix.mjs ``` Web 推荐命令: ```bash cd /home/mes123456/cnc_wams/web-rtcp-5axis-xyzbc-trt-sim-plan npm --prefix app run build node tests/node/verify_run_feedback_loop.mjs APP_URL_PATH=/web-rtcp-5axis-xyzbc-trt-sim-plan/app/dist/index.html node tools/trace-pause-position-json.mjs RUN_STABLE_BEFORE_FIRST_PAUSE_MS=3000 node tools/verify-estop-power-home-run-pause-50ms.mjs ``` 预期证据关键词: - `linuxcnc_task_runtime_smoke=ok` - `task_state_matrix=ok` - `run_feedback_status_loop_smoke=ok` - `pause_position_status=passed-position-frozen` - `verification_status=passed` ## 步骤 8:记录与关闭 每完成一个编号任务: 1. 更新 `03-推进台账.md`。 2. 更新 `04-任务矩阵.md` 状态。 3. 把命令、输出摘要、trace 路径、截图目录写入 `05-验收证据.md`。 4. 如果改变技术方向,追加 `06-决策记录.md`。