8.3 KiB
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.hlinuxcnc/src/emc/motion/usrmotintf.cclinuxcnc/src/emc/task/taskintf.cc
WASM runtime 锚点:
runtime/core/linuxcnc_wrap/linuxcnc_motion_runtime.hruntime/core/linuxcnc_wrap/linuxcnc_motion_runtime.cvendor/linuxcnc/src/emc/task/taskintf_wasm_subset.hhvendor/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:
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 |
已有底层 ABI,ack 语义需降级 |
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) 做三件事:
- 校验 motion id。
- 写入 shared memory command slot。
- 轮询
usrmotReadEmcmotStatus(),等待commandNumEcho和commandStatus。
WASM shim 的 T-033 最小实现合同:
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_ABORTemcTrajPause()/EMCMOT_PAUSEemcTrajStep()/EMCMOT_STEPemcTrajResume()/EMCMOT_RESUMEemcTrajLinearMove()/EMCMOT_SET_LINEemcJogIncr()/EMCMOT_JOG_INCRemcJointHome()/ homing command envelopeemcMotionSetAout()/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 语义必须保持这一点:
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 设计结论:
usrmotReadEmcmotConfig(s)
-> lcmot_read_config_snapshot(&config)
-> map config to emcmot_config_t subset
T-033 已新增窄实现:
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);
如果后续替换或重命名该 API,shim 不能假装 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 设计结论:
usrmotReadEmcmotError(e)
-> lcmot_read_error_message(e, EMCMOT_ERROR_LEN)
T-033 已新增窄实现:
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 实施入口
- T-033 已在
taskintf_wasm_subset中新增lc_taskintf_subset_motion_init()、lc_taskintf_subset_motion_update()、lc_taskintf_subset_motion_abort()。 - T-033 已新增
lcmot_read_config_snapshot()与lcmot_read_error_message()。 - T-033 已让
lctask_init_session()、task-cycle motion update 和 task abort path 通过 shim 访问 motion runtime。 - 继续保持 task status read 和 motion status read 的周期隔离:外部
lctask_read_status_json()不触发新的 motion update。 - 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_errorboolean 当成usrmotReadEmcmotError()的错误队列。 - 不把 T-032/T-033 的 usrmot shim 解释为
nativeTaskReady=true或nativeHalSyncReady=true。