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,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`