chore: close wasm status contract work

This commit is contained in:
wangdequan
2026-07-08 09:20:47 -04:00
parent 97732ceb0b
commit e69333972c
69 changed files with 20435 additions and 495 deletions

View File

@@ -0,0 +1,122 @@
# 01-项目功能内容
## 项目目标
`wasm-port` 的 task/motion/HAL 运行时从当前 minimal adapter 推进到尽可能贴近 LinuxCNC 原生 `emctaskmain.cc` 的 task 主循环结构。
核心要求:
- 每个 task 周期都建立 LinuxCNC 式 motion 状态快照。
- task 状态机使用该 motion 快照驱动等待、错误、estop、abort、queueFull、in-position、program line 等行为。
- 周期顺序对标上游 `emctaskmain.cc`command read -> plan -> execute -> motion update -> subordinate sync -> task update -> status write。
- 当前 JSON 自有状态机逐步收缩为 host/runtime 边界CNC/task 语义优先来自 LinuxCNC 源码。
- 后续 WASM 程序定位为核心状态机实现的运行载体task/motion 状态机、周期调度、状态聚合、命令执行位于 C/C++ WASM 侧JS/SDK 和 JSON 只承担外部边界职责。
## 对标源
主要对标文件:
- `/home/mes123456/cnc_wams/linuxcnc/src/emc/task/emctaskmain.cc`
- `/home/mes123456/cnc_wams/linuxcnc/src/emc/task/emctask.cc`
- `/home/mes123456/cnc_wams/linuxcnc/src/emc/task/taskintf.cc`
- `/home/mes123456/cnc_wams/linuxcnc/src/emc/task/emccanon.cc`
- `/home/mes123456/cnc_wams/linuxcnc/src/emc/task/task.hh`
- `/home/mes123456/cnc_wams/linuxcnc/src/emc/nml_intf/emc.hh`
- `/home/mes123456/cnc_wams/linuxcnc/src/emc/nml_intf/emc_nml.hh`
- `/home/mes123456/cnc_wams/linuxcnc/src/emc/motion/usrmotintf.h`
- `/home/mes123456/cnc_wams/linuxcnc/src/emc/motion/motion.h`
当前 WASM 侧入口:
- `/home/mes123456/cnc_wams/wasm-port/runtime/core/linuxcnc_wrap/linuxcnc_task_hal_wasm.cpp`
- `/home/mes123456/cnc_wams/wasm-port/runtime/core/linuxcnc_wrap/linuxcnc_motion_runtime.c`
- `/home/mes123456/cnc_wams/wasm-port/runtime/sdk/src/linuxcnc-task-hal.js`
## 当前闭合状态
当前 `wasm-port` 已有:
- `lctask_*` C ABI。
- `lcmot_*` minimal motion runtime。
- HAL pin/snapshot runtime。
- Node WASM task/motion/HAL smoke。
- LinuxCNC 式 task 周期骨架command read -> plan -> execute -> motion update -> subordinate sync -> task update -> status write。
- 周期内 `LcmotStatusSnapshot``StandaloneEmcStatus.motion` 的映射。
- `StandaloneEmcStatus` 作为当前阶段 `EMC_STAT` 等价容器,集中导出 task/motion/io/top status。
- RUN 文件主路径通过 staged program plan read/command/execute、`emccanon.cc` command envelope 和 `taskintf.cc` motion issue 工作,不依赖 host JSON motion plan。
- task 状态、模式、pause/resume/step/home/run gate、wait-for-motion、queueFull、motion error、soft-limit、IO error、RCS 聚合和 no-JSON RUN path 的 WASM/SDK/state-matrix 覆盖。
当前保守边界:
- 当前 shim `runtime/core/shims/nml_intf/emc.hh` 只暴露 `motion.traj.linearUnits`,远小于上游 `emc_nml.hh``EMC_STAT``EMC_TASK_STAT``EMC_MOTION_STAT``EMC_TRAJ_STAT` 的字段范围。
- task-HAL WASM 构建接入的是 `emctask.cc``taskintf.cc``emccanon.cc` 的窄 source-anchored subset不是完整上游 process/NML topology。
- `tools/task-hal-source-manifest.txt` 仍是 Phase 0 references`task_hal_runtime_promoted=0`
- `nativeTaskReady=false``nativeHalSyncReady=false``fullLinuxCncProgramExecutionReady=false` 仍是当前 readiness contract。
## WASM核心状态机边界
后续完善时按以下职责划分:
| 层 | 职责 |
| --- | --- |
| WASM/C++ | 核心状态机、LinuxCNC 语义复用、task cycle、motion snapshot、`StandaloneEmcStatus`、command read/plan/execute、RCS 聚合。 |
| JS/SDK | 加载 WASM、传命令、读状态、管理 Emscripten FS/OPFS 和浏览器/Node 边界。 |
| JSON | 作为外部通信格式,例如 command JSON 和 status JSON不得作为核心状态机事实源。 |
因此,新增状态应优先进入 C/C++ 结构体、枚举、队列和周期函数status JSON 只能从最后一次 status write 或 `StandaloneEmcStatus` 导出。
`status JSON` 的具体 LinuxCNC 对标方案详见 `12-status-json-LinuxCNC对标方案.md`。该方案要求 `emcStatus` 成为新增 LinuxCNC 对标字段的主对象,`task``motionStatus` 等旧字段只作为兼容视图。
## 功能范围
本阶段要实现或准备实现:
1. 在 WASM task runtime 内建立 `EMC_STAT` 等价状态容器。
2. 将 minimal motion runtime 的状态导入 `EMC_STAT.motion` 等价快照。
3. 重排 `lctask_run_cycles()`,使每个 task 周期符合上游主循环顺序。
4. 把 wait-for-motion、motion queue、pause/step/resume、abort/error 逻辑改为依赖 motion 快照。
5. 增加测试证明 task 周期内读取 motion而不是只在 status API 读取时拼接 motion。
6. 分阶段引入 vendored/upstream task 源码,减少自有状态机语义。
## 最小字段闭环
第一阶段必须优先闭合以下字段,原因是它们直接参与 `emctaskmain.cc` 主循环、`emcTaskExecute()` 或顶层 status 聚合:
| 领域 | 字段 | 用途 |
| --- | --- | --- |
| task | `state``mode` | state/mode gate、power/home/run 前置 |
| task | `execState``interpState` | `emcTaskPlan()``emcTaskExecute()` 状态机 |
| task | `currentLine``readLine``motionLine` | interpreter/motion line 对齐 |
| task | `task_paused` | pause/resume/step |
| motion | `status` | wait-for-motion、error、top-level status |
| motion.traj | `enabled``inpos``queue``activeQueue``queueFull` | motion wait、queue gate、disable edge |
| motion.traj | `id``paused``single_stepping` | stepping、motion id、pause |
| motion.traj | `position``actualPosition``current_vel` | UI/status、interpreter sync |
| motion | `on_soft_limit` | soft-limit error path |
| io | `status``aux.estop` | subordinate sync、top-level status |
完整字段映射详见 `07-emctaskmain周期对标蓝图.md`
后续 WASM 核心状态机完善路线详见 `11-WASM核心状态机边界与后续完善路线.md`
## 非目标
本阶段不做:
- 驱动真实硬件。
- 浏览器内复刻 LinuxCNC 原生多进程拓扑。
- 移植 native GUI。
- 用 JavaScript 重写 CNC/task/motion 语义。
- 一次性完整移植 realtime motion controller。
## 完成定义
阶段完成至少满足:
- 文档记录 task 主循环对标范围、步骤、任务矩阵和验收证据。
- 新增测试能区分“task 周期读取 motion”和“status API 拼接 motion”。
- `lctask_run_cycles()` 内存在清晰的 LinuxCNC 式周期结构。
- `nativeTaskReady``nativeHalSyncReady``fullLinuxCncProgramExecutionReady` 等 readiness 字段与真实能力一致。
- 现有 WASM task/motion/HAL smoke 不回退。
- `lctask_send_command_json()` 不再直接产生 LinuxCNC task 语义变化;语义变化必须由后续 `lctask_run_cycles()` 的 command read/plan/execute 阶段产生。
- `lctask_read_status_json()` 不推进、不同步、不重新读取 motion它只导出最后一次 status write 的快照。

View File

@@ -0,0 +1,150 @@
# 02-项目程序开发详细步骤
## 阶段 0基线固定
1. 记录当前实现与 LinuxCNC 主循环差距。
2. 固定当前通过的 smoke
- `./tools/verify_task_hal_source_manifest.sh`
- `./tests/wasm/node/verify_motion_hal_sync.sh`
- `./tests/wasm/node/verify_task_hal_wasm.sh`
- `./tests/wasm/node/verify_task_hal_sdk.sh`
3. 记录当前已知阻塞和 readiness
- `./tests/native/verify_task_hal_phase0.sh` 曾因上游运行目录缺少 `xyzac-trt_cmds.hal` 失败T-016 已通过运行目录 machine overlay 修复该 probe 输入完整性。
- task-hal source manifest 仍显示 `task_hal_runtime_promoted=0`,不代表 full native task/HAL runtime 已 promoted。
## 阶段 1建立 task 周期内 motion snapshot
1.`linuxcnc_task_hal_wasm.cpp` 中新增 task runtime 内部 motion snapshot。
2.`linuxcnc_motion_runtime.h` 中定义 `LcmotStatusSnapshot`,字段至少覆盖:
- cycle、program_line、motion_id、status、in_position、paused、stepping、aborted
- queue_count、queue_capacity、queue_full、active_depth
- axis/joint command/feedback
- requested/current velocity
- switchkins/analog outputs。
3.`linuxcnc_motion_runtime.c` 暴露结构化读取函数,避免 task 周期内解析 JSON。
4.`linuxcnc_task_hal_wasm.cpp` 中新增 `wasm_emcMotionUpdate()`,把 `LcmotStatusSnapshot` 映射到 task 持有的 `EMC_STAT.motion` 等价结构。
5. 在每个 `lctask_run_cycles()` task 周期调用 motion snapshot update。
6. 将 status JSON 改为读取 task 内已更新的 snapshot而不是独立拼接最新 motion JSON。
7. 新增测试:
- 队列中 motion 状态变化必须在 `runCycles()` 后反映到 task status。
- 不调用 `runCycles()` 时,仅调用 status API 不应推进 task 周期语义。
- 直接调用 low-level `lcmot_step_servo()`task status 不应自动更新,直到下一次 `lctask_run_cycles()`
## 阶段 2重排 `lctask_run_cycles()` 周期顺序
目标顺序:
1. task heartbeat / cycle 自增。
2. command read从 staged command queue 或 C ABI command slot 取命令。
3. plan处理模式、run、pause、resume、mdi、home、abort 等 task plan 行为。
4. execute根据 task exec state 向 motion/io 发命令或等待 motion/io 完成。
5. motion update读取 motion runtime snapshot 到 task 状态。
6. subordinate sync处理 estop、motion error、io error、soft limit、abort cleanup 等。
7. task update刷新 task-specific status。
8. status write更新 C ABI 可读 status snapshot。
9. servo step按 standalone WASM 边界推进 deterministic servo cycles。
注意:上游 LinuxCNC 是 native process/realtime 拓扑WASM 内的 servo step 位置允许作为 standalone runtime 边界记录在决策里,但 task 对外语义必须说明与上游差异。
建议拆成内部函数,避免把所有逻辑堆回 `lctask_run_cycles()`
```cpp
static void task_cycle_begin(TaskRuntime &state);
static bool task_read_command(TaskRuntime &state);
static int wasm_emcTaskPlan(TaskRuntime &state);
static int wasm_emcTaskExecute(TaskRuntime &state);
static int wasm_emcMotionUpdate(TaskRuntime &state);
static void sync_subordinate_states(TaskRuntime &state);
static void wasm_emcTaskUpdate(TaskRuntime &state);
static void update_top_level_status(TaskRuntime &state);
static void write_status_snapshot(TaskRuntime &state);
```
每个函数必须在注释或文档中标明对应的上游 `emctaskmain.cc` 行为。
## 阶段 3引入 `EMC_STAT` 等价状态容器
1. 对齐 `EMC_STAT.task``EMC_STAT.motion``EMC_STAT.io` 中本阶段需要的字段。
2. 识别上游真实定义来源:
- enum 和函数声明主要在 `emc.hh`
- `EMC_STAT``EMC_TASK_STAT``EMC_MOTION_STAT``EMC_TRAJ_STAT` 真实字段在 `emc_nml.hh`
3. 优先复用 vendored `emc_nml.hh`/`emc.hh` 类型;如依赖过重,建立字段同名、语义同向的窄 `StandaloneEmcStatus`,并记录差异。
4.`TaskRuntime` 中重复字段逐步映射到 `EMC_STAT.task`
5.`lcmot` motion status 映射到 `EMC_STAT.motion`
6. 初始 IO 可用 shim 固定 `DONE`,但必须具备 `status``aux.estop``fault``reason` 字段。
7. 确保 JSON status 只是 `EMC_STAT` 或等价 status buffer 的导出视图。
## 阶段 4迁移 wait/execute 语义
1. 对标 `emcTaskExecute()` 的关键状态:
- `DONE`
- `WAITING_FOR_MOTION_QUEUE`
- `WAITING_FOR_MOTION`
- `WAITING_FOR_IO`
- `WAITING_FOR_MOTION_AND_IO`
- `WAITING_FOR_DELAY`
- `WAITING_FOR_SYSTEM_CMD`
- `ERROR`
2. 先迁移 motion 相关状态,不急于实现 system command/process。
3. `queueFull``motion.status``io.status` 的判断必须从周期 snapshot 读取。
4. pause/step/resume 的状态变化必须覆盖现有 smoke。
## 阶段 5逐步替换自有状态机
1. 把当前 JSON command 分派收缩为 host/C ABI 边界。
2. `lctask_send_command_json()` 不直接修改 `state/mode/interp/exec`,而是入队 command envelope。
3. 在 command read 阶段消费 envelope生成 LinuxCNC task command 等价物。
4. 把 task plan/execute 语义迁向 vendored/upstream `emctask.cc``taskintf.cc``emccanon.cc`
5. 为 native-only/runtime-edge 功能建立 shim
- NML transport
- file IO
- process spawning
- IO process
- realtime HAL/thread scheduling
6. 每替换一段,补一条 matrix 任务和验收证据。
具体源码替换顺序见 `08-上游task源码替换分解.md`。实施时按以下顺序推进:
1. `taskintf.cc` minimal bridge先替换 motion init/update/abort、traj pause/step/resume/linear move。
2. `emctask.cc` state/update/abort替换 task state/mode/abort/update。
3. `emctask.cc` plan wrapper接 interpreter open/read/execute/synch。
4. `emccanon.cc` straight motion`INIT_CANON()``FINISH()``STRAIGHT_TRAVERSE()``STRAIGHT_FEED()`
5. `emctaskmain.cc` execute 分支:用 `interp_list` 和 taskintf issue command。
6. `emccanon.cc` spindle/tool/io 子集dwell、switchkins、tool/spindle command。
## 阶段 6readiness 和文档收口
1. 修正文档、代码、测试中的 readiness 口径。
2. `nativeTaskReady` 只有在真实 vendored/native task 周期被采用后才能为 true。
3. `nativeHalSyncReady` 只有在 HAL 同步达到对应验收后才能为 true。
4. `fullLinuxCncProgramExecutionReady` 只有在完整 program execution 语义闭合后才能为 true。
5. 更新 `docs/source-reuse-map.md`,避免文档声称与实现不一致。
## 阶段 7后续 WASM 核心状态机完善
本阶段用于后续新增任务,不改变 T-001 到 T-049 的闭合状态。实施前必须先在 `04-任务矩阵.md` 新增任务编号、状态、验收标准和 gate。
1. 坚持 WASM/C++ 为核心状态机实现:
- task/motion 状态机、周期调度、状态聚合、命令执行进入 C/C++。
- `StandaloneEmcStatus` 或后续 `EMC_STAT` 等价容器是 status 事实源。
- `LcmotStatusSnapshot` 是 task 周期读取 motion 的结构化输入。
2. 保持 JS/SDK 为 host 边界:
- JS/SDK 可以加载 WASM、写入文件、入队 command、读取 status。
- JS/SDK 不实现 G-code、task、motion、planner 或 canon 语义。
3. 保持 JSON 为通信格式:
- command JSON 只描述 host command envelope。
- status JSON 只导出最后一次 status write。
- 不允许新增依赖 JSON 文本推进 task cycle 的路径。
- 新增 status 字段优先进入 `emcStatus` 对标对象,再按需提供旧字段兼容视图。
4. 每次迁移新语义时优先查找 vendored LinuxCNC source
- 能接入 source-anchored subset 时接入 subset。
- 不能直接接入时建立窄 shim并在 `06-决策记录.md` 写明原因。
5. 每次新增状态字段时同步更新:
- C/C++ status 结构体。
- status JSON 导出。
- WASM smoke。
- SDK smoke。
- state matrix。
- source reuse/drift docs gate。
详细边界和检查清单见 `11-WASM核心状态机边界与后续完善路线.md`status JSON 字段映射、禁止链路和后续 SJ 批次见 `12-status-json-LinuxCNC对标方案.md`

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,72 @@
# 04-任务矩阵
## 状态说明
- `待办`:尚未开始。
- `进行中`:已有修改但未验收闭合。
- `完成`:代码/文档/测试/证据均已闭合。
- `阻塞`:需要外部文件、上游能力或明确决策后才能继续。
## 任务列表
| 编号 | 任务 | 状态 | 验收标准 |
| --- | --- | --- | --- |
| T-001 | 创建 `wasm-port/working` 推进文档 | 完成 | README、01-06 文档存在;任务矩阵、台账、验收证据、决策记录具备初始内容。 |
| T-002 | 固定当前 task/motion/HAL 基线证据 | 完成 | `verify_task_hal_source_manifest.sh``verify_motion_hal_sync.sh``verify_task_hal_wasm.sh``verify_task_hal_sdk.sh` 结果写入 `05-验收证据.md`。 |
| T-003 | 设计 task 周期内 motion snapshot C ABI | 完成 | 有设计记录;避免 task 周期内解析 JSON明确字段映射到 `EMC_STAT.motion` 等价结构。 |
| T-004 | 实现 minimal motion snapshot 结构化读取 | 完成 | `linuxcnc_motion_runtime.c` 提供结构化 snapshot 读取;现有 motion smoke 不回退。 |
| T-005 | 在 `lctask_run_cycles()` 每个 task 周期读取 motion snapshot | 完成 | 新测试证明 task status 来自周期 snapshotstatus API 不再是 task motion 事实源。 |
| T-006 | 重排 `lctask_run_cycles()` 为 LinuxCNC 式周期骨架 | 完成 | 代码中有 command read、plan、execute、motion update、subordinate sync、task update、status write 的清晰阶段;现有 smoke 通过。 |
| T-007 | 建立 `EMC_STAT` 等价状态容器 | 完成 | task/motion/io 必需字段集中管理JSON status 从该状态导出。 |
| T-008 | 迁移 wait-for-motion 和 queueFull 语义 | 完成 | `WAITING_FOR_MOTION``WAITING_FOR_MOTION_QUEUE` 依赖周期 motion snapshot新增覆盖测试。 |
| T-009 | 迁移 motion/io error 和 abort cleanup 语义 | 完成 | motion error/io error 能驱动 task abort/error测试覆盖不回退。 |
| T-010 | 迁移 pause/resume/step 到 snapshot 驱动 | 完成 | `pause_freezes_motion_queue``resume_restores_interp_resume_state``step_returns_to_paused` 继续通过,并新增周期 snapshot 断言。 |
| T-011 | 收缩 JSON command 自有状态机 | 完成 | JSON 只作为 C ABI host 边界task 语义转入 LinuxCNC 式 plan/execute 层。 |
| T-012 | 引入 vendored/upstream `emctask.cc` 可编译子集 | 完成 | build 脚本纳入对应源或 shim新增 source reuse 验证。 |
| T-013 | 引入 vendored/upstream `taskintf.cc` 可编译子集 | 完成 | motion command issuing 更接近上游adapter 边界有文档说明。 |
| T-014 | 引入 vendored/upstream `emccanon.cc` 可编译子集 | 完成 | canonical task/motion command 生成减少自有语义;测试通过。 |
| T-015 | 修正 readiness 文档和实现口径 | 完成 | `nativeTaskReady``nativeHalSyncReady``fullLinuxCncProgramExecutionReady` 与实际能力一致;`docs/source-reuse-map.md` 不再与代码矛盾。 |
| T-016 | 处理 `verify_task_hal_phase0.sh` native probe 阻塞 | 完成 | 缺失 `xyzac-trt_cmds.hal` 问题有明确来源修复或任务降级决策phase0 gate 口径稳定。 |
| T-017 | 建立 `emctaskmain.cc` 周期对标蓝图 | 完成 | `07-emctaskmain周期对标蓝图.md` 存在包含上游代码锚点、WASM 周期骨架、字段映射、command/plan/execute/motion update/status write 对标要求。 |
| T-018 | 定义 `LcmotStatusSnapshot` 结构 | 完成 | header 中有结构化 snapshot 类型;字段覆盖 queue、inpos、paused、motion id、axis/joint、velocity、switchkins不解析 JSON。 |
| T-019 | 实现 `lcmot_read_status_snapshot()` | 完成 | 函数只复制 motion runtime 状态,不 step servo、不消费队列新增 low-level 单测。 |
| T-020 | 实现 `wasm_emcMotionUpdate()` 映射层 | 完成 | `LcmotStatusSnapshot` 映射到 `EMC_STAT.motion``StandaloneEmcStatus.motion`;字段映射有测试。 |
| T-021 | 建立 task status buffer 等价物 | 完成 | `lctask_read_status_json()` 只导出最后一次 task status write不直接读取/同步 motion runtime。 |
| T-022 | 建立 command buffer/slot | 完成 | `lctask_send_command_json()` 入队 command不调用 `runCycles()` 时 task 语义状态不变化。 |
| T-023 | 拆分 `lctask_run_cycles()` 周期函数 | 完成 | 内部函数覆盖 cycle begin、command read、plan、execute、motion update、subordinate sync、task update、top-level status、status write。 |
| T-024 | 迁移当前 state/mode/home/run gate 到 plan 阶段 | 完成 | 现有 state matrix 通过command 语义由 `runCycles()` 触发。 |
| T-025 | 迁移 MDI/JOG/HOME motion issue 到 execute 阶段 | 完成 | MDI/JOG/HOME 不在 send command 时直接 forward motion现有 smoke 通过。 |
| T-026 | 新增 task 周期 snapshot 行为测试 | 完成 | 覆盖 status read 不推进、不同步low-level motion step 后 task status 等待下一 task cycle 才更新。 |
| T-027 | 新增 motion error/soft-limit 注入测试 | 完成 | motion ERROR 和 soft-limit 能通过 subordinate sync 改变 task/top-level status。 |
| T-028 | 对齐 top-level `RCS_STATUS` 聚合 | 完成 | task/motion/io 三方 DONE/EXEC/ERROR 聚合逻辑与 `emctaskmain.cc` 对齐JSON status 反映聚合值。 |
| T-029 | 评估 vendored `emc_nml.hh` 直接复用可行性 | 完成 | 形成记录:直接 include、窄 shim、或分阶段 typedef 的选择和依赖清单。 |
| T-030 | 更新 source reuse map 与 drift 文档 | 完成 | `docs/source-reuse-map.md`、drift/compatibility 文档反映 task 主循环迁移阶段和 readiness 真实状态。 |
| T-031 | 建立上游 task 源码替换分解文档 | 完成 | `08-上游task源码替换分解.md` 存在,覆盖 `emctask.cc``taskintf.cc``emccanon.cc` 的函数族、shim、验收和批次。 |
| T-032 | `taskintf.cc` usrmot shim 设计 | 完成 | 明确 `usrmot*``lcmot_*` 的映射,包含 command write、status read、config read、error read。 |
| T-033 | `taskintf.cc` motion init/update/abort 子集 | 完成 | `emcMotionInit()``emcMotionUpdate()``emcMotionAbort()` 通过 WASM bridge 工作task cycle snapshot 测试通过。 |
| T-034 | `taskintf.cc` traj control 子集 | 完成 | `emcTrajEnable/Disable/Abort/Pause/Step/Resume/SetMotionId` 接入 `lcmot`,现有 pause/step/resume smoke 不回退。 |
| T-035 | `taskintf.cc` linear move issue 子集 | 完成 | `emcTrajLinearMove()` 替换 task JSON linear move 拼接G0/G1 smoke 通过。 |
| T-036 | `taskintf.cc` jog/home/switchkins 子集 | 完成 | `emcJogIncr()``emcJointHome/Unhome()``emcMotionSetAout()` 接入Home/Jog/M428-M430 验收通过。 |
| T-037 | `emctask.cc` abort/state/mode 子集 | 完成 | `emcTaskAbort()``emcTaskSetMode()``emcTaskSetState()` 替换当前自有逻辑;语义由 task cycle 触发。 |
| T-038 | `emctask.cc` determine/update 子集 | 完成 | `determineMode()``determineState()``emcTaskUpdate()` 从 motion/io snapshot 推导 task status。 |
| T-039 | `emctask.cc` plan wait/synch/open/close 子集 | 完成 | `PlanSetWait/IsWait/ClearWait/Synch/Open/Close/Reset` 接入 vendored interpreter 和 staged FS。 |
| T-040 | `emctask.cc` plan read/execute 子集 | 完成 | `PlanRead/Execute/Line/Level/Command` 驱动 `interp_list`;不依赖 JSON motion plan。 |
| T-041 | `emccanon.cc` canon init/finish/unit 子集 | 完成 | `INIT_CANON()``ON_RESET()``FINISH()`、单位/endpoint getter 接入 `EMC_STAT`。 |
| T-042 | `emccanon.cc` straight traverse/feed 子集 | 完成 | `STRAIGHT_TRAVERSE()``STRAIGHT_FEED()` 生成 LinuxCNC `EMC_TRAJ_LINEAR_MOVE``interp_list`。 |
| T-043 | `emccanon.cc` dwell/path-control 子集 | 完成 | `DWELL()``SET_MOTION_CONTROL_MODE()` 进入 task delay/path mode 语义。 |
| T-044 | `emccanon.cc` spindle/tool command 子集 | 完成 | spindle/tool commands append 到 `interp_list`runtime boundary 和 readiness 保守记录。 |
| T-045 | `emccanon.cc` motion output/switchkins 子集 | 完成 | M62-M68/M428-M430 通过 canon motion output 到 `emcMotionSetAout()`,移除字符串 special-case。 |
| T-046 | 移除主路径 JSON motion plan 依赖 | 完成 | RUN 文件主路径由 `Interp::open/read/execute` + `emccanon.cc` + `interp_list` + `emcTaskExecute()` 驱动;`loadProgramMotionPlan()` 降为调试/兼容入口或删除。 |
| T-047 | 收口 working 索引与闭合 gate | 完成 | README、功能内容、NML 评估和矩阵闭合口径与 T-007/T-046 当前实现一致;有 gate 验证无待办/进行中/阻塞任务。 |
| T-048 | 将 working closure gate 纳入全局文档一致性验证 | 完成 | `source-reuse-map.md``compatibility-validation.md``verify_task_source_reuse_drift_docs.sh` 均记录并检查 `verify_task_working_closure.sh`。 |
| T-049 | 建立 task-HAL 全量闭合验证入口 | 完成 | `tools/verify_task_full_closure.sh` 一次性执行 build、WASM smoke、SDK、state matrix、motion sync、T-007/T-046/T-047/T-048/docs/readiness gates。 |
| T-050 | 建立 status JSON LinuxCNC 对标方案 | 完成 | `12-status-json-LinuxCNC对标方案.md` 存在README、功能内容、开发步骤、台账、证据和决策记录均记录 `StandaloneEmcStatus -> status JSON` 方案working closure gate 不回退。 |
| T-051 | SJ-1 规范 `emcStatus.motion.traj` | 完成 | `emcStatus.motion.traj` 导出 enabled/inpos/queue/activeQueue/queueFull/id/paused/singleStepping/position/actualPosition/currentVelWASM/SDK/state matrix 和 status JSON contract gate 断言其与兼容 `motionStatus` 同源。 |
| T-052 | SJ-2 规范 task line 和 interpreter 字段 | 完成 | `StandaloneEmcTaskStatus` 集中 currentLine/readLine/motionLine/callLevel`task` 兼容视图和 `emcStatus.task` 同源staged RUN 后 contract gate 验证 line 字段。 |
| T-053 | SJ-3 规范 `emcStatus.motion.axis[]``joint[]` | 完成 | `StandaloneEmcMotionStatus` 保存 axis command/feedback 与 joint command/feedback 数组;`emcStatus.motion.axis[]``joint[]` 导出至少 6 轴/关节,旧 `motionStatus.axis``joint0` 与新数组一致。 |
| T-054 | SJ-4 规范 IO/aux/tool/coolant 边界 | 完成 | `emcStatus.io` 导出 status/error/fault/reason/aux.estoptool/coolant 以 `supported=false` 和 shim reason 显式标记未接 native IOreadiness 仍为 false。 |
| T-055 | SJ-5 引入 status JSON contract gate | 完成 | 新增 `tools/verify_task_status_json_contract.sh` 和 Node contract 测试;检查 `statusSource=StandaloneEmcStatus``lctask_read_status_json()` 不调用 motion JSON、SDK 不实现 task/motion 语义;该 gate 纳入 full closure。 |
## 当前推进指针
下一条优先任务:无。任务矩阵当前已闭合;`11-WASM核心状态机边界与后续完善路线.md``12-status-json-LinuxCNC对标方案.md` 中 SJ-1 到 SJ-5 已补入 T-051 到 T-055 并闭合。后续新增对标项需先补入本矩阵。

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,218 @@
# 07-emctaskmain 周期对标蓝图
## 对标目标
本蓝图把 LinuxCNC `emctaskmain.cc` 的 task 主循环拆成 `wasm-port` 可逐步实现的周期阶段。后续实现不得只在 JSON status 层拼接 motion而必须让 task 周期本身读取并消费 motion snapshot。
## 上游周期源代码锚点
| 上游位置 | 行为 | WASM 对标要求 |
| --- | --- | --- |
| `emctask_startup()` motion 初始化 | `emcMotionInit()` 后立即 `emcMotionUpdate(&emcStatus->motion)`,失败则启动失败 | `lctask_init_session()` 必须初始化 motion runtime并建立第一份 task 持有的 motion snapshot |
| 主循环 `task_beat++` | task heartbeat 每周期递增 | `lctask_run_cycles()` 每个 task cycle 增加 task heartbeat/cycle |
| `check_ini_hal_items()` | 周期检查 INI/HAL 项 | standalone 可先记录为 shim 阶段,后续接 HAL/INI 检查 |
| `emcCommandBuffer->read()` | 读取新 task command成功后清 `taskPlanError/taskExecuteError` | JSON C ABI command 应先进入 command buffer/slot再由 task cycle 消费 |
| `emcTaskPlan()` | 处理 task state/mode/interpreter/read-ahead/MDI 队列 | 当前 `lctask_send_command_json()` 的状态变化要迁到 plan 阶段 |
| `emcTaskExecute()` | 根据 `execState` issue command 或等待 motion/io | 当前直接 forward motion command 的逻辑要迁到 execute 阶段 |
| `emcMotionUpdate(&emcStatus->motion)` | 每周期读取 motion 状态 | 每个 `lctask_run_cycles()` 周期必须执行结构化 `lcmot_read_snapshot()` 等价调用 |
| volatile home sync | motion enabled -> disabled 时 unhome volatile joints | standalone 先保留字段/事件,后续接 joints/homing |
| estop subordinate sync | io estop 时 disable traj、abort task/io/spindle、synch plan | 需要 task 周期内根据 `emcStatus.io``emcStatus.motion` 统一处理 |
| motion/io error sync | soft-limit、motion error、io hard fault 驱动 abort cleanup | 必须新增 motion error 注入测试 |
| `emcTaskUpdate(&emcStatus->task)` | 刷新 task status | WASM status snapshot 要从 `emcStatus.task` 等价结构导出 |
| top-level status aggregation | 根据 task/motion/io 状态设置 `emcStatus.status``task.status` | JSON status 中的 task top-level status 必须由聚合结果生成 |
| `emcStatusBuffer->write(emcStatus)` | 写出完整状态 | WASM 中写入 last status snapshotSDK read 只读该 snapshot |
## WASM 周期骨架
目标伪代码:
```cpp
int lctask_run_cycles(long task_period_ns, long servo_period_ns, int task_cycles)
{
for each task cycle:
task_heartbeat++;
task_cycle_begin();
check_ini_hal_items_shim();
command_read_result = wasm_task_command_buffer_read();
if (command_read_result.new_command) {
taskPlanError = false;
taskExecuteError = false;
}
if (wasm_emcTaskPlan() != 0) {
taskPlanError = true;
}
if (wasm_emcTaskExecute() != 0) {
taskExecuteError = true;
}
wasm_emcMotionUpdate(&emcStatus.motion);
wasm_sync_subordinate_states();
wasm_emcTaskUpdate(&emcStatus.task);
wasm_update_top_level_status();
wasm_status_buffer_write(emcStatus);
lcmot_step_servo(servo_period_ns, servo_per_task);
}
```
说明:
- 上游 motion 是独立 realtime 子系统task 读的是 motion 已产生的状态。
- WASM standalone 需要 deterministic servo step。若先 step servo 再 motion update 才能模拟“读取最新子系统状态”,必须在 `06-决策记录.md` 明确差异,并用测试固定语义。
- 无论 servo step 放在周期前还是周期后,`emcTaskExecute()` 的判断必须读取 task 持有的上一份/本份 motion snapshot不允许临时解析 status JSON。
## `EMC_STAT` 字段映射优先级
第一优先级字段用于让 task 主循环能按 LinuxCNC 结构运行:
| LinuxCNC 字段 | 上游定义 | 当前/目标 WASM 来源 | 用途 |
| --- | --- | --- | --- |
| `EMC_STAT.task.state` | `EMC_TASK_STAT.state` | 当前 `TaskRuntime.state` -> `emcStatus.task.state` | ESTOP/OFF/ON gate |
| `EMC_STAT.task.mode` | `EMC_TASK_STAT.mode` | 当前 `TaskRuntime.mode` -> `emcStatus.task.mode` | MANUAL/MDI/AUTO gate |
| `EMC_STAT.task.execState` | `EMC_TASK_STAT.execState` | 当前 `exec_state` -> enum | execute 状态机 |
| `EMC_STAT.task.interpState` | `EMC_TASK_STAT.interpState` | 当前 `interp_state` -> enum | read-ahead/pause/run |
| `EMC_STAT.task.currentLine` | `EMC_TASK_STAT.currentLine` | motion plan/interp list line | motion id、UI line |
| `EMC_STAT.task.readLine` | `EMC_TASK_STAT.readLine` | interpreter read line | read-ahead 对标 |
| `EMC_STAT.task.motionLine` | `EMC_TASK_STAT.motionLine` | motion snapshot `programLine/id` | 当前 motion line |
| `EMC_STAT.task.task_paused` | `EMC_TASK_STAT.task_paused` | pause/step state | pause/resume/step |
| `EMC_STAT.motion.status` | base `RCS_STAT_MSG.status` | `lcmot` snapshot status | wait/error/status aggregation |
| `EMC_STAT.motion.traj.enabled` | `EMC_TRAJ_STAT.enabled` | state ON/off + motion runtime | estop/disable edge |
| `EMC_STAT.motion.traj.inpos` | `EMC_TRAJ_STAT.inpos` | `lcmot.in_position` | wait-for-motion |
| `EMC_STAT.motion.traj.queue` | `EMC_TRAJ_STAT.queue` | `lcmot.queue_count` | queue/status aggregation |
| `EMC_STAT.motion.traj.activeQueue` | `EMC_TRAJ_STAT.activeQueue` | active motion depth | queue/status aggregation |
| `EMC_STAT.motion.traj.queueFull` | `EMC_TRAJ_STAT.queueFull` | queue capacity check | `WAITING_FOR_MOTION_QUEUE` |
| `EMC_STAT.motion.traj.id` | `EMC_TRAJ_STAT.id` | `lcmot.motion_id` | stepping/current line |
| `EMC_STAT.motion.traj.paused` | `EMC_TRAJ_STAT.paused` | `lcmot.paused` | pause/step |
| `EMC_STAT.motion.traj.single_stepping` | `EMC_TRAJ_STAT.single_stepping` | `lcmot.stepping` | step |
| `EMC_STAT.motion.traj.actualPosition` | `EMC_TRAJ_STAT.actualPosition` | `lcmot.axis_fb` mapped pose | interpreter sync/start line |
| `EMC_STAT.motion.traj.position` | `EMC_TRAJ_STAT.position` | `lcmot.axis_cmd` mapped pose | UI/canon endpoint |
| `EMC_STAT.motion.on_soft_limit` | `EMC_MOTION_STAT.on_soft_limit` | future injection/runtime flag | soft-limit path |
| `EMC_STAT.io.status` | `EMC_IO_STAT.status` | initial shim `DONE`/future IO runtime | wait/error aggregation |
| `EMC_STAT.io.aux.estop` | `EMC_IO_STAT.aux.estop` | task state/IO shim | estop subordinate sync |
第二优先级字段在 program execution 更深入时补齐:
- `activeGCodes``activeMCodes``activeSettings`
- `g5x_offset``g92_offset``rotation_xy``toolOffset`
- `synch_di``synch_do``analog_input``analog_output`
- spindle orient state/fault
- toolchanger fault/reason
## command read 对标
当前 `lctask_send_command_json()` 直接修改 task state 或 forward motion。目标结构
1. `lctask_send_command_json()` 只把 JSON 解析成 task command envelope写入 WASM command buffer。
2. `lctask_run_cycles()` 内的 command read 阶段消费一条 command。
3. command read 成功后清 `taskPlanError``taskExecuteError`
4. command 的语义处理转入 `wasm_emcTaskPlan()``wasm_emcTaskIssueCommand()`
验收:
- 调用 `sendCommand()` 后不调用 `runCycles()`task state 不发生 LinuxCNC 语义变化。
- 调用一次 `runCycles()`command 被计划/执行,状态变化出现。
## plan 对标
第一阶段 plan 只迁移现有已支持命令:
- `EMC_TASK_SET_STATE`
- `EMC_TASK_SET_MODE`
- `EMC_TASK_PLAN_RUN`
- `EMC_TASK_PLAN_PAUSE`
- `EMC_TASK_PLAN_RESUME`
- `EMC_TASK_PLAN_STEP`
- `EMC_TASK_ABORT`
- `EMC_TASK_PLAN_EXECUTE`
- `EMC_JOINT_HOME`
- `EMC_JOG_INCR`
要求:
- plan 只决定 task/interp/exec 状态和待执行命令,不直接 step motion。
- AUTO run 必须通过 state/mode/home/program/motion-plan gates。
- MDI/JOG/HOME 只生成后续 execute 要 issue 的 command。
## execute 对标
第一阶段 execute 对标 `emcTaskExecute()` 的 motion 相关分支:
- `DONE`:从 interp/MDI/jog/home pending command 取命令,检查 `motion.traj.queueFull`issue command 或进入 wait。
- `WAITING_FOR_MOTION_QUEUE`:直到 `motion.traj.queueFull == false` 才继续。
- `WAITING_FOR_MOTION``motion.status == ERROR` 进入 `ERROR``motion.status == DONE` 进入 `DONE`
- `WAITING_FOR_MOTION_AND_IO`motion/io 都 DONE 才完成,任一 ERROR 则 ERROR。
- `ERROR`:执行 abort cleanup清 pending command/interp list重置 interp/exec state。
暂缓:
- `WAITING_FOR_SYSTEM_CMD`:外部进程 runtime boundary。
- spindle orient 深度行为:先保留字段和测试入口,后续接 spindle snapshot。
- toolchanger fault 深度行为:先由 IO shim 固定 DONE。
## motion update 对标
必须新增结构化边界,建议名称:
```c
typedef struct LcmotStatusSnapshot { ... } LcmotStatusSnapshot;
int lcmot_read_status_snapshot(LcmotStatusSnapshot *out);
```
要求:
- `lcmot_read_status_snapshot()` 不推进 servo不消费队列只复制当前 motion runtime 状态。
- `wasm_emcMotionUpdate(&emcStatus.motion)` 只把 `LcmotStatusSnapshot` 映射到 `EMC_MOTION_STAT` 等价结构。
- `lctask_read_status_json()` 只导出最后一次 `wasm_status_buffer_write()` 的结果。
验收:
- 先写入 motion command不跑 task cyclestatus 不应被 task semantic 更新。
- 跑 task cycle 后task-held `motion.traj.queue/queueFull/id/inpos/position` 更新。
- 直接调用 low-level `lcmot_step_servo()` 后,除非再跑 task cycle否则 task status snapshot 仍保持上一周期。
## subordinate sync 对标
第一阶段需要覆盖:
1. `motion.traj.enabled` 从 true 到 false 时,清 homed 或记录 volatile-home TODO。
2. `io.aux.estop == true` 且 motion enabled 时,执行 traj disable、task abort、io abort、spindle abort shim、plan synch。
3. `motion.status == ERROR && motion.on_soft_limit` 时,进入 soft-limit reporting path。
4. `motion.status == ERROR` 或 hard IO error 时,执行 abort cleanup。
5. 根据 task/motion/io 三方状态聚合 top-level `RCS_STATUS::ERROR/DONE/EXEC`
## status write 对标
WASM 需要引入 task status buffer 等价物:
- `TaskRuntime.last_status_snapshot`
-`StandaloneEmcStatus emcStatus`
- `lctask_read_status_json()` 从该 snapshot 序列化
要求:
- status read 不改变 task/motion/io 状态。
- status read 不直接调用 `lcmot_read_status_json()` 改变观察口径。
- debug/event log 可以单独存在,但不能替代 status buffer。
status JSON 只是 status buffer 的 host/browser 序列化格式。后续新增 LinuxCNC 对标字段时,字段应先进入 `StandaloneEmcStatus` 或后续 `EMC_STAT` 等价容器,再导出到 `emcStatus` JSON 对象;旧 `task``motionStatus` 字段只作为兼容视图。具体字段映射和 SJ 批次见 `12-status-json-LinuxCNC对标方案.md`
## 替换上游源码路线
| 阶段 | 引入源 | 目标 |
| --- | --- | --- |
| R1 | `emc_nml.hh` 必需 enum/status 子集或 vendored include | 用 LinuxCNC 状态类型替换字符串状态 |
| R2 | `emctaskmain.cc` 周期骨架等价函数 | 建立 task main loop 结构 |
| R3 | `taskintf.cc` motion issuing 可编译子集 | 用上游 task interface 发 motion command |
| R4 | `emctask.cc` state/mode/task update 可编译子集 | 减少自有 task state logic |
| R5 | `emccanon.cc` canonical motion command 子集 | interpreter/canon 到 motion 命令更接近上游 |
每一阶段必须满足:
- source reuse map 更新。
- build 脚本增量编译。
- Node WASM smoke 不回退。
- 新增至少一个对标断言。

View File

@@ -0,0 +1,262 @@
# 08-上游 task 源码替换分解
## 目标
本文件把上游 `emctask.cc``taskintf.cc``emccanon.cc` 的替换路线拆成可实施步骤。目标不是把三个文件一次性塞进 WASM 构建,而是按 LinuxCNC 语义依赖顺序逐步替换当前 `linuxcnc_task_hal_wasm.cpp` 中的 JSON 自有状态机。
总原则:
- 先建立 `EMC_STAT`、motion snapshot、status buffer、command buffer。
- 再迁 `emctask.cc` 的 task/interpreter/status 管理。
- 再迁 `taskintf.cc` 的 task->motion command issue 和 motion update。
- 最后迁 `emccanon.cc` 的 canon->interp_list command 生成。
- 每迁一个函数族,都必须有 source reuse、shim 边界和 WASM 测试证据。
## 文件职责总览
| 文件 | 上游职责 | WASM 替换目标 |
| --- | --- | --- |
| `emctask.cc` | task mode/state、abort cleanup、interpreter plan open/read/execute/synch、`emcTaskUpdate()` | 替换当前 `TaskRuntime` 中 state/mode/interp/exec 字符串状态和 open/run/MDI 自有逻辑 |
| `taskintf.cc` | task 到 motion 的接口;`emcTraj*``emcJoint*``emcSpindle*``emcMotionInit/Update/Abort` | 替换当前直接 `forward_motion_command()``lcmot_read_status_json()` 拼接路径 |
| `emccanon.cc` | canonical API单位/偏置/速度加速度转换;生成 `EMC_TRAJ_*`、spindle/tool/io command 到 `interp_list` | 替换当前按字符串/G-code line 生成 motion plan/linear move 的自有行为 |
## 迁移依赖链
```text
emctaskmain cycle
-> emcTaskPlan()/emcTaskExecute()
-> interp_list
-> emcTaskIssueCommand()
-> taskintf.cc emcTraj*/emcMotion*/emcJoint*/emcSpindle*
-> lcmot/lchal runtime boundary
-> emccanon.cc canonical functions append commands to interp_list
```
因此迁移顺序必须是:
1. `EMC_STAT`/`interp_list`/command buffer 基础。
2. `taskintf.cc` 的 minimal motion command bridge。
3. `emctask.cc` 的 abort/state/mode/update 和 plan wrapper。
4. `emccanon.cc` 的 linear/traverse/feed/dwell/spindle/tool 子集。
5. 更完整的 interpreter file run 和 MDI 行为。
## `emctask.cc` 分解
### E1状态和 abort 基础
优先函数:
| 函数 | 上游行为 | WASM 实施 |
| --- | --- | --- |
| `emcTaskQueueTaskPlanSynchCmd()` | 向 task command queue 追加 `EMC_TASK_PLAN_SYNCH` | 需要 command queue 支持内部 command |
| `emcTaskAbort()` | `emcMotionAbort()`、清 `emcTaskCommand`、清 `interp_list`、重置 interp/exec/line、queue synch | 替换当前 `EMC_TASK_ABORT` 直接设置字符串状态 |
| `emcTaskSetMode()` | MANUAL/MDI/AUTO 切换并设置 traj mode、abort/synch | 替换当前 SET_MODE 自有逻辑 |
| `emcTaskSetState()` | OFF/ON/ESTOP_RESET/ESTOP 驱动 motion/io/spindle/task abort | 替换当前 SET_STATE 自有逻辑 |
| `determineMode()` | 由 `motion.traj.mode``mdiOrAuto` 推导 task mode | 用 snapshot 推导 status而不是保存字符串 |
| `determineState()` | 由 `io.aux.estop``motion.traj.enabled` 推导 task state | 用 snapshot 推导 status |
| `emcTaskUpdate()` | 更新 mode/state/motionLine/file/active modes | 替换当前 `status_json()` 手写 task 字段 |
| `emcAbortCleanup()` | abort 后清理/消息 | 初期保留 shim后续接 LinuxCNC 行为 |
依赖 shim
- `emcMotionAbort()``emcTrajSetMode()``emcTrajEnable()``emcTrajDisable()`
- `emcIoAbort()``emcAuxEstopOn/Off()`、coolant/spindle shim。
- `interp_list.clear()``emcTaskCommand`
- `emcStatus` 全局或等价容器。
验收:
- SET_STATE/SET_MODE 发送后不立即改变 task 语义;一次 task cycle 后通过 `emcTaskSetState/Mode` 路径改变。
- `emcTaskAbort()``interpState=IDLE``execState=DONE`、line 清零、motion abort command 已发出。
- `emcTaskUpdate()``state/mode/motionLine` 来自 `EMC_STAT.motion/io` snapshot。
### E2plan/interpreter wrapper
优先函数:
| 函数 | 上游行为 | WASM 实施 |
| --- | --- | --- |
| `emcTaskPlanInit()` | 创建/初始化 interpreter、执行 startup code | 先接现有 vendored interpreter init动态 shlib 路径作为非目标 shim |
| `emcTaskPlanSetWait/IsWait/ClearWait()` | 控制 read-ahead waitFlag | 直接迁移 |
| `emcTaskPlanSynch()` | `interp.synch()`,失败 abort | 用 task-held motion position/status 支撑 |
| `emcTaskPlanOpen()` | 打开文件并清 motion/current/read line | 替换 `lctask_open_program()` 中自有 open 状态 |
| `emcTaskPlanRead()` | `interp.read()`,必要时 reopen file | 替换 motion plan 预加载路线 |
| `emcTaskPlanExecute()` | `interp.execute()`MDI 时 `FINISH()` | 接 `emccanon.cc` 后形成 `interp_list` |
| `emcTaskPlanClose/Reset/Line/Level/Command()` | interpreter 状态读写 | 直接对接 vendored interpreter |
依赖 shim
- vendored `Interp` 可编译子集已在 interpreter WASM 中存在,但 task-hal 模块需要链接或抽取共享。
- `FINISH()` 来自 `emccanon.cc`
- `rs274ngc_startup_code`、INI lookup、file staging。
验收:
- `open -> runCycles(read/execute)` 通过 LinuxCNC `Interp::open/read/execute`,不是 JS/JSON motion plan。
- `readLine/currentLine/callLevel/command` 与 upstream interpreter 返回一致。
- MDI command 通过 `emcTaskPlanExecute(command)` 进入 `interp_list`
## `taskintf.cc` 分解
### TIF1motion runtime bridge
优先函数:
| 函数 | 上游行为 | WASM 实施 |
| --- | --- | --- |
| `emcMotionInit()` | `emcTrajInit()`、joint/axis/spindle init、position load | 调用 `lcmot_init_from_ini()` 和 HAL init建立 config defaults |
| `emcMotionAbort()` | jog abort + traj abort | 发 `EMCMOT_ABORT``lcmot` |
| `emcMotionHalt()` | halt/disable/save/exit | standalone shim不能真实硬件 |
| `emcMotionUpdate()` | `usrmotReadEmcmotStatus()` 后更新 traj/joint/axis/spindle/synch IO/heartbeat | 改为 `lcmot_read_status_snapshot()` -> `EMC_MOTION_STAT` |
| `emcTrajUpdate()` | 映射 emcmot status 到 `EMC_TRAJ_STAT` | 复刻字段映射到 snapshot |
| `emcJointUpdate()` | 映射 joint status | 第一阶段只映射 homed/pos/ferror 必需字段 |
| `emcAxisUpdate()` | 映射 axis status | 第一阶段映射 pos cmd/fb |
| `emcSpindleUpdate()` | 映射 spindle status | 初期单 spindle shim后续 orient/atspeed |
依赖 shim
- `usrmot*` 系列函数替换为 `lcmot_*` C ABI。
- `emcmot_command_t` 可复用上游 motion headers或建立命令转换层。
- INI axis/joint/spindle 初始化先使用已有 INI/WASM runtime 或默认值。
验收:
- `emcMotionUpdate(&emcStatus.motion)` 每个 task cycle 调用一次。
- status read 不调用 `emcMotionUpdate()`
- low-level `lcmot_step_servo()` 后 task status 不变,直到 task cycle 调用 `emcMotionUpdate()`
### TIF2traj command issue
优先函数:
| 函数 | 上游行为 | WASM 实施 |
| --- | --- | --- |
| `emcTrajSetMotionId()` | 设置下一个 motion id | 映射到 `lcmot` command id 或 task pending id |
| `emcTrajEnable/Disable/Abort()` | 发 ENABLE/DISABLE/ABORT | 替换当前 state ON/OFF 手写状态 |
| `emcTrajPause/Step/Resume()` | 发 PAUSE/STEP/RESUME | 替换当前 pause/step/resume direct JSON |
| `emcTrajLinearMove()` | 构造 `EMCMOT_SET_LINE` | 替换 `enqueue_linear_move_from_line()` |
| `emcTrajCircularMove()` | 构造 `EMCMOT_SET_CIRCLE` | 后续接 arc/canon |
| `emcTrajDelay()` | task controller 处理 delay | 映射到 `WAITING_FOR_DELAY` |
| `emcTrajSetOffset/G5X/G92/Rotation` 相关 | motion/task offsets | 后续接 `emccanon.cc` offsets |
验收:
- `EMC_TRAJ_LINEAR_MOVE``emcTrajLinearMove()` 路径进入 `lcmot`,而不是 task JSON 自行拼接。
- pause/resume/step 仍通过现有 WASM smoke。
- queueFull 时 `emcTaskExecute()` 进入 `WAITING_FOR_MOTION_QUEUE`
### TIF3joint/jog/spindle/io 命令
优先函数:
| 函数组 | 范围 | 首阶段处理 |
| --- | --- | --- |
| `emcJointHome/Unhome` | homing/unhome | 保留当前 homing smoke但通过 taskintf shim |
| `emcJogIncr/Cont/Abs/Stop` | manual jog | 先迁 `emcJogIncr()` |
| `emcSpindleOn/Off/Speed/Orient` | spindle | 初期 command/event shim后续 snapshot |
| `emcMotionSetAout/Dout` | M62-M68/switchkins | 优先保留 `M428/M429/M430` switchkins 验收 |
验收:
- Home/Jog/switchkins 现有 tests 通过。
- `motion.switchkins-type` 仍同步 HAL。
- spindle/tool 未实现项明确标为 runtime boundary不假装 ready。
## `emccanon.cc` 分解
### C1canon 基础状态和单位转换
优先函数/变量:
| 函数/组 | 上游行为 | WASM 实施 |
| --- | --- | --- |
| `INIT_CANON()``ON_RESET()``FINISH()` | 初始化 canon、丢弃/flush segments | 先直接迁移或抽取 |
| `get_canon()``CanonConfig_t canon` | canon 全局状态 | 使用 vendored类型避免自建 motion plan |
| `GET_EXTERNAL_LENGTH_UNITS()``GET_EXTERNAL_ANGLE_UNITS()` | 从 motion/task status 取单位 | 接 `EMC_STAT.motion.traj.linearUnits/angularUnits` |
| `CANON_UPDATE_END_POINT()` | 更新 canon endpoint | 接 task/motion snapshot |
| `SET_G5X_OFFSET()``SET_G92_OFFSET()``SET_XY_ROTATION()` | 偏置/旋转 | 先保留字段,后续生成 task commands |
验收:
- interpreter 执行时 canon endpoint 与 motion snapshot 可同步。
- 单位换算不再由 JS/JSON motion plan 决定。
### C2直线/圆弧/探测 motion command 生成
优先函数:
| 函数 | 上游行为 | WASM 实施 |
| --- | --- | --- |
| `STRAIGHT_TRAVERSE()` | 生成 `EMC_TRAJ_LINEAR_MOVE` traverse 到 `interp_list` | 第一优先级 |
| `STRAIGHT_FEED()` | 通过 segment queue 生成 feed move | 第一优先级 |
| `generate_fast_move()``generate_move()` | flush 后 append linear move | 作为 STRAIGHT 基础 |
| `ARC_FEED()` | 生成 circular move/segments | 第二阶段 |
| `STRAIGHT_PROBE()` | 生成 `EMC_TRAJ_PROBE` | 第二阶段 |
| `RIGID_TAP()` | 生成 rigid tap | 第二阶段 |
| `SET_MOTION_CONTROL_MODE()` | G61/G64 path control | 与 planner/tolerance 验证绑定 |
依赖 shim
- `interp_list`
- `EMC_TRAJ_LINEAR_MOVE``EMC_TRAJ_CIRCULAR_MOVE` 等 NML command 类型。
- `StateTag`
- velocity/acceleration helpers 的 axis limits 来源。
验收:
- G0/G1 文件执行后 `interp_list` 中出现 LinuxCNC `EMC_TRAJ_LINEAR_MOVE`,再由 `emcTaskExecute()` issue。
- 不再由 `loadProgramMotionPlan(plan_json)` 提供主路径 motion segments。
- line number、motion id、axis endpoint 与 upstream interpreter/canon 输出一致。
### C3spindle/tool/io canonical command
优先函数:
| 函数组 | 上游行为 | WASM 实施 |
| --- | --- | --- |
| `DWELL()` | append `EMC_TRAJ_DELAY` | 接 `WAITING_FOR_DELAY` |
| `START_SPINDLE_*``STOP_SPINDLE_TURNING()``SET_SPINDLE_SPEED()` | append spindle commands | 初期 command/event shim |
| `ORIENT_SPINDLE()``WAIT_SPINDLE_ORIENT_COMPLETE()` | spindle orient wait | 后续接 snapshot |
| `SELECT_TOOL()``CHANGE_TOOL()``CHANGE_TOOL_NUMBER()` | append tool commands | 先支持 T/M6 smoke再接 IO/tool DB |
| `MOTION_OUTPUT_BIT_()``MOTION_OUTPUT_VALUE_()` | M62-M68 motion outputs | 优先用于 switchkins |
| `WAIT()` | M66 input wait | 后续接 motion `synch_di/analog_input` |
验收:
- `M428/M429/M430` 不再 special-case 字符串 MDI而是通过 remap/canon/MOTION_OUTPUT_VALUE_ 到 motion AOUT。
- `DWELL` 进入 task delay state。
- tool/spindle runtime boundary 在 readiness 中保持 false直到有对应验收。
## 替换任务批次
| 批次 | 内容 | 退出条件 |
| --- | --- | --- |
| B1 | taskintf minimal bridge`emcMotionInit/Update/Abort``emcTrajPause/Step/Resume/Abort/LinearMove` | task cycle 内 motion snapshot 和 linear move issue 通过 |
| B2 | emctask state/update/abort`emcTaskAbort/SetMode/SetState/Update` | state/mode/home/run/pause smoke 仍通过,且语义由 task cycle 触发 |
| B3 | emctask plan wrapper`PlanInit/Open/Read/Execute/Synch` | 文件和 MDI 通过 LinuxCNC interpreter/canon 生成 `interp_list` |
| B4 | emccanon straight motion`INIT_CANON/FINISH/STRAIGHT_TRAVERSE/STRAIGHT_FEED` | G0/G1 不再依赖 JSON motion plan |
| B5 | task execute issue`emcTaskExecute()` motion branches + `taskintf` issue | wait/queue/error/top-level status 对标 |
| B6 | emccanon MDI/spindle/tool/io 子集 | MDI、switchkins、dwell、basic tool/spindle command 有验收 |
## 构建策略
1. 不直接修改 `/home/mes123456/cnc_wams/linuxcnc`
2. 优先 vendored source 或可重复 copy/sync 到 `wasm-port/vendor/linuxcnc`
3. 对 runtime-edge 依赖建立 shim
- `usrmot*` -> `lcmot_*`
- NML channels -> in-process command/status buffers
- POSIX process/system command -> blocked/shim
- IO/tool DB/spindle hardware -> minimal status/command shim
4. 每增加一个上游源文件到 build更新
- `tools/task-hal-source-manifest.txt`
- `tools/build_task_hal_wasm.sh`
- `docs/source-reuse-map.md`
- `working/04-任务矩阵.md`
- `working/05-验收证据.md`
## 禁止路线
- 不允许继续把 G-code line 文本在 `linuxcnc_task_hal_wasm.cpp` 中手写解析成 motion。
- 不允许让 `readStatus()` 触发 motion update 来掩盖 task cycle 缺失。
- 不允许把 `nativeTaskReady` 提前置 true。
- 不允许绕过 `interp_list` 直接把 `emccanon.cc` 输出改成 JSON。

View File

@@ -0,0 +1,99 @@
# 09-emc_nml 复用评估
## 结论
T-029 选择:暂不直接 include 完整上游 `emc_nml.hh`,当前阶段采用窄 `StandaloneEmcStatus` / 分阶段 typedef 路线。
原因:
- `wasm-port/vendor/linuxcnc/src/emc/nml_intf/` 当前未 vendored `emc_nml.hh`
- 上游 `emc_nml.hh` 不是单纯状态结构头文件,会拉入 NML/CMS command/status message 基类和大量 interpreter/canon 依赖。
- 当前 task runtime 已有 T-028 的 `RCS_STATUS` 等价聚合行为T-007 已建立集中 `StandaloneEmcStatus` 容器;但完整 `emc_nml.hh` 仍需要未 promoted 的 NML/CMS/message runtime 边界,因此不直接 include。
- 直接 include 会把未设计的 NML transport、CMS serialization、command message update、RS274 active code arrays、tool/canon table 等边界提前混入 task main loop 迁移。
## 上游依赖清单
上游文件:`linuxcnc/src/emc/nml_intf/emc_nml.hh`
直接 include 依赖:
- `linuxcnc.h`
- `emcpos.h`
- `emc.hh`
- `libnml/rcs/rcs.hh`
- `libnml/nml/cmd_msg.hh`
- `libnml/nml/stat_msg.hh`
- `rs274ngc/modal_state.hh`
- `canon.hh`
- `rs274ngc/rs274ngc.hh`
这些依赖带来的边界:
- `RCS_CMD_MSG` / `RCS_STAT_MSG` / `CMS` / `NMLTYPE` message runtime。
- `update(CMS *)` serialization hooks。
- `CANON_TOOL_TABLE``CANON_UNITS`、RS274 active G/M/settings arrays。
- full motion/task/io/tool/coolant/aux/spindle status object graph。
## 需要的状态子集
当前 T-028 已闭合的最小状态字段:
| 领域 | 当前字段 | LinuxCNC 对应概念 |
| --- | --- | --- |
| top | `top_level_rcs_status` | `EMC_STAT.status` |
| task | `task_rcs_status` | `EMC_STAT.task.status` |
| task | `state``mode``exec_state``interp_state` | `EMC_TASK_STAT.state/mode/execState/interpState` |
| motion | `motion_rcs_status``LcmotStatusSnapshot.status` | `EMC_STAT.motion.status` |
| motion.traj | queue、queueFull、in_position、paused、stepping、motion_id | `EMC_TRAJ_STAT` queue/inpos/pause/id 字段族 |
| motion | `on_soft_limit` | `EMC_MOTION_STAT.on_soft_limit` |
| io | `io_rcs_status``io_error` | `EMC_STAT.io.status` |
## 选择
采用分阶段 typedef / 窄 status 容器:
1. T-007 已建立 `StandaloneEmcStatus`,集中承载 task/motion/io/top-level 必需字段。
2. 字段命名和 JSON 导出继续对齐 `EMC_STAT``EMC_TASK_STAT``EMC_MOTION_STAT``EMC_TRAJ_STAT``EMC_IO_STAT`
3. `RCS_STATUS` 暂以 `"DONE"``"EXEC"``"ERROR"` 字符串导出,内部可在 T-030/T-032 后替换为窄 enum。
4. T-032+ 建立 usrmot/NML shim 后,再评估是否 vendor `emc_nml.hh` 及其必要依赖,或只 vendor 一个由上游字段映射驱动的 status subset header。
## 不采用的方案
### 直接 include 完整 `emc_nml.hh`
暂不采用。
阻塞项:
- `emc_nml.hh` 未在 vendor tree 中。
- 直接 include 需要引入 `libnml`、CMS、RS274、canon 依赖链。
- 完整类中大量 `update(CMS *)` 和 message 构造路径超出当前 WASM task runtime 边界。
- 会让 T-028 已闭合的 status 聚合和后续 T-032/T-040 的 runtime edge 纠缠。
### 只扩展现有 `runtime/core/shims/nml_intf/emc.hh`
仅作为短期兼容,不作为 T-029 结论。
现有 shim 只服务解释器单位字段和 source probe
- `EMC_STAT.motion.traj.linearUnits`
- `EmcJointType`
- `extern EMC_STAT *emcStatus`
继续无限扩展该 shim 会让 interpreter 单位兼容层和 task status 容器混在一起。
## 后续入口
- T-007已建立集中 `StandaloneEmcStatus`
- T-030更新 source reuse map 与 drift 文档,记录本 T-029 决策。
- T-032设计 `taskintf.cc` usrmot shim明确 NML/transport 仍是 runtime boundary。
- T-033/T-038把 motion update 和 task update 映射到 `StandaloneEmcStatus` 字段。
## 验收
T-029 的验收由 `tools/verify_task_emc_nml_reuse_plan.sh` 固定:
- 上游 `emc_nml.hh` 存在。
- 当前 vendor tree 未声称完整 `emc_nml.hh` 已 vendored。
- 本文记录直接 include 依赖、阻塞项和最终选择。
- 任务矩阵将 T-029 标为完成。

View File

@@ -0,0 +1,191 @@
# 10-taskintf usrmot shim 设计
## 目标
T-032 定义 `taskintf.cc` 在 WASM 中继续保留的 usrmot 语义边界,以及这些边界如何落到 standalone `lcmot_*` runtime。目标是给 T-033 之后的实现提供窄 shim 合同,而不是在本阶段直接编译完整 `linuxcnc/src/emc/motion/usrmotintf.cc`
上游锚点:
- `linuxcnc/src/emc/motion/usrmotintf.h`
- `linuxcnc/src/emc/motion/usrmotintf.cc`
- `linuxcnc/src/emc/task/taskintf.cc`
WASM runtime 锚点:
- `runtime/core/linuxcnc_wrap/linuxcnc_motion_runtime.h`
- `runtime/core/linuxcnc_wrap/linuxcnc_motion_runtime.c`
- `vendor/linuxcnc/src/emc/task/taskintf_wasm_subset.hh`
- `vendor/linuxcnc/src/emc/task/taskintf_wasm_subset.cc`
## 不直接复用完整 `usrmotintf.cc`
完整上游 `usrmotintf.cc` 绑定 native shared memory、mutex、command ack 轮询、split read、error ring buffer、RTAPI init/exit 和 compensation file loading。WASM 当前 motion runtime 是同进程 standalone C ABI不存在上游共享内存段也没有 native emcmot process ack 通道。
因此 T-032 采用一个窄 usrmot shim
```text
taskintf.cc-compatible calls
-> wasm usrmot shim
-> lcmot_* C ABI
-> standalone motion runtime
```
shim 必须保留上游函数的返回值语义,但只能承诺当前 `lcmot_*` 已有或明确新增的能力。
## 映射总表
| usrmot 边界 | 上游行为 | WASM shim 映射 | 当前状态 |
| --- | --- | --- | --- |
| `usrmotIniLoad(file)` | 读取 INI 中的 motion shared memory key、timeout 等 | 只保存 `ini_path`,等待 `usrmotInit()` 调用 `lcmot_init_from_ini(ini_path, ini_text)` | 需要 shim 缓存 staged INI text |
| `usrmotInit(name)` | 连接 native emcmot shared memory | 初始化 standalone motion runtime映射到 `lcmot_init_from_ini()` | 已有底层 ABI |
| `usrmotExit()` | 断开 native emcmot shared memory/RTAPI | 映射到 `lcmot_reset()`;不退出 WASM runtime | 已有底层 ABI |
| `usrmotWriteEmcmotCommand(c)` | 写 `emcmot_command_t`,等待 `commandNumEcho` ack | 将 taskintf 命令转换为 `lcmot_write_command_json()` 可接受的 command JSON | 已有底层 ABIack 语义需降级 |
| `usrmotReadEmcmotStatus(s)` | split-read 复制 `emcmot_status_t` | 映射 `lcmot_read_status_snapshot()` 到窄 `emcmot_status_t`/`EMC_MOTION_STAT` subset | 已有底层 ABI |
| `usrmotReadEmcmotConfig(s)` | split-read 复制 `emcmot_config_t` | 新增 `lcmot_read_config_snapshot()`,输出 axes/joints/queue/config_num/limits/default units 等窄 config subset | T-033 已实现窄底层 ABI |
| `usrmotReadEmcmotInternal(s)` | 读取 debug/internal shared memory | 第一阶段返回空 internal subset后续可新增 `lcmot_read_internal_snapshot()` | 非 T-032 必需 |
| `usrmotReadEmcmotError(e)` | 从 motion error ring 取最早错误 | 新增 `lcmot_read_error_message(char *out, int out_len)` 或等价 JSON/error buffer API | T-033 已实现窄 error message queue |
| `usrmotLoadComp()` / `usrmotPrintComp()` | joint compensation 文件 IO | 暂不支持;返回 `EMCMOT_COMM_ERROR_COMMAND` 或独立 unsupported code | 后续 joint compensation 批次处理 |
## command write
上游 `usrmotWriteEmcmotCommand(emcmot_command_t *c)` 做三件事:
1. 校验 motion id。
2. 写入 shared memory command slot。
3. 轮询 `usrmotReadEmcmotStatus()`,等待 `commandNumEcho``commandStatus`
WASM shim 的 T-033 最小实现合同:
```text
usrmotWriteEmcmotCommand(c)
-> validate supported command and motion id
-> convert emcmot_command_t to taskintf/lcmot command JSON
-> lcmot_write_command_json(json)
-> return EMCMOT_COMM_OK on accepted enqueue
```
返回值映射:
| 条件 | 返回值 |
| --- | --- |
| command 转换成功且 `lcmot_write_command_json()` 返回 0 | `EMCMOT_COMM_OK` |
| command unsupported、queue full、字段非法 | `EMCMOT_COMM_ERROR_COMMAND` |
| runtime 未初始化 | `EMCMOT_COMM_ERROR_CONNECT` |
| motion id 为 invalid sentinel | `EMCMOT_COMM_INVALID_MOTION_ID` |
| in-process WASM runtime 无 ack 通道 | 不使用 `EMCMOT_COMM_ERROR_TIMEOUT`,除非后续引入 command ack |
现有 `taskintf_wasm_subset` 已覆盖的 command family
- `emcTrajAbort()` / `EMCMOT_ABORT`
- `emcTrajPause()` / `EMCMOT_PAUSE`
- `emcTrajStep()` / `EMCMOT_STEP`
- `emcTrajResume()` / `EMCMOT_RESUME`
- `emcTrajLinearMove()` / `EMCMOT_SET_LINE`
- `emcJogIncr()` / `EMCMOT_JOG_INCR`
- `emcJointHome()` / homing command envelope
- `emcMotionSetAout()` / `EMCMOT_SET_AOUT`
后续 T-034 到 T-036 可以把这些 command family 从 JSON 拼接继续收缩到 `emcmot_command_t -> shim -> lcmot` 的窄转换层。
## status read
上游 `usrmotReadEmcmotStatus(emcmot_status_t *s)` 是 split-read只复制 shared memory不推进 servo。WASM 语义必须保持这一点:
```text
usrmotReadEmcmotStatus(s)
-> lcmot_read_status_snapshot(&snapshot)
-> map snapshot to status subset
-> return EMCMOT_COMM_OK
```
硬性约束:
- 不调用 `lcmot_step_servo()`
- 不消费 motion command queue。
- 不调用 `lctask_run_cycles()`
- 不从 JSON status 反向解析。
- `status``in_position``queue_full``queue_count``motion_id``program_line``axis_cmd/fb``joint_cmd/fb``motion_error``on_soft_limit` 必须来自 `LcmotStatusSnapshot`
`LcmotStatusSnapshot.status` 到 RCS 子状态的第一阶段映射:
| `LcmotStatusSnapshot.status` | 语义 |
| --- | --- |
| `0` | motion DONE |
| `1` | motion EXEC |
| `2` | motion ERROR |
## config read
上游 `usrmotReadEmcmotConfig(emcmot_config_t *s)` 读取 config shared memory并依赖 `head == tail` 的 split-read 稳定性。当前 `lcmot_*` 只有 `lcmot_init_from_ini()`,没有 config snapshot read API。
T-032 设计结论:
```text
usrmotReadEmcmotConfig(s)
-> lcmot_read_config_snapshot(&config)
-> map config to emcmot_config_t subset
```
T-033 已新增窄实现:
```c
typedef struct {
int config_num;
int axes;
int joints;
int queue_capacity;
double linear_units;
double angular_units;
double axis_min_limit[LCMOT_MAX_AXES];
double axis_max_limit[LCMOT_MAX_AXES];
} LcmotConfigSnapshot;
int lcmot_read_config_snapshot(LcmotConfigSnapshot *snapshot);
```
如果后续替换或重命名该 APIshim 不能假装 `usrmotReadEmcmotConfig()` 已支持。允许的临时行为只有:
- task 初始化阶段使用 `lcmot_init_from_ini()` 建立 runtime defaults。
- `emcMotionUpdate()` 遇到 config read 需求时返回错误,保持 readiness false。
- 文档和验证脚本继续记录 config read 是窄 runtime-edge ABI不是 native shared-memory config promotion。
## error read
上游 `usrmotReadEmcmotError(char *e)` 从 motion error ring 取最早错误字符串。当前 `LcmotStatusSnapshot` 只有 `motion_error``on_soft_limit` 标志,不能替代错误队列。
T-032 设计结论:
```text
usrmotReadEmcmotError(e)
-> lcmot_read_error_message(e, EMCMOT_ERROR_LEN)
```
T-033 已新增窄实现:
```c
int lcmot_read_error_message(char *out, int out_len);
```
行为合同:
- 有错误消息时返回 0并复制最早错误。
- 无错误消息时返回 -1匹配上游 “no error” 分支。
- `EMCMOT_INJECT_ERROR`、soft-limit、abort cleanup 写入该 error buffer。
- status flag 仍来自 `lcmot_read_status_snapshot()`,错误文本只通过 error read 消费。
## T-033 实施入口
1. T-033 已在 `taskintf_wasm_subset` 中新增 `lc_taskintf_subset_motion_init()``lc_taskintf_subset_motion_update()``lc_taskintf_subset_motion_abort()`
2. T-033 已新增 `lcmot_read_config_snapshot()``lcmot_read_error_message()`
3. T-033 已让 `lctask_init_session()`、task-cycle motion update 和 task abort path 通过 shim 访问 motion runtime。
4. 继续保持 task status read 和 motion status read 的周期隔离:外部 `lctask_read_status_json()` 不触发新的 motion update。
5. T-034+ 可继续把 traj control command family 从 envelope 迁到更完整的 usrmot command conversion。
## 禁止路线
- 不把完整 `usrmotintf.cc` 直接加入 WASM build。
- 不用 `lcmot_read_status_json()` 反解析生成 `emcmot_status_t`
- 不让 status read 推进 servo 或 task cycle。
- 不把 config read 映射成 HAL snapshot。
- 不把 `motion_error` boolean 当成 `usrmotReadEmcmotError()` 的错误队列。
- 不把 T-032/T-033 的 usrmot shim 解释为 `nativeTaskReady=true``nativeHalSyncReady=true`

View File

@@ -0,0 +1,82 @@
# 11-WASM核心状态机边界与后续完善路线
## 目标
本文件固定后续完善 `wasm-port` 程序时的边界WASM/C++ 程序作为核心状态机实现的运行载体JS/SDK 和 JSON 只承担 host/browser 边界职责。
后续新增代码任务前,必须先把对应任务补入 `04-任务矩阵.md`,写明验收标准和 gate再按本文件推进。
## 分层边界
| 层 | 职责 | 不应承担 |
| --- | --- | --- |
| WASM/C++ | LinuxCNC 语义复用、task/motion 核心状态机、task cycle、motion snapshot、command read/plan/execute、RCS 聚合、`StandaloneEmcStatus` | 浏览器 UI 状态、DOM、OPFS 业务流程、JSON 文本状态机 |
| JS/SDK | 加载 WASM、管理 Emscripten FS/OPFS 边界、传入 command JSON、读取 status JSON、提供测试和 UI 友好 API | G-code 语义、task/motion 状态机、LinuxCNC planner/canon 语义 |
| JSON | host 与 WASM 的输入/输出通信格式,例如 `lctask_send_command_json()``lctask_read_status_json()` | 保存事实状态、推进 task 周期、执行 motion 语义、替代结构体状态 |
## 核心原则
1. `lctask_run_cycles()` 是 task 状态变化的主入口。
2. `lctask_send_command_json()` 只入队 host command不直接改变 LinuxCNC task/motion 语义状态。
3. `lctask_read_status_json()` 只导出最后一次 status write不推进 cycle、不重新读取 motion、不触发 command 执行。
4. 核心状态保存在 C/C++ 结构体、枚举、队列和周期函数中;当前集中容器为 `StandaloneEmcStatus`
5. motion 状态通过 `LcmotStatusSnapshot` 在 task 周期内读入,再映射到 `StandaloneEmcStatus.motion`
6. JSON 字段可以兼容旧 SDK/UI但必须从核心结构体导出不能成为新的事实源。
7. 若 LinuxCNC 上游源码已有对应语义,优先接入 vendored source 或窄 shim不在 JS/JSON 中重写。
## 当前事实源
当前阶段的事实源如下:
- task cycle skeleton`linuxcnc_task_hal_wasm.cpp` 中的 command read、plan、execute、motion update、subordinate sync、task update、status write。
- task/motion/io/top status`StandaloneEmcStatus`
- motion runtime snapshot`LcmotStatusSnapshot``lcmot_read_status_snapshot()`
- RUN 主路径staged program -> `emcTaskPlanRead()` -> `emcTaskPlanCommand()` -> `emcTaskPlanExecute()` -> `emccanon.cc` command envelope -> `taskintf.cc` motion issue。
- JSON status`statusSource=StandaloneEmcStatus` 的外部导出视图。
status JSON 的 LinuxCNC `EMC_STAT` 字段映射、兼容策略和后续 SJ 批次见 `12-status-json-LinuxCNC对标方案.md`
当前 `12-status-json-LinuxCNC对标方案.md` 中 SJ-1 到 SJ-5 已补入 `04-任务矩阵.md` 的 T-051 到 T-055并已闭合。后续不得再只用“后续路线”描述实际任务凡是出现可执行实现项必须同步进入任务矩阵。
## 后续完善路线
后续 WASM 程序完善应按以下顺序拆成新任务:
1. 扩展 `StandaloneEmcStatus` 字段覆盖,而不是扩展 status JSON 自有字段。
2. 将更多 `TaskRuntime` 分散字段迁移到 task/motion/io/top status 容器。
3. 继续把 plan/execute 分支替换为 vendored `emctask.cc``taskintf.cc``emccanon.cc` 的 source-anchored 子集。
4. 扩展 `taskintf.cc` usrmot shim使 motion command/status/config/error 的映射更接近上游。
5. 评估 `emc_nml.hh` 的分阶段 typedef 或窄编译复用,但不得为了 readiness 提前引入完整 native NML/process topology。
6. 将新增状态字段同步补齐 WASM smoke、SDK smoke、state matrix 和 source reuse/drift docs gate。
7. 只有在完整 native task/HAL/runtime 边界被实际采用并验证后,才能提升 `nativeTaskReady``nativeHalSyncReady``fullLinuxCncProgramExecutionReady`
本轮已闭合的 status JSON 子任务:
- T-051 / SJ-1`emcStatus.motion.traj`
- T-052 / SJ-2task current/read/motion line 和 call level。
- T-053 / SJ-3`emcStatus.motion.axis[]``joint[]`
- T-054 / SJ-4`emcStatus.io.aux/tool/coolant` 窄边界。
- T-055 / SJ-5`tools/verify_task_status_json_contract.sh`
## 代码修改检查清单
每次按本路线改 WASM runtime 时,至少检查:
- 新状态是否有 C/C++ 结构体字段,而不是只新增 JSON 字段。
- 新 command 是否先入队,再由 `lctask_run_cycles()` 消费。
- 新 status JSON 字段是否从 `StandaloneEmcStatus` 或明确的 C/C++ status buffer 导出。
- JS/SDK 是否只做边界包装和兼容 API。
- 是否新增或更新 `tools/verify_task_*` gate。
- 是否同步更新 `03-推进台账.md``05-验收证据.md``06-决策记录.md`
## 验收要求
后续实现任务完成时,至少运行:
```bash
cd /home/mes123456/cnc_wams/wasm-port
./tools/verify_task_full_closure.sh
git diff --check
```
如任务新增专用 gate应先运行专用 gate再运行 full closure gate。

View File

@@ -0,0 +1,242 @@
# 12-status JSON LinuxCNC对标方案
## 目标
本方案用于后续在 WASM 中完善 `status JSON`:对标 LinuxCNC 的 `EMC_STAT` / status buffer 模型,在 WASM/C++ 内维护结构化 status 事实源,再把最后一次 status write 序列化为 JSON 给 JS/SDK/UI 读取。
`status JSON` 不是 LinuxCNC 语义实现层。它是浏览器/Node host 无法直接读取 native NML/CMS status channel 时的外部通信格式。
## LinuxCNC对标基线
上游 LinuxCNC 的 status 模型来自:
- `/home/mes123456/cnc_wams/linuxcnc/src/emc/nml_intf/emc.hh`
- 定义 `EMC_TASK_MODE``EMC_TASK_STATE``EMC_TASK_EXEC``EMC_TASK_INTERP``EMC_TRAJ_MODE` 等枚举。
- 定义 `EMC_STAT_TYPE``EMC_TASK_STAT_TYPE``EMC_MOTION_STAT_TYPE``EMC_IO_STAT_TYPE` 等 NML 类型编号。
- `/home/mes123456/cnc_wams/linuxcnc/src/emc/nml_intf/emc_nml.hh`
- `EMC_STAT` 聚合 `EMC_TASK_STAT task``EMC_MOTION_STAT motion``EMC_IO_STAT io`
- `EMC_TASK_STAT` 保存 task mode/state、exec/interp state、program line、file、active G/M code、offset、program units、pause 等状态。
- `EMC_MOTION_STAT` 保存 `EMC_TRAJ_STAT traj`、joint、axis、spindle、synch IO、analog IO、soft limit、heartbeat 等状态。
- `EMC_TRAJ_STAT` 保存 enabled、inpos、queue、activeQueue、queueFull、id、paused、single_stepping、position、actualPosition、current_vel、probe、kinematics 等轨迹状态。
- `EMC_IO_STAT` 保存 tool、coolant、aux、fault/reason 等 IO 状态。
上游 GUI 读取的是 status channel 中的 `EMC_STAT` 快照,不是在 GUI 层重建 task/motion 状态机。WASM 中的 JSON 应只模拟“读 status channel 后得到可展示快照”的边界。
## WASM中的等价模型
当前 WASM 侧已建立:
- `StandaloneEmcStatus`
- `StandaloneEmcTaskStatus`
- `StandaloneEmcMotionStatus`
- `StandaloneEmcIoStatus`
- `write_status_snapshot()`
- `lctask_read_status_json()`
后续完善时采用以下固定链路:
```text
LinuxCNC source semantics
-> WASM/C++ task cycle
-> LcmotStatusSnapshot
-> StandaloneEmcStatus
-> write_status_snapshot()
-> lctask_read_status_json()
-> JS/SDK/UI
```
禁止以下链路:
```text
motion JSON -> parse -> task state
status JSON -> parse -> task/motion state
JS/SDK -> compute LinuxCNC task/motion semantics
lctask_read_status_json() -> step servo / read fresh motion / consume command
```
## status JSON职责
`status JSON` 只承担四类职责:
1. 把最后一次 `write_status_snapshot()` 中的状态导出给 JS/SDK/UI。
2. 给浏览器 UI 提供稳定、可版本化、可兼容的字段名。
3. 给 Node/WASM/browser 测试提供可断言的观察面。
4. 保留旧 SDK/UI 兼容字段,同时新增更接近 `EMC_STAT``emcStatus` 对象。
`status JSON` 不承担:
- task 状态机事实源。
- motion 状态机事实源。
- LinuxCNC planner/canon/interpreter 语义。
- queueFull、inpos、abort、estop、pause/resume/step 等语义判断。
## 推荐JSON结构
顶层保留 runtime/readiness 和兼容字段,同时以 `emcStatus` 作为 LinuxCNC 对标主对象:
```json
{
"statusSource": "StandaloneEmcStatus",
"schemaVersion": 1,
"taskTopLevelStatus": "DONE",
"rcsStatus": {
"top": "DONE",
"task": "DONE",
"motion": "DONE",
"io": "DONE"
},
"task": {},
"motionStatus": {},
"emcStatus": {
"source": "StandaloneEmcStatus",
"top": { "status": "DONE" },
"task": {},
"motion": {},
"io": {}
}
}
```
要求:
- `task``motionStatus` 是兼容视图,字段必须来自 `emcStatus` 或同一份 C/C++ status buffer。
- `emcStatus` 是后续新增 LinuxCNC 对标字段的默认入口。
- 新字段优先落在 `emcStatus.task``emcStatus.motion.traj``emcStatus.motion.joint[]``emcStatus.motion.axis[]``emcStatus.io` 中。
- 若必须保留旧字段名,应在测试中断言旧字段与 `emcStatus` 同源一致。
## 字段映射方案
| LinuxCNC字段 | WASM事实源 | JSON位置 | 状态 |
| --- | --- | --- | --- |
| `EMC_STAT.status` / top RCS status | `StandaloneEmcStatus.top_rcs_status` | `emcStatus.top.status``taskTopLevelStatus``rcsStatus.top` | 已有 |
| `EMC_STAT.task.status` | `StandaloneEmcTaskStatus.rcs_status` | `emcStatus.task.status``task.status``rcsStatus.task` | 已有 |
| `EMC_STAT.task.state` | `StandaloneEmcTaskStatus.state` | `emcStatus.task.state``task.state` | 已有 |
| `EMC_STAT.task.mode` | `StandaloneEmcTaskStatus.mode` | `emcStatus.task.mode``task.mode` | 已有 |
| `EMC_STAT.task.execState` | `StandaloneEmcTaskStatus.exec_state` | `emcStatus.task.execState``task.execState` | 已有 |
| `EMC_STAT.task.interpState` | `StandaloneEmcTaskStatus.interp_state` | `emcStatus.task.interpState``task.interpState` | 已有 |
| `EMC_STAT.task.task_paused` | `StandaloneEmcTaskStatus.task_paused` | `emcStatus.task.taskPaused``task.taskPaused` | 已有 |
| `EMC_STAT.task.file` | `StandaloneEmcTaskStatus.open_program` | `emcStatus.task.file``task.file` | 已有 |
| `EMC_STAT.task.currentLine/readLine/motionLine` | staged interpreter + motion snapshot | `emcStatus.task.currentLine/readLine/motionLine` | 已有 |
| `EMC_STAT.task.activeGCodes/activeMCodes/activeSettings` | vendored interpreter/canon state | `emcStatus.task.activeGCodes/activeMCodes/activeSettings` | 后续 |
| `EMC_STAT.task.g5x_offset/g92_offset/toolOffset` | vendored interpreter/canon state | `emcStatus.task.offsets` | 后续 |
| `EMC_STAT.motion.status` | `StandaloneEmcMotionStatus.rcs_status` | `emcStatus.motion.status``rcsStatus.motion` | 已有 |
| `EMC_STAT.motion.traj.enabled` | `LcmotStatusSnapshot.motion_enabled` | `emcStatus.motion.traj.enabled` | 已有 |
| `EMC_STAT.motion.traj.inpos` | `LcmotStatusSnapshot.in_position` | `emcStatus.motion.traj.inpos` | 已有 |
| `EMC_STAT.motion.traj.queue` | `LcmotStatusSnapshot.queue_count` | `emcStatus.motion.traj.queue` | 已有 |
| `EMC_STAT.motion.traj.activeQueue` | `LcmotStatusSnapshot.active_depth` | `emcStatus.motion.traj.activeQueue` | 已有 |
| `EMC_STAT.motion.traj.queueFull` | `LcmotStatusSnapshot.queue_full` | `emcStatus.motion.traj.queueFull` | 已有 |
| `EMC_STAT.motion.traj.id` | `LcmotStatusSnapshot.motion_id` | `emcStatus.motion.traj.id` | 已有 |
| `EMC_STAT.motion.traj.paused` | `LcmotStatusSnapshot.paused` | `emcStatus.motion.traj.paused` | 已有 |
| `EMC_STAT.motion.traj.single_stepping` | `LcmotStatusSnapshot.stepping` | `emcStatus.motion.traj.singleStepping` | 已有 |
| `EMC_STAT.motion.traj.position/actualPosition` | `LcmotStatusSnapshot.axis_cmd/axis_fb` | `emcStatus.motion.traj.position/actualPosition` | 已有 |
| `EMC_STAT.motion.traj.current_vel` | `LcmotStatusSnapshot.current_vel` | `emcStatus.motion.traj.currentVel` | 已有 |
| `EMC_STAT.motion.on_soft_limit` | `LcmotStatusSnapshot.on_soft_limit` | `emcStatus.motion.onSoftLimit` | 已有 |
| `EMC_STAT.motion.joint[]` | `LcmotStatusSnapshot.joint_cmd/joint_fb` | `emcStatus.motion.joint[]` | 已有 |
| `EMC_STAT.motion.axis[]` | `LcmotStatusSnapshot.axis_cmd/axis_fb` | `emcStatus.motion.axis[]` | 已有 |
| `EMC_STAT.io.status` | `StandaloneEmcIoStatus.rcs_status` | `emcStatus.io.status``rcsStatus.io` | 已有 |
| `EMC_STAT.io.aux.estop` | task/io shim | `emcStatus.io.aux.estop` | 已有 |
| `EMC_STAT.io.fault/reason` | `StandaloneEmcIoStatus.error/reason` | `emcStatus.io.fault/reason` | 已有 |
## 后续实施批次
### SJ-1规范 `emcStatus.motion.traj`
状态:已完成,对应 T-051。
目标:把当前 `motionStatus.motion.*` 中已有的 queue、inpos、id、paused、stepping、currentVel 等字段,以 LinuxCNC `EMC_TRAJ_STAT` 名称归入 `emcStatus.motion.traj`
验收:
- `emcStatus.motion.traj.queue` 等于兼容字段 `motionStatus.motion.queueDepth`
- `emcStatus.motion.traj.inpos` 等于兼容字段 `motionStatus.motion.inPosition`
- `emcStatus.motion.traj.id` 等于兼容字段 `motionStatus.motion.id`
- `lctask_read_status_json()` 不新增 motion read 或 servo step。
### SJ-2规范 task line 和 interpreter字段
状态:已完成,对应 T-052。active G/M code、active settings 和 offsets 仍按字段映射表保留为后续 source-anchored 扩展,不计入本 SJ-2 验收。
目标:对齐 `EMC_TASK_STAT.currentLine``readLine``motionLine``callLevel`,让 UI 和测试能分辨 interpreter 已读行、当前执行行和 motion 正在执行行。
验收:
- staged program RUN 后,`emcStatus.task.readLine/currentLine/motionLine` 与现有 plan read/execute/motion id evidence 一致。
- 兼容字段若存在,必须与 `emcStatus.task.*Line` 同源。
### SJ-3规范 `motion.axis[]` 和 `motion.joint[]`
状态:已完成,对应 T-053。`emcStatus.motion.axis``emcStatus.motion.joint` 为数组;按名字访问的兼容视图保留在 `motionStatus.axis``emcStatus.motion.axisByName` 仅辅助迁移。
目标:把当前 axis x/y/z/a/b/c 和 joint0 字段扩展成数组结构,对标 `EMC_MOTION_STAT.axis[]``joint[]`
验收:
- 至少导出存在的 5/6 轴位置和 joint0 command/feedback。
-`motionStatus.axis``motionStatus.joint0` 与新数组值一致。
### SJ-4规范 IO/aux/tool/coolant边界
状态:已完成,对应 T-054。tool/coolant 只暴露 shim/unsupported 边界,不提升 native IO readiness。
目标:将当前 IO shim 状态组织为 `emcStatus.io.aux``emcStatus.io.tool``emcStatus.io.coolant` 的窄对象,未实现字段显式标记为 shim/unsupported而不是省略成语义完成。
验收:
- `emcStatus.io.status``fault``reason``aux.estop` 可观测。
- readiness 仍保持 false不因 JSON 字段存在而宣称 native IO ready。
### SJ-5引入 schema gate
状态:已完成,对应 T-055。
目标:新增专用 gate例如 `tools/verify_task_status_json_contract.sh`,固定 status JSON 字段来自 `StandaloneEmcStatus`,并检查 `emcStatus` 与兼容字段的一致性。
验收:
- gate 检查 `statusSource=StandaloneEmcStatus`
- gate 检查 `lctask_read_status_json()` 不调用 `lcmot_read_status_json()`
- gate 检查 JS/SDK 没有实现 task/motion 语义。
- gate 纳入 `tools/verify_task_full_closure.sh`
## 兼容策略
短期保留:
- `taskTopLevelStatus`
- `rcsStatus`
- `task`
- `motionStatus`
新增字段默认进入:
- `emcStatus.top`
- `emcStatus.task`
- `emcStatus.motion`
- `emcStatus.motion.traj`
- `emcStatus.motion.axis`
- `emcStatus.motion.joint`
- `emcStatus.io`
旧字段只能作为兼容视图,不能作为后续实现的主字段。新增测试应优先断言 `emcStatus`,再断言兼容字段与其一致。
## 文档和测试要求
每完成一个 SJ 批次,需要同步更新:
- `04-任务矩阵.md`
- `03-推进台账.md`
- `05-验收证据.md`
- `06-决策记录.md`
- `07-emctaskmain周期对标蓝图.md`
- `11-WASM核心状态机边界与后续完善路线.md`
- `docs/source-reuse-map.md`
- `docs/compatibility-validation.md`
- 对应 `tools/verify_task_*` gate
默认最终验收命令:
```bash
cd /home/mes123456/cnc_wams/wasm-port
./tools/verify_task_full_closure.sh
git diff --check
```

View File

@@ -0,0 +1,50 @@
# wasm-port task 主循环完全对标推进索引
## 目标
本目录用于推进 `wasm-port` 对标 LinuxCNC `linuxcnc/src/emc/task/emctaskmain.cc` 的 task 主循环,重点补齐每个 task 周期读取 motion 状态并驱动 task 状态机的结构。
当前基线结论:
- 上游 LinuxCNC task 主循环每周期执行 command read、`emcTaskPlan()``emcTaskExecute()``emcMotionUpdate(&emcStatus->motion)`、subordinate sync、`emcTaskUpdate()`、status write。
- `wasm-port` 当前 task-HAL runtime 已闭合本目录任务矩阵:`lctask_run_cycles()` 具备 command read、plan、execute、motion update、subordinate sync、task update、status write 的 LinuxCNC 式周期骨架。
- task status 已由周期内 `LcmotStatusSnapshot``StandaloneEmcStatus` 导出,`lctask_read_status_json()` 只读取最后一次 status write不推进或重新同步 motion。
- RUN 文件主路径已由 staged program 的 plan read/command/execute、`emccanon.cc` command envelope 和 `taskintf.cc` motion issue 驱动host JSON motion plan 仅保留为 timed-plan 兼容/调试入口。
- vendored/upstream `emctask.cc``taskintf.cc``emccanon.cc` 的窄子集已按 T-033 到 T-046 分阶段接入;完整 `emctaskmain.cc`/NML/native HAL/native motion process topology 仍未 promoted。
## 文档索引
| 文件 | 用途 |
| --- | --- |
| `01-项目功能内容.md` | 定义本阶段要实现的功能边界和 LinuxCNC 对标范围。 |
| `02-项目程序开发详细步骤.md` | 拆解从当前 minimal adapter 到 LinuxCNC task 主循环对标的开发步骤。 |
| `03-推进台账.md` | 记录每轮做了什么、改了哪些文件、验证了什么、下一步是什么。 |
| `04-任务矩阵.md` | 维护任务编号、状态、验收标准,防止重复做和口径漂移。 |
| `05-验收证据.md` | 记录命令、报告、截图、页面、job/report id 等证据。 |
| `06-决策记录.md` | 记录关键技术决策和理由,后续变更避免重复争论。 |
| `07-emctaskmain周期对标蓝图.md` | 把上游 `emctaskmain.cc` 周期拆成 WASM 可执行阶段、字段映射和验收要求。 |
| `08-上游task源码替换分解.md` | 拆解 `emctask.cc``taskintf.cc``emccanon.cc` 的函数族迁移顺序、shim 和验收。 |
| `09-emc_nml复用评估.md` | 记录完整 `emc_nml.hh` 直接复用评估、依赖清单和当前窄 status 容器路线。 |
| `10-taskintf-usrmot-shim设计.md` | 设计 `taskintf.cc` usrmot shim 到 `lcmot_*` 的 command/status/config/error 映射。 |
| `11-WASM核心状态机边界与后续完善路线.md` | 固定 WASM/C++、JS/SDK、JSON 的职责边界,并给出后续完善 WASM 核心状态机的任务拆分规则。 |
| `12-status-json-LinuxCNC对标方案.md` | 对标 LinuxCNC `EMC_STAT` / status buffer定义 WASM 中 `StandaloneEmcStatus -> status JSON` 的字段映射、禁止链路和后续实施批次。 |
## 使用方式
1. 每轮实施前先看 `04-任务矩阵.md`,选择 `待办``进行中` 任务。
2. 修改代码或文档后同步更新 `03-推进台账.md`
3. 每条任务完成前,把可复现命令和关键输出写入 `05-验收证据.md`
4. 如改变迁移路线、边界或验收口径,先更新 `06-决策记录.md`
5. 涉及 task 主循环实现时,必须同步查看 `07-emctaskmain周期对标蓝图.md`
6. 涉及上游 task 源码替换时,必须同步查看 `08-上游task源码替换分解.md`
7. 涉及完整 `emc_nml.hh` 复用或 status 容器时,必须同步查看 `09-emc_nml复用评估.md`
8. 涉及 `taskintf.cc` motion bridge 或 usrmot shim 时,必须同步查看 `10-taskintf-usrmot-shim设计.md`
9. 涉及 WASM 程序核心状态机、JS/SDK 边界或 status JSON 时,必须同步查看 `11-WASM核心状态机边界与后续完善路线.md`
10. 涉及 status JSON 字段、SDK status API 或 UI status 展示时,必须同步查看 `12-status-json-LinuxCNC对标方案.md`
11. 每轮结束后遵守仓库 `AGENTS.md`,追加中文执行日志。
## 当前闭合状态
`04-任务矩阵.md` 当前所有任务均为完成,下一条优先任务为“无”。后续继续扩展对标范围时,先在矩阵中新增任务编号、验收标准和 gate再实施代码或文档变更。
后续 WASM 程序完善的默认方向是WASM/C++ 承载核心状态机和 LinuxCNC 语义JS/SDK 承担加载、命令传递、状态读取和文件/OPFS 边界JSON 仅作为 host/browser 通信格式,不作为核心状态机事实源。