Use native LinuxCNC homing and consolidate web panel status

This commit is contained in:
2026-09-09 12:28:02 +08:00
parent eb5c58cdb3
commit 0be2ee8ce1
35 changed files with 881 additions and 350 deletions

View File

@@ -45,12 +45,12 @@ digraph LinuxCncAxisWebControlLogic {
source [label="LinuxCNC 源程序\naxis.py · axis.tcl\nemctaskmain.cc · HAL/INI", fillcolor="#f7f1df", color="#b08a2e"];
contract [label="源程序锁定契约\nSOURCE_EXACT · SOURCE_ADAPTER\nSOURCE_BLOCKED · WEB_EXTENSION", fillcolor="#fff5c9", color="#b08a2e", penwidth=2.2];
gesture [label="浏览器控件手势\ndata-axis-control\n82 个文档控制 ID", fillcolor="#edf6f8", color="#3c8091"];
gesture [label="浏览器控件手势\ndata-axis-control\n83 个文档控制 ID", fillcolor="#edf6f8", color="#3c8091"];
react [label="React handler\n只发意图,不是状态权威", fillcolor="#edf6f8", color="#3c8091"];
operation [label="AxisOperationController\noperation_id · ledger\nWeb 通道暂停仍接收合法连续 seq", fillcolor="#eef2fb", color="#526da8"];
gate [label="SimSession command gate\n最终门控与稳定拒绝原因", fillcolor="#fcebdc", color="#bd6a28", penwidth=2.2];
wasm [label="LinuxCNC/WASM 权威\nTask · Interpreter · TP\nIO · Home/Limit · Kinematics", fillcolor="#e9f5e8", color="#43844b", penwidth=2.2];
snapshot [label="Canonical snapshot\naxis_state · ui_gates / gates · motion\nprogram · devices · visual", fillcolor="#e9f5e8", color="#43844b"];
snapshot [label="Canonical snapshot\naxis_state · ui_gates / gates · motion\nprogram · devices · visual · source_status", fillcolor="#e9f5e8", color="#43844b"];
projection [label="React projection\n按钮 enabled/pressed\nDRO · Preview · Diagnostics", fillcolor="#edf6f8", color="#3c8091"];
{ rank=same; source; contract; gesture; react; operation; }
@@ -106,7 +106,10 @@ digraph LinuxCncAxisWebControlLogic {
estop -> off [label="ESTOP active=false"];
off -> on_unhomed [label="POWER active=true"];
on_unhomed -> idle [label="HOME all=true"];
homing [label="MANUAL · HOMING\\ntraj.mode=FREE · interpState=IDLE\\nhoming.c + simple_tp.c\\njoint homing / homed / home-state", fillcolor="#e9f5e8"];
on_unhomed -> homing [label="HOME all/joint"];
homing -> idle [label="全部 homed -> TELEOP"];
homing -> on_unhomed [label="部分回零 / 中止", style=dashed];
idle -> running [label="PROGRAM_RUN"];
running -> paused [label="PROGRAM_PAUSE"];
paused -> running [label="PROGRAM_RESUME"];
@@ -135,7 +138,7 @@ digraph LinuxCncAxisWebControlLogic {
];
manual_controls [
label="手动控制\n\nmanual-axis-x / y / z / a / c (本地选择)\nmanual-jog-increment (本地选择)\nmanual-jog-negative / positive (JOG_START -> release JOG_STOP)\nmanual-home-axis (BOTH: world-axis 拒绝)\nmanual-touch-off (TOUCH_OFF / G10 L20)\nmanual-tool-touch-off (blocked_by_abi_tool_offsets)\nmanual-override-limits (blocked_by_abi)\nmanual-spindle-ccw / stop / cw (SPINDLE_COMMAND)\nmanual-spindle-decrease / increase\n (SPINDLE_COMMAND -> release SPINDLE_CONSTANT)\nmanual-spindle-brake (SPINDLE_BRAKE)\nmanual-coolant-mist / flood (COOLANT_COMMAND)",
label="手动控制\n\nmanual-axis-x / y / z / a / c (本地选择)\nmanual-jog-increment (本地选择)\nmanual-jog-negative / positive (JOG_START -> release JOG_STOP)\nmanual-home-joint-select (数字关节选择)\nmanual-home-axis (HOME joint; 原生 homemod)\nmanual-touch-off (TOUCH_OFF / G10 L20)\nmanual-tool-touch-off (blocked_by_abi_tool_offsets)\nmanual-override-limits (blocked_by_abi)\nmanual-spindle-ccw / stop / cw (SPINDLE_COMMAND)\nmanual-spindle-decrease / increase\n (SPINDLE_COMMAND -> release SPINDLE_CONSTANT)\nmanual-spindle-brake (SPINDLE_BRAKE)\nmanual-coolant-mist / flood (COOLANT_COMMAND)",
fontname="Noto Sans Mono CJK SC",
fillcolor="#e9f5e8",
color="#43844b"

View File

@@ -91,6 +91,8 @@ fingerprinted so the audit fails on an unreviewed source drift:
| `lib/python/glnav.py` | `b2d811a21954966655a40f107c2af217cc7d57bae0dc308dc4698f5859ed3f11` | Orthographic/perspective presets, rotation, camera framing |
| `src/emc/task/emctask.cc` | pinned by submodule commit | Machine state edges and observed `ESTOP`/`ESTOP_RESET`/`ON` state |
| `src/emc/task/emctaskmain.cc` | pinned by submodule commit | Task command acceptance, homing enforcement, run/pause/resume/abort and task-plan reopen/close |
| `src/emc/motion/homing.c` | `ee73d38f2feb8d5523b9a733cb17d635d3904667aaa219f8a02d7fbffee1ba39` | Native joint homing and sequence state machines, compiled into WASM |
| `src/emc/motion/simple_tp.c` | `5a0026f4d5bdd9d1bc55290c6ea9c399abd664633b69413c307f7353953d2603` | Native free-mode joint motion during homing |
| `configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzac-trt.ini` plus `remap_subs/{428,429,430}remap.ngc` | pinned by submodule commit | Selected axes, limits, speeds, startup file and switchkins remaps |
The current local LinuxCNC tree contains unrelated heartbeat instrumentation
@@ -155,7 +157,7 @@ families because their cardinality comes from the selected INI.
| Optional Stop and Block Delete | `toggle_optional_stop`, `toggle_block_delete` | Visible `SOURCE_BLOCKED`; block delete's source wait, MANUAL switch and preview reload must not be approximated by a local checkbox |
| MDI history clear/copy/paste/select/double-click/Up/Down | `clear_mdi_history`, `mdi_history_hist2clip`, `mdi_history_clip2hist`, `mdi_history_butt_1`, `mdi_history_double_butt_1`, `mdi_up_cmd`, `mdi_down_cmd` | Select/Up/Down/local history: `SOURCE_ADAPTER`; clipboard/file persistence variants are browser/host boundaries |
| Calibration, HAL Configuration, HAL Meter, HAL Scope, LinuxCNC Status, Debug Level | external `exec` commands in Machine menu | Desktop-process boundary; not rendered and never mapped to Diagnostics as though it were the same action |
| Home all/joint and Unhome all/joint | `home_all_joints`, `home_joint_number`, `unhome_all_joints`, `unhome_joint_number` | Home all: `SOURCE_ADAPTER`; Web Home Axis maps the fixed XYZAC axis selection to a numeric joint and retains the source KINEMATICS_BOTH restriction; individual joint selection and Unhome remain `SOURCE_BLOCKED` |
| Home all/joint and Unhome all/joint | `home_all_joints`, `home_joint_number`, `unhome_all_joints`, `unhome_joint_number` | Home All and numeric Home Joint: `SOURCE_ADAPTER`, native homemod execution. World-axis requests reject for BOTH. Unhome remains unavailable. |
| Zero P1..P9 and G92 coordinate systems | `clear_offset` | `SOURCE_BLOCKED`; Touch Off is not an alias for clearing a coordinate system |
| Tool touch-off target workpiece/fixture | `toggle_tto_g11` selecting `G10 L10`/`G10 L11` | `SOURCE_BLOCKED` with Tool Touch Off; no local target state is exposed |
| Top/Z2/Side/Front/Y2/Perspective, zoom and rotate | `set_view_*`, `zoomin`, `zoomout`, rotate Tcl command | `SOURCE_ADAPTER`; Y2 is toolbar-only in the native layout |
@@ -163,9 +165,9 @@ families because their cardinality comes from the selected INI.
| Show program, rapids, alpha, live plot, tool, extents, offsets, limits, velocity, DTG | `toggle_show_*`, `toggle_program_alpha` | Program/live/extents/offsets/limits/velocity have adapters; rapids, alpha, tool toggle and DTG are not rendered |
| Grid Off/custom/INI increments, large DRO font, PyVCP, Joint/World | `set_grid_size`, `set_grid_size_custom`, `toggle_dro_large_font`, `toggle_show_pyvcppanel`, `set_teleop_mode` | Not rendered; Joint/World is `SOURCE_BLOCKED`, presentation-only settings are not aliased |
| Clear Live Plot | `clear_live_plot` -> `LivePlotter.clear` -> `positionlogger.clear` | `SOURCE_ADAPTER`; this is the only native live-trace deletion action |
| Axis/joint selection and jog increment | `ja_rbutton`, `jogincrement`, `activate_ja_widget` | XYZAC axis and increment selection: `SOURCE_ADAPTER`; native joint selection is `SOURCE_BLOCKED` |
| Axis/joint selection and jog increment | `ja_rbutton`, `jogincrement`, `activate_ja_widget` | XYZAC axis/increment selection and dedicated numeric homing-joint selection: `SOURCE_ADAPTER`; full joint-mode jogging remains unavailable |
| Jog negative/positive and key jog | `jog_minus`, `jog_plus`, `jog_on`, `jog_off` | `SOURCE_ADAPTER`; press/release semantics and Manual-tab guard apply |
| Home Axis, Touch Off, Tool Touch Off, Override Limits | corresponding `zerohome`/`override` widgets | Home Axis: fixed XYZAC axis-to-joint `SOURCE_ADAPTER` with source mode transaction; Touch Off: selected-coordinate adapter; Tool Touch Off/Override Limits: visible `SOURCE_BLOCKED` |
| Home Axis, Touch Off, Tool Touch Off, Override Limits | `home_joint`, `home_joint_number`, touch-off/override widgets | Home Joint uses explicit numeric selection and native homemod. Touch Off is a coordinate adapter; Tool Touch Off/Override Limits remain blocked. |
| Spindle CCW/Stop/CW, slower/faster, brake | `spindle`, `spindle_decrease`, `spindle_increase`, `spindle_constant`, `brake` | `SOURCE_ADAPTER`; button-state formulas and press/release ordering apply |
| Mist and Flood | `mist`, `flood`, `mist_toggle`, `flood_toggle` | `SOURCE_ADAPTER`; independent canonical IO bits |
| MDI entry, Go, Enter, history activation | `send_mdi`, `send_mdi_command` | `SOURCE_ADAPTER`; source trim, mode and adjacent-history de-duplication apply |
@@ -184,7 +186,7 @@ command are blocked instead of being silently mapped to another operation.
| --- | --- | --- |
| `F1`, `F2`, lowercase `o`, `r`, `t`, `p`, `s`, `Escape`, `Ctrl-r`, `F7`-`F12` | E-stop, power, open, run, step, pause, resume, stop, reload, coolant and spindle handlers | Worker-backed commands where the corresponding control is supported. Display labels remain `O/R/T/P/S`. |
| uppercase `R`, `F` | `task_reverse`, `task_forward` | Source controls are recorded as blocked because the selected WASM program ABI has no reverse/forward command; they are never mapped to Run. |
| `Home`, `Ctrl-Home`, `Shift-Home`, `End`, `Ctrl-End` | selected joint home, home all, zero selected G54 axis, system touch off, tool touch off | Home uses the fixed XYZAC axis-to-joint adapter (and Home All uses the all-joint transaction); system Touch Off has an adapter; zero-G54 and Tool Touch Off are blocked. |
| `Home`, `Ctrl-Home`, `Shift-Home`, `End`, `Ctrl-End` | selected joint home, home all, zero selected G54 axis, system touch off, tool touch off | Home uses numeric joint selection (and Home All uses the native configured joint sequences); system Touch Off has an adapter; zero-G54 and Tool Touch Off are blocked. |
| lowercase `x`, `y`, `z`, `a` | Select the first four source axes | Axis selection adapter. Native AXIS does **not** bind lowercase `c` to C-axis selection; `c` selects continuous jog. C remains selectable only through its radio control. |
| `-`, `=`, arrows/Page keys/`[`/`]` and their Shift variants | `jog_on_map`/`jog_off_map` or selected-axis `jog_minus`/`jog_plus` | Jog key semantics require keydown start and keyup stop. Pointer controls are supported; unavailable key bindings are not reassigned. |
| lowercase `c`, lowercase `i`, uppercase `I` | Continuous, next incremental and previous incremental jog modes | Represented by the jog increment selector; no second machine-mode state is created. |
@@ -219,15 +221,12 @@ command are blocked instead of being silently mapped to another operation.
`motion/control.c:2186` 在执行 ID 改变后暂停 TP,不能“解析一行后永久
冻结”,也不能一次 Step 把全部已排队运动执行完。Web 单步的源码行解析
与原生 NML 指令细分仍是需单独验证的适配边界,不能用行数相同替代运动断言。
5. **回零类型不能混同。** `switchkins.c::kinematicsType()` 始终返回
`KINEMATICS_BOTH`;M429 的 `active_type=0` 不代表 KINEMATICS_IDENTITY。
原生 `home_joint` 在这种配置下只接受数字 joint;直接把世界坐标字母传给
`home_joint` 会被源码拒绝。固定的 XYZAC TRT Web 面板没有原生 joint
单选组,因此 `Home Axis` 使用明确记录的 Web 适配:
`X/Y/Z/A/C -> joint 0/1/2/3/4`,Worker 只把这个映射后的数字 joint
交给 WASM home-limit authority,并在结果中回显 `source_axis`、
`joint` 和 `motion_mode`。它不是把 `KINEMATICS_BOTH` 冒充成
`KINEMATICS_IDENTITY`,也不是用坐标轴字母绕过 joint 约束。
5. **回零采用原生 homemod。** `switchkins.c::kinematicsType()` 始终返回
`KINEMATICS_BOTH`,M429 不改变这一类型。世界轴字母不能作为回零目标;
`manual-home-joint-select` 明确选择数字关节,`manual-home-axis` 保留 ID,
按钮显示 Home Joint,提交 `HOME {joint:0..4}`。Home All 提交
`HOME {all:true}`。WASM 直接编译源 `homing.c` 和 `simple_tp.c`,
不再预览 home-limit 后排一条协调 TP 回零直线。完整语义见下方 Native Homing。
6. **自动恢复标签模式。** `axis.tcl::update_state` 在 ON+IDLE 的状态边沿,
当前 task_mode 为 AUTO 时调用 `set_mode_from_tab`;显式 Open/Reload 完成后
也调用它。Web 必须通过排队的 `SET_MODE` 恢复所选 Manual/MDI 页,不能只
@@ -254,7 +253,7 @@ command are blocked instead of being silently mapped to another operation.
| 功能 | 原生行为 / 当前边界 | 禁止的错误结论 |
| --- | --- | --- |
| Run 警告 | `run_warn` 对 XYZ 预览边界给出确认;当前 WASM 没有完整含刀偏 extents 警告事务 | 不得声称已复制 run_warn 的确认/取消交互 |
| Joint/World、Home Axis | KINEMATICS_BOTH 需要 joint 数字选择与 FREE/TELEOP 状态;固定 XYZAC Web 面板以 X/Y/Z/A/C 的明确一对一映射提供 Home Axis 适配,执行时仍切入 FREE/joint 并由 WASM 返回数字 joint 结果 | 不得用 switchkins 编号判断 kinematics 类型,不得把世界轴字母直接交给 `home_joint`,不得把本地坐标归零冒充 joint home |
| Joint/World、Home Axis | 回零执行使用原生 FREE/homemod;数字关节选择用于 Home Joint,轴选择仍用于世界坐标 Jog/Touch Off | 不得用 X/Y/Z/A/C 偷换 joint,也不得把 M429 当作 KINEMATICS_IDENTITY。完整 Joint/World 点动切换尚未提供。 |
| 速度滑块 | 原生线性/角速度独立,显示物理单位;当前 Jog/Max 的百分比与 6% 下限属于已公开的 Web 适配 | 不得把单一比例视为独立 angular jog 控制 |
| 预览图层 | limits 现从 WASM XYZ 软限位 getter 读取;offsets 使用已实现的 G5x 平移;extents 使用 canonical 采样包围框 | G92/旋转/刀具偏置范围与原生文字标注仍未全量覆盖,不能称完整原生图层复刻 |
| commanded/actual | 仿真当前两者相同,需要分别存在的 canonical 字段才可声明跟随误差显示 | 不得从 React 标签推导真实反馈差异 |
@@ -354,10 +353,10 @@ safety adaptation, not attributed to AXIS.
| DRO coordinate/display/units | local projection | Maps AXIS `coord_type`, `display_type` and `metric` variables; values remain Worker snapshot projections. |
| Preview layers | local projection | `SOURCE_ADAPTER` only where the source variable exists: path=`show_program`, live=`show_live_plot`, limits=`show_machine_limits`, velocity=`show_machine_speed`, offsets=`show_offsets`, extents=`show_extents`. AXIS also has rapids, alpha, tool and DTG controls that the Web does not expose. Toggling visibility never deletes layer data. |
| Manual / MDI tabs | `SET_MODE` | `SOURCE_ADAPTER`: native tab callbacks are `ensure_manual` and `ensure_mdi`, including `set_motion_teleop` transitions. `axis.tcl::update_state` calls `set_mode_from_tab` only when returning to ON+IDLE from a non-idle/task-state transition while task mode is AUTO. No unrelated React effect may force a mode. |
| Joint/World (teleop) mode | not exposed | AXIS View menu calls `set_teleop_mode`/`c.teleop_enable`; the selected WASM motion ABI has no canonical teleop setter, so Web does not pretend its coordinate mode is a joint/world toggle. |
| Joint/World (teleop) mode | not exposed | AXIS View menu calls `set_teleop_mode`/`c.teleop_enable`; WASM now exposes motion mode for homing and task transitions; the full joint/world jog toggle is still not rendered. |
| Jog `-` / `+` | `JOG_START`, `SIM_STEP`, `JOG_STOP` | `SOURCE_ADAPTER`: source requires `manual_ok` and the visible Manual tab. Incremental sends one `JOG_INCREMENT`; Continuous sends one `JOG_CONTINUOUS` and motion continues until the deferred release issues `JOG_STOP`. Web servo sampling is transport/runtime work, not repeated user jog commands. |
| Home Axis | `HOME {axis,joint}` | `SOURCE_ADAPTER`: UI uses the fixed map `x/y/z/a/c -> 0/1/2/3/4`; Worker validates the pair, applies the source `manual_ok` gate, enters MANUAL, switches to FREE/joint for the `c.home(joint)` equivalent, waits for the WASM home-limit result, then publishes the canonical joint mask. An unmapped axis, mismatched joint or invalid numeric joint is rejected before any mode/home mutation. |
| Home All / Re-home All | `HOME {all:true}` | `SOURCE_ADAPTER`: `manual_ok`, ensure MANUAL, if `all_homed()` ask the native re-home confirmation, then switch to FREE/joint, call the WASM equivalent of `c.home(-1)`, wait, and publish all five homed bits. The fixed Web axis adapter restores its prior world-axis presentation mode after the completed transaction; the source mode used for homing is still recorded. Native text remains Home All; the Web `RE-HOME ALL` label is presentation-only and cannot trigger a hidden home during load. |
| Home Axis / Home Joint | `HOME {joint}` | `SOURCE_ADAPTER`: select numeric joint, confirm re-home if applicable, ensure MANUAL, native FREE + `do_home_joint(j)`, then servo-driven `do_homing`/`simple_tp_update`. Letter-axis requests reject for BOTH. |
| Home All / Re-home All | `HOME {all:true}` | `SOURCE_ADAPTER`: manual_ok, ensure MANUAL, re-home confirmation, native FREE + `do_home_joint(-1)`. ACK means accepted; only native homing/homed/home_state establish completion. HOME_SEQUENCE comes from INI. |
| Touch Off | `TOUCH_OFF {axis,value,system,units}` | `SOURCE_ADAPTER`: source UI condition is the Touch Off formula above; task-layer MDI additionally enforces homing unless `NO_FORCE_HOMING`. Prompt for `P0 Current` through `P9 G59.3`, save mode, ensure MDI, scale linear units, issue `G10 L20 <P-token> <axis>[value*scale]`, wait, redraw/reload, restore saved mode and TELEOP. |
| Tool Touch Off | `TOOL_TOUCH_OFF {axis,value,system,units}` | LinuxCNC source requires `G10 L10/L11` plus `G43`, but the selected WASM interpreter does not expose canonical tool-offset storage. The control is therefore disabled with `blocked_by_abi_tool_offsets`; it never sends a fake fixed `G43`. |
| Override limits | disabled | `SOURCE_BLOCKED`: widget enable requires `on_any_limit`; handler separately requires interpreter IDLE. If already overridden it ensures AUTO; otherwise it ensures MANUAL and calls `c.override_limits()`. The selected WASM ABI cannot represent this canonical path. |
@@ -404,15 +403,16 @@ history rows intentionally share the family ID `mdi-history-select`.
| `toolbar-clear-live-plot` | `clear_live_plot` -> `positionlogger.clear()` | Worker `VISUAL_CLEAR`; always visual-only | Advances `live_path_epoch`, clears Live Plot only and retains static preview |
| `workspace-case-select` | Web selection of the INI/configuration input | Local selection; selected catalog is restricted to supported XYZAC case | Does not load or change machine state until `toolbar-load-case` |
| `workspace-load-3d-chips` | Web packaged-file equivalent of `open_file_guts` | Fetch published `3D_Chips.ngc`, then `PROGRAM_LOAD`; IDLE only | Same replacement path as Open; retains Live Plot, no automatic Run/Home |
| `manual-home-all` | Machine Homing menu -> `home_all_joints` | `HOME {all:true}`; `manual_ok`, MANUAL, FREE/joint home, wait, canonical snapshot | Repeat asks source confirmation; Web Re-home label is non-authoritative presentation only; response records the mode phase and five-joint homed mask |
| `manual-home-all` | `home_all_joints` | `HOME {all:true}`; ON+IDLE, no concurrent homing/jog | Native homemod selects the configured sequences. No artificial coordinated return-to-zero motion. |
| `switchkins-0`, `switchkins-1`, `switchkins-2` | `M429`, `M428`, `M430` remaps and `motion.switchkins-type` | `KINEMATICS_SELECT`; ON, homed, IDLE, empty TP | Identity/XYZAC/User K canonical type, or stable gate reason |
| `tab-manual`, `tab-mdi` | AXIS notebook F3/F5 `ensure_manual`/`ensure_mdi` | `SET_MODE` adapter under `manual_ok` | Acknowledged MANUAL/MDI task mode. The Web does not expose a separate Joint/World toggle; Home transactions use an internal FREE/joint phase and restore the selected fixed XYZAC world-axis presentation mode after completion. |
| `tab-manual`, `tab-mdi` | `ensure_manual` / `ensure_mdi` | `SET_MODE`; manual_ok and motion exclusion | Task mode acknowledgement and WASM motion mode are monitored separately; no local tab is mode authority. |
| `tab-diagnostics` | Web diagnostics boundary | Local tab only | Reads Worker state/gates; sends no command |
| `tab-preview`, `tab-dro` | AXIS preview/DRO presentation | Local tab only | Changes visible projection; machine state unchanged |
| `manual-axis-x`, `manual-axis-y`, `manual-axis-z`, `manual-axis-a`, `manual-axis-c` | AXIS axis radio group / `ja_rbutton` | Local axis selection; source manualgroup ON+IDLE | Supplies the selected axis to Jog/Home/Touch Off; sends no motion by itself |
| `manual-axis-x`, `manual-axis-y`, `manual-axis-z`, `manual-axis-a`, `manual-axis-c` | AXIS axis radio group / `ja_rbutton` | Local axis selection; source manualgroup ON+IDLE | Supplies the selected world axis to Jog/Touch Off; sends no motion by itself |
| `manual-jog-increment` | `jogincrement` combobox | Local choice: Continuous or configured increment | Determines `JOG_CONTINUOUS` versus `JOG_INCREMENT` payload only |
| `manual-jog-negative`, `manual-jog-positive` | `jogminus`, `jogplus` -> `jog_on` | `JOG_START`; visible Manual tab and `manual_ok`; source chooses joint/teleop mode from kinematics+homing | Incremental submits once; Continuous remains active until one release/cancel `JOG_STOP` |
| `manual-home-axis` | `home_joint` | UI ON+IDLE; `HOME {axis,joint}` validates the fixed XYZAC mapping, then follows the source MANUAL -> FREE/joint -> home transaction | Selected axis is homed through its mapped numeric joint; already-homed joint asks for explicit re-home confirmation; invalid mapping is rejected without mode/home mutation |
| `manual-home-joint-select` | Native numeric joint Homing selection | Local integer 0..4; same homing gate | Selects only the target joint; no motion command. |
| `manual-home-axis` | `home_joint` / numeric Homing menu | `HOME {joint}`; ON+IDLE and no concurrent motion | Label Home Joint; numeric target only. Native state and motor offset determine the result. |
| `manual-touch-off` | `touch_off_system` | `TOUCH_OFF`; exact Touch Off UI formula, `manual_ok`, valid axis/value/system, plus task-layer homing policy | MDI `G10 L20`, wait, reload and restore saved task/motion mode |
| `manual-tool-touch-off` | `touch_off_tool` | Permanently disabled for selected ABI | `blocked_by_abi_tool_offsets`; never approximated with `G92`/fixed `G43` |
| `manual-override-limits` | `toggle_override_limits` | Permanently disabled for selected ABI | No state mutation; explanatory ABI title |
@@ -449,10 +449,10 @@ React must derive its button gates from that state on the next snapshot.
| `ESTOP(active=false)` | Source toggle requires current status ESTOP | IO E-stop clears; observed source task state becomes `ESTOP_RESET`; Web may display `STOPPED` only as an adapter label | Power is enabled; motion/manual/MDI remain disabled until ON |
| `POWER(active=true)` | Source ON edge is valid only from `ESTOP_RESET`; it does not require interpreter IDLE | Trajectory enables and observed task state becomes ON | Manual group requires ON+IDLE; program Run still meets UI/taskfile adapter and task-layer homing rules |
| `POWER(active=false)` | Source toolbar allows the toggle whenever status is not ESTOP, including active execution | Motion/task/IO abort, trajectory disables, volatile-home joints unhome, task plan synchronizes; taskfile retained | Observed state returns to ESTOP_RESET; nonvolatile homing is not falsely cleared by the UI |
| `HOME(all/axis)` | AXIS homing UI: ON+IDLE; handler `manual_ok`, then MANUAL; `go_home()` selects FREE/joint before `c.home()` | Home authority updates the canonical five-joint `homed[]`; Web axis selection is validated and mapped to one numeric joint for this fixed one-to-one XYZAC case | AUTO's task layer may run only when all required joints are homed unless `NO_FORCE_HOMING=1`; an invalid axis/joint pair never changes mode or home state |
| `HOME(all/joint)` | ON+IDLE, no concurrent homing or jog; ensure MANUAL | FREE mode, original homing sequence and joint state machines; `homing`, `homed`, `home_state`, motor offset and position from WASM | Home is not AUTO execution. INTERP_IDLE does not mean homing is inactive. |
| `PROGRAM_LOAD` | Native Open/Reload requires interpreter IDLE; Web additionally excludes active TP/MDI queue and concurrent parse | Save mode, ensure MANUAL, restore mode, set line 0, synchronize, open/replace taskfile and canon, parse status-derived preview, then apply tab mode | New taskfile/preview replace the old selection. Static preview replacement is independent of Live Plot data. |
| `KINEMATICS_SELECT` | Machine on, homed, idle, TP queue empty, valid type 0/1/2 | M429/M428/M430 selection updates canonical kinematics and the HAL switchkins type | KINEMATICS_BOTH remains unchanged; a non-empty queue blocks selection |
| `SET_MODE(MANUAL)` | Source task rejects leaving active AUTO; tab handler also requires `manual_ok` | Task mode MANUAL acknowledged; explicit joint/teleop switching remains the stated boundary | Manual widgets are still controlled by ON+IDLE, not mode alone |
| `SET_MODE(MANUAL)` | Source task rejects leaving active AUTO; tab handler also requires `manual_ok` | Task mode MANUAL acknowledged; motion mode selects TELEOP when homed, FREE otherwise | Manual widgets are still controlled by ON+IDLE, not mode alone |
| `SET_MODE(MDI)` | Tab handler requires `manual_ok`; task mode transition follows source motion-mode calls | Task mode MDI | MDI widgets use ON+queue-capacity; submission still calls `manual_ok` |
| `PROGRAM_RUN` | Native toolbar formula is ON+IDLE and does not test taskfile. Web adds current-taskfile validation; task acceptance adds all-homed unless `NO_FORCE_HOMING=1`. Completed/aborted are valid idle starts. | `task_run`: warning, ensure AUTO, `AUTO_RUN(start_line)`, reset next start line to 0. Task layer reopens the retained file when plan is closed. | During non-IDLE, native Run relief is pressed and Open/Reload/Run/manual controls disable; on IDLE, direct Run is available again. |
| `PROGRAM_PAUSE` | Source handler: AUTO plus READING/WAITING; combined toolbar: AUTO/MDI plus non-IDLE and not currently paused | Trajectory pauses, previous interpreter state is saved, interpreter becomes PAUSED | Combined toolbar remains enabled and becomes Resume; Stop, E-stop and Power remain enabled by their own formulas |
@@ -628,7 +628,7 @@ Run 仍需用户单独操作,不能因加载文件而自动上电、回零或
| Open、Reload、案例和打包程序 | 四条入口共用 `gates.load`,包含 PAUSED 与活动 TP 队列;Reload 还要求已有 taskfile | 文件读取完成后再次检查门控,再提交一次 `PROGRAM_LOAD` | 用户取消文件选择不发命令;门控已变化则不替换编辑器文本、路径或预览;解析失败属于已选新文件的源码错误 |
| 点动和主轴调速按住按钮 | 主指针按下或聚焦按钮的 Space/Enter 按下;重复 keydown/第二指针不重复提交 | 记录本次手势的 axis/direction/increment 与 release 操作;按下和释放有固定命令顺序 | pointerup/cancel/leave/lost capture、keyup、窗口失焦、页面隐藏、离开 Manual 页只结束同一手势一次;release 早于 ACK 时仍按 start→stop 顺序处理 |
| 坐标轴、步长、DRO、视图、图层、选项卡 | 使用表内本地显示状态;切换 Manual/MDI 另走 `SET_MODE` | 更新选择或投影,不能变更 canonical machine state | 每个选项均验证显示变化;隐藏 Live Plot 不得删除轨迹;旋转、平移和缩放须验证实际画布变化 |
| 系统对刀、重复回零 | 源码门控通过后显示参数/确认对话框 | 确认后只发送一次 `TOUCH_OFF` 或 `HOME` | 取消不发运动/对刀命令;Home All 的原生 ensure MANUAL 在确认之前,Web 确认前模式处理属于适配差异;空白/非有限数字/非法 P 或 G 系统标识不提交 |
| 系统对刀、重复回零 | 源码门控通过后显示参数/确认对话框 | 确认后只发送一次 `TOUCH_OFF` 或 `HOME` | 取消不发运动/对刀命令;Home All 在确认前 ensure MANUAL,单关节重复回零在确认后 ensure MANUAL;空白/非有限数字/非法 P 或 G 系统标识不提交 |
| About 和菜单 | 本地打开、关闭、Escape;About 打开时焦点进入,关闭后返回入口 | 显示/隐藏相应内容 | 弹窗打开期间不触发普通机器快捷键;F1 急停仍可用;关闭动作不触发 Stop |
| ABI/桌面边界控件 | 原生 disabled 属性与明确原因 | 无成功路径 | `SOURCE_BLOCKED` 不得出现机器命令或本地假开关;全部在浏览器清单中检查 |
@@ -792,38 +792,83 @@ block whose target already equals the current canonical pose is a zero-motion
block: it advances the interpreter line but must not enqueue an invalid
zero-length TP segment.
### Homing must execute through the WASM trajectory
### Native Homing and State Monitoring (2026-09-09)
`sim_kinematics_home_limit_home()` and
`sim_kinematics_home_limit_home_joint()` are home-state authorities. They
calculate and commit the canonical homed mask, joint values and forward pose;
they are not a substitute for the LinuxCNC `c.home()` motion command. The Web
must therefore use a two-phase transaction whenever the current pose differs
from the home target:
This section supersedes the former axis-to-joint alias and coordinated-TP
return-to-zero implementation. The reference is the pinned native source,
including the selected INI, not the previous browser tests.
| Requested status | Correct native field / source | Web snapshot |
| --- | --- | --- |
| Task mode | `emcStatus->task.mode` | `source_status.task.mode`: MANUAL/MDI/AUTO |
| Machine state | `emcStatus->task.state` | `source_status.task.state`: STATE_ESTOP/STATE_ESTOP_RESET/STATE_ON |
| Interpreter state | `emcStatus->task.interpState` | `source_status.task.interpState`: INTERP_IDLE/READING/WAITING/PAUSED |
| Motion mode | `emcStatus->motion.traj.mode` | `source_status.traj.mode`: FREE/COORD/TELEOP |
| Motion type | `emcStatus->motion.traj.motion_type` | `source_status.traj.motion_type`: motion classification, not mode |
| Joint homing/homed | `get_homing(j)` / `get_homed(j)`, reflected in joint status | `source_status.joint[j].homing/homed` |
| Joint home state | `homing.c::H[j].home_state`, HAL `joint.N.home-state` | `source_status.joint[j].home_state/home_state_name` |
The native NML joint status does not directly expose a `home_state` member.
WASM reads the original homemod state that drives the HAL pin. Task status
remains the existing WASM task/interpreter adapter; this is not a claim that
the entire NML task process has been ported. Motion mode is stored in WASM.
The visible monitor retains only Task mode, Task state, Interpreter, Motion
mode, Motion type and Homing. Per-joint status, positions, motor offsets and
bounded servo transition history remain in the Worker snapshot for logic and
diagnostics, but their table and history list are not rendered on the panel.
The detailed status strip is the single visible machine-state summary. The
duplicate footer and header operation badge are removed. Connection status
remains separately labelled. The case strip shows the current program basename
with its full path in a tooltip, and renders the command result once. Existing
machine/operation values remain on the main element as data attributes for
browser diagnostics; no control command or gate changes with this layout.
Home Joint, the numeric joint selector and Home All are rendered in the Manual
tab's action area; the standalone Machine sequence heading is not rendered.
```text
HOME click
-> validate ON+IDLE/manual_ok and axis-to-joint mapping
-> ensure MANUAL -> select FREE/joint homing phase
-> WASM kinematics computes target pose without committing home state
-> enqueue one LinuxCNC TP homing move to that target
-> return HOME {homing.phase:"moving"}; keep current pose and homed state
-> browser scheduler sends SIM_STEP task/servo ticks
-> TP reaches target and queue becomes empty
-> commit sim_kinematics_home(_joint)
-> synchronize interpreter/TP canonical position
-> restore the prior Web presentation mode
-> publish HOME {homing.phase:"complete", wasm_home_limit, pose}
HOME(all/joint)
-> ON+IDLE and no active motion; ensure MANUAL
-> native FREE, do_home_joint(-1 or numeric joint)
-> ACK: accepted; does not mean homed
-> servo cycle: original do_homing() then simple_tp_update()
-> forward kinematics of resulting joint coordinates
-> synchronize coordinated planner coordinate origin to native result
-> publish homing/homed/home_state and motor position
-> native all-homed edge: control.c switches to TELEOP; partial home remains FREE
-> native homing inactive: synchronize interpreter
```
When the current pose already equals the target, the transaction may commit in
the same command because there is no motion segment to execute. A Home request
must never call `setPosition()` to jump the TP to zero, must never change the
React pose locally, and must never advance `home_sequence` before the queued
motion has completed. `HOME ALL` targets all five configured joint home values;
`Home Axis` targets only the mapped joint and lets the selected XYZAC
kinematics calculate the resulting world pose. A pending home blocks another
Home until its queue has completed or an ESTOP/Power Off aborts it.
`HOME_SEARCH_VEL=0` and default `HOME_LATCH_VEL=0` select home-at-current-
position (`homing.c:805`). `HOME_SET_SWITCH_POSITION` adjusts joint coordinates
and motor offset without moving the motor. The final move targets INI HOME
through the joint `free_tp` (`homing.c:1248`). In the selected XYZAC INI,
HOME and HOME_OFFSET are zero; re-home after Jog can therefore reset displayed
joint coordinates with unchanged physical motor position. This is native
behavior. It must not be replaced by G0, G53 or a coordinated TP line to zero.
A nonzero HOME relative to HOME_OFFSET executes a real native free_tp final
move. Search/index inputs use homemod inputs; the selected browser fixture
has no physical switches. Unlock hardware is unsupported and configurations
requiring it are rejected, rather than faking an unlocked device.
Home completion never follows coordinated queue depth. Abort, ESTOP and power
off cancel homemod; aborted joints do not become homed. Power off additionally
applies VOLATILE_HOME. During homing, conflicting Run/MDI/Jog/Load/mode/recovery
requests reject, while status sampling and abort remain available. These extra
Web UI exclusions are explicit adapters around the native button formulas.
`visual.pose_epoch` follows native home command sequence. It invalidates stale
display playback without clearing Live Plot. Neither this sequence nor the
displayed zero value is evidence of homing completion.
Validation boundary: the native homing state round-trip preserves joint/motor
positions and offsets. The existing general recovery audit still reports
`endpoint_at_checkpoint_equal=false` for planner/HAL fields; a roughly 7.7 MB
full-history RECOVER envelope also exceeds the existing ccall-array stack
boundary. These are not closed by this homing change and must not be included
in claims of full recovery parity. Native homing checkpoint bytes are stored
sparsely to avoid copying unused joint compensation tables into JSON.
### Touch-off command encoding
@@ -902,7 +947,7 @@ caller with its obsolete flag. Clear Live Plot is an explicit user operation.
1. `web/worker/sim-session.mjs` is the command gate and transaction boundary.
2. `web/worker/wasm-linuxcnc-tp.mjs`, `wasm-program-runtime.mjs`,
`wasm-xyzac-io.mjs` and `wasm-xyzac-device-io.mjs` are the only authorities
`wasm-native-homing.mjs`, `wasm-xyzac-io.mjs` and `wasm-xyzac-device-io.mjs` are the only authorities
for selected-case motion, interpreter and device state.
3. `web/react/src/App.tsx` may render a button disabled from a gate snapshot,
but a Worker gate is still mandatory because UI state can be stale.
@@ -930,14 +975,14 @@ caller with its obsolete flag. Clear Live Plot is an explicit user operation.
Focused evidence for this contract is kept in
`web/worker/test_xyzac_touch_off_source_flow.mjs`,
`web/worker/test_xyzac_home_source_flow.mjs`,
`web/worker/test_native_homing.mjs`,
`web/worker/test_xyzac_panel_buttons.mjs` and
`scripts/test_xyzac_panel_buttons_browser.mjs`. The completed/aborted direct
rerun contract is covered by `web/worker/test_xyzac_program_rerun.mjs` and the
direct visible Jog -> Home Axis/Home All sequence at
`scripts/test_xyzac_home_reset_browser.mjs` records the in-flight TP pose,
queue depth and final zero pose on the local `:5175` panel.
published-site execution sequence is covered by
rerun contract is covered by `web/worker/test_xyzac_program_rerun.mjs`. The
direct visible Jog -> Home Joint/Home All sequence at
`scripts/test_xyzac_home_reset_browser.mjs` records native homing transitions,
joint coordinates and unchanged motor positions for no-search homing on the local `:5175` panel.
The published-site execution sequence is covered by
`scripts/test_xyzac_program_execution_browser_strict.mjs`.
The source-surface audit is enforced by `scripts/test_axis_control_contract.mjs`.
The press/release, focus-loss, MDI history, modal keyboard and desktop/mobile
@@ -948,8 +993,8 @@ OFF/ESTOP overrides and the source mode transitions against real WASM.
`update_state` procedure across 576 combinations and compares 13 widget
predicates (7488 assertions), rather than comparing two rewritten formulas.
`web/worker/test_axis_source_execution.mjs` verifies repeated Step, queued
motion Step, WAITING/MDI Pause-Resume, source OFF state, fixed XYZAC
axis-to-joint Home Axis mapping and spindle override 0-to-100 restoration using
motion Step, WAITING/MDI Pause-Resume, source OFF state, KINEMATICS_BOTH
world-axis rejection and spindle override 0-to-100 restoration using
the actual WASM runtime.
The exhaustive control-ID audit is enforced by
`scripts/test_axis_control_inventory.mjs` and

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 MiB

After

Width:  |  Height:  |  Size: 2.6 MiB