12 KiB
12 KiB
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 snapshot,SDK read 只读该 snapshot |
WASM 周期骨架
目标伪代码:
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、activeSettingsg5x_offset、g92_offset、rotation_xy、toolOffsetsynch_di、synch_do、analog_input、analog_output- spindle orient state/fault
- toolchanger fault/reason
command read 对标
当前 lctask_send_command_json() 直接修改 task state 或 forward motion。目标结构:
lctask_send_command_json()只把 JSON 解析成 task command envelope,写入 WASM command buffer。lctask_run_cycles()内的 command read 阶段消费一条 command。- command read 成功后清
taskPlanError和taskExecuteError。 - command 的语义处理转入
wasm_emcTaskPlan()或wasm_emcTaskIssueCommand()。
验收:
- 调用
sendCommand()后不调用runCycles(),task state 不发生 LinuxCNC 语义变化。 - 调用一次
runCycles()后,command 被计划/执行,状态变化出现。
plan 对标
第一阶段 plan 只迁移现有已支持命令:
EMC_TASK_SET_STATEEMC_TASK_SET_MODEEMC_TASK_PLAN_RUNEMC_TASK_PLAN_PAUSEEMC_TASK_PLAN_RESUMEEMC_TASK_PLAN_STEPEMC_TASK_ABORTEMC_TASK_PLAN_EXECUTEEMC_JOINT_HOMEEMC_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 对标
必须新增结构化边界,建议名称:
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 cycle,status 不应被 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 对标
第一阶段需要覆盖:
motion.traj.enabled从 true 到 false 时,清 homed 或记录 volatile-home TODO。io.aux.estop == true且 motion enabled 时,执行 traj disable、task abort、io abort、spindle abort shim、plan synch。motion.status == ERROR && motion.on_soft_limit时,进入 soft-limit reporting path。motion.status == ERROR或 hard IO error 时,执行 abort cleanup。- 根据 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 不回退。
- 新增至少一个对标断言。