8.1 KiB
8.1 KiB
02-项目程序开发详细步骤
阶段 0:基线固定
- 记录当前实现与 LinuxCNC 主循环差距。
- 固定当前通过的 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
- 记录当前已知阻塞和 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
- 在
linuxcnc_task_hal_wasm.cpp中新增 task runtime 内部 motion snapshot。 - 在
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。
- 从
linuxcnc_motion_runtime.c暴露结构化读取函数,避免 task 周期内解析 JSON。 - 在
linuxcnc_task_hal_wasm.cpp中新增wasm_emcMotionUpdate(),把LcmotStatusSnapshot映射到 task 持有的EMC_STAT.motion等价结构。 - 在每个
lctask_run_cycles()task 周期调用 motion snapshot update。 - 将 status JSON 改为读取 task 内已更新的 snapshot,而不是独立拼接最新 motion JSON。
- 新增测试:
- 队列中 motion 状态变化必须在
runCycles()后反映到 task status。 - 不调用
runCycles()时,仅调用 status API 不应推进 task 周期语义。 - 直接调用 low-level
lcmot_step_servo()后,task status 不应自动更新,直到下一次lctask_run_cycles()。
- 队列中 motion 状态变化必须在
阶段 2:重排 lctask_run_cycles() 周期顺序
目标顺序:
- task heartbeat / cycle 自增。
- command read:从 staged command queue 或 C ABI command slot 取命令。
- plan:处理模式、run、pause、resume、mdi、home、abort 等 task plan 行为。
- execute:根据 task exec state 向 motion/io 发命令或等待 motion/io 完成。
- motion update:读取 motion runtime snapshot 到 task 状态。
- subordinate sync:处理 estop、motion error、io error、soft limit、abort cleanup 等。
- task update:刷新 task-specific status。
- status write:更新 C ABI 可读 status snapshot。
- servo step:按 standalone WASM 边界推进 deterministic servo cycles。
注意:上游 LinuxCNC 是 native process/realtime 拓扑,WASM 内的 servo step 位置允许作为 standalone runtime 边界记录在决策里,但 task 对外语义必须说明与上游差异。
建议拆成内部函数,避免把所有逻辑堆回 lctask_run_cycles():
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 等价状态容器
- 对齐
EMC_STAT.task、EMC_STAT.motion、EMC_STAT.io中本阶段需要的字段。 - 识别上游真实定义来源:
- enum 和函数声明主要在
emc.hh; EMC_STAT、EMC_TASK_STAT、EMC_MOTION_STAT、EMC_TRAJ_STAT真实字段在emc_nml.hh。
- enum 和函数声明主要在
- 优先复用 vendored
emc_nml.hh/emc.hh类型;如依赖过重,建立字段同名、语义同向的窄StandaloneEmcStatus,并记录差异。 - 把
TaskRuntime中重复字段逐步映射到EMC_STAT.task。 - 把
lcmotmotion status 映射到EMC_STAT.motion。 - 初始 IO 可用 shim 固定
DONE,但必须具备status、aux.estop、fault、reason字段。 - 确保 JSON status 只是
EMC_STAT或等价 status buffer 的导出视图。
阶段 4:迁移 wait/execute 语义
- 对标
emcTaskExecute()的关键状态:DONEWAITING_FOR_MOTION_QUEUEWAITING_FOR_MOTIONWAITING_FOR_IOWAITING_FOR_MOTION_AND_IOWAITING_FOR_DELAYWAITING_FOR_SYSTEM_CMDERROR
- 先迁移 motion 相关状态,不急于实现 system command/process。
queueFull、motion.status、io.status的判断必须从周期 snapshot 读取。- pause/step/resume 的状态变化必须覆盖现有 smoke。
阶段 5:逐步替换自有状态机
- 把当前 JSON command 分派收缩为 host/C ABI 边界。
lctask_send_command_json()不直接修改state/mode/interp/exec,而是入队 command envelope。- 在 command read 阶段消费 envelope,生成 LinuxCNC task command 等价物。
- 把 task plan/execute 语义迁向 vendored/upstream
emctask.cc、taskintf.cc、emccanon.cc。 - 为 native-only/runtime-edge 功能建立 shim:
- NML transport
- file IO
- process spawning
- IO process
- realtime HAL/thread scheduling
- 每替换一段,补一条 matrix 任务和验收证据。
具体源码替换顺序见 08-上游task源码替换分解.md。实施时按以下顺序推进:
taskintf.ccminimal bridge:先替换 motion init/update/abort、traj pause/step/resume/linear move。emctask.ccstate/update/abort:替换 task state/mode/abort/update。emctask.ccplan wrapper:接 interpreter open/read/execute/synch。emccanon.ccstraight motion:接INIT_CANON()、FINISH()、STRAIGHT_TRAVERSE()、STRAIGHT_FEED()。emctaskmain.ccexecute 分支:用interp_list和 taskintf issue command。emccanon.ccspindle/tool/io 子集:dwell、switchkins、tool/spindle command。
阶段 6:readiness 和文档收口
- 修正文档、代码、测试中的 readiness 口径。
nativeTaskReady只有在真实 vendored/native task 周期被采用后才能为 true。nativeHalSyncReady只有在 HAL 同步达到对应验收后才能为 true。fullLinuxCncProgramExecutionReady只有在完整 program execution 语义闭合后才能为 true。- 更新
docs/source-reuse-map.md,避免文档声称与实现不一致。
阶段 7:后续 WASM 核心状态机完善
本阶段用于后续新增任务,不改变 T-001 到 T-049 的闭合状态。实施前必须先在 04-任务矩阵.md 新增任务编号、状态、验收标准和 gate。
- 坚持 WASM/C++ 为核心状态机实现:
- task/motion 状态机、周期调度、状态聚合、命令执行进入 C/C++。
StandaloneEmcStatus或后续EMC_STAT等价容器是 status 事实源。LcmotStatusSnapshot是 task 周期读取 motion 的结构化输入。
- 保持 JS/SDK 为 host 边界:
- JS/SDK 可以加载 WASM、写入文件、入队 command、读取 status。
- JS/SDK 不实现 G-code、task、motion、planner 或 canon 语义。
- 保持 JSON 为通信格式:
- command JSON 只描述 host command envelope。
- status JSON 只导出最后一次 status write。
- 不允许新增依赖 JSON 文本推进 task cycle 的路径。
- 新增 status 字段优先进入
emcStatus对标对象,再按需提供旧字段兼容视图。
- 每次迁移新语义时优先查找 vendored LinuxCNC source:
- 能接入 source-anchored subset 时接入 subset。
- 不能直接接入时建立窄 shim,并在
06-决策记录.md写明原因。
- 每次新增状态字段时同步更新:
- 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。