Files
cnc_wams/wasm-port/working/10-taskintf-usrmot-shim设计.md
2026-07-10 03:22:55 -04:00

192 lines
8.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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`
- `runtime/core/linuxcnc_task_subset/taskintf_wasm_subset.hh`
- `runtime/core/linuxcnc_task_subset/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`