1074 lines
95 KiB
Markdown
1074 lines
95 KiB
Markdown
# LinuxCNC AXIS Web Control Panel Source Logic
|
||
|
||
Status: source-locked contract; verified paths and open source gaps are recorded separately
|
||
Scope: the selected `XYZAC TRT` Web/WASM panel and its LinuxCNC-compatible
|
||
Worker command path
|
||
Source baseline: LinuxCNC submodule `239dcf4284762ad7e9c65d390bc5524d855c2f8e`
|
||
|
||
执行顺序:**源程序核对 → 完善本流程文件 → Worker/WASM 实现 → Web 控件实现 → 逐控件验收**。
|
||
本文件覆盖当前 XYZAC TRT Web 面板的全部交互控件,包括按钮、菜单、
|
||
选项卡、单选框、复选框、滑块、输入框、文件选择和弹窗。下文的稳定控件 ID
|
||
是实现与验收的连接点;源码中的桌面专属功能和 ABI 缺口必须保留明确记录,
|
||
不得把“已列入文档”或“按钮已禁用”计为功能完成。
|
||
|
||
Relationship map: [`linuxcnc-axis-web-control-panel-source-logic.png`](linuxcnc-axis-web-control-panel-source-logic.png)
|
||
|
||
Reproducible graph source: [`linuxcnc-axis-web-control-panel-source-logic.dot`](linuxcnc-axis-web-control-panel-source-logic.dot)
|
||
|
||
This document is the control-flow authority for the Web panel. A button is
|
||
implemented only when its complete path is defined here:
|
||
|
||
```text
|
||
browser gesture
|
||
-> React handler
|
||
-> AxisOperationController operation
|
||
-> SimSession command gate
|
||
-> LinuxCNC/WASM task, interpreter, TP or IO authority
|
||
-> canonical snapshot
|
||
-> React projection
|
||
```
|
||
|
||
React machine state is never an authority; local presentation and input state
|
||
do not carry that restriction. A rejected Worker command must remain
|
||
rejected in the UI, with the source gate reason visible as the disabled-button
|
||
title and in Diagnostics.
|
||
|
||
"Source parity" has a strict meaning in this document:
|
||
|
||
| Mark | Meaning |
|
||
| --- | --- |
|
||
| `SOURCE_EXACT` | Same user action, source handler, UI enable formula, command ordering and observable result as AXIS. |
|
||
| `SOURCE_ADAPTER` | Browser/WASM transport or presentation differs. The tested machine semantics match the cited source for the explicitly stated domain; omitted domains and stronger Web gates are listed as gaps, not claimed as identical. |
|
||
| `SOURCE_BLOCKED` | AXIS has the action, but the selected WASM or browser boundary cannot represent its canonical state. It stays disabled or absent and is never emulated with local state. |
|
||
| `WEB_EXTENSION` | No corresponding native control or automatic flow exists. Its differences must be explicitly documented and never counted as source parity. Automatic file-load clearing has been withdrawn; current clearing follows the native explicit action. |
|
||
|
||
Only `SOURCE_EXACT` and `SOURCE_ADAPTER` count as implemented AXIS parity.
|
||
These marks describe the intended mapping, not a blanket acceptance result.
|
||
The explicit differences below remain open until their end-to-end tests pass;
|
||
a passing source hash or an entry in the inventory does not close a difference.
|
||
`SOURCE_BLOCKED` is an honest capability boundary. `WEB_EXTENSION` is never
|
||
evidence of parity. If this document and the pinned source disagree, the pinned
|
||
source wins and this document, its graph and the Web implementation must be
|
||
updated together.
|
||
|
||
The panel does not add a startup/run alias. The source-defined machine sequence
|
||
is explicit: release E-stop when needed, power on, home, then press the single
|
||
toolbar Run control (or the source `R` shortcut).
|
||
|
||
Native AXIS selects its startup program in this exact priority order:
|
||
positional command-line argument, `AXIS_OPEN_FILE`, `[DISPLAY] OPEN_FILE`, then
|
||
the built-in lathe/mill sample. The browser has no AXIS process argument or
|
||
process environment override, so the selected INI's `[DISPLAY] OPEN_FILE` is
|
||
the first applicable source authority. For `xyzac-trt.ini` it selects
|
||
`./demos/xyzac_switchkins.ngc`. Browser UI persistence must not insert a new
|
||
higher-priority executable source and must never schedule a hidden second
|
||
`PROGRAM_LOAD` after the configured file appears.
|
||
|
||
AXIS has both Machine/View menu bindings and toolbar/notebook bindings. The Web
|
||
surface keeps the toolbar as the single machine-command entry point and the
|
||
notebook tabs as the single view entry point. This removes duplicate buttons;
|
||
the command, gate and source symbol for each retained entry are unchanged.
|
||
|
||
## Source References
|
||
|
||
The primary GUI source is
|
||
`linuxcnc/src/emc/usr_intf/axis/scripts/axis.py`. The accepted command and
|
||
post-completion/abort behavior are also checked against
|
||
`linuxcnc/src/emc/task/emctaskmain.cc`; the Web panel must not stop at the
|
||
Python button handler when the LinuxCNC task layer defines an additional
|
||
transition.
|
||
|
||
### Source-lock manifest
|
||
|
||
The source baseline is the submodule commit above, not a LinuxCNC version name
|
||
or an approximate UI description. The two primary GUI files are additionally
|
||
fingerprinted so the audit fails on an unreviewed source drift:
|
||
|
||
| Source | Baseline SHA-256 | Normative responsibility |
|
||
| --- | --- | --- |
|
||
| `src/emc/usr_intf/axis/scripts/axis.py` | `328c038a1e8fefd952e53c8e398e3fa98b04602351c44318edd1b044e8f63ffa` | Handlers, mode transitions, keyboard bindings, preview and live-plot ownership |
|
||
| `share/axis/tcl/axis.tcl` | `c9f0b4dc686717b37565f85fb0ab8cc8ded9cfa0028cc0aaaccdbcf808c4c524` | Widgets, menu/toolbar wiring and exact dynamic enable formulas |
|
||
| `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
|
||
and an `INTRO_GRAPHIC` substitution. Neither changes the AXIS control flow
|
||
specified here; they are not used to redefine parity.
|
||
|
||
| AXIS source symbol | Role |
|
||
| --- | --- |
|
||
| `manual_ok`, `ensure_mode` | Polling, task-state and mode preconditions |
|
||
| `estop_clicked`, `onoff_clicked` | E-stop and machine power edges |
|
||
| `open_file_guts` | File replacement transaction and mode restoration |
|
||
| `task_run`, `task_run_line`, `task_step`, `task_pause`, `task_resume`, `task_pauseresume`, `task_stop` | Program execution lifecycle |
|
||
| `send_mdi`, `send_mdi_command` | MDI history, mode and command submission |
|
||
| `home_all_joints`, `home_joint` | Homing and joint/kinematics restrictions |
|
||
| `touch_off_system`, `touch_off_tool` | Coordinate/tool offset dialogs and `G10`/`G43` sequence |
|
||
| `spindle`, `spindle_forward_toggle`, `spindle_backward_toggle`, `spindle_increase`, `spindle_decrease`, `spindle_constant` | Spindle direction, speed and brake controls |
|
||
| `mist_toggle`, `flood_toggle`, `brake_on`, `brake_off` | Auxiliary IO controls |
|
||
| `toggle_override_limits`, `cycle_view` | Limit override and preview view selection |
|
||
| `update_state`, `set_mode_from_tab` in `axis.tcl` | Exact widget enable/disable rules and idle mode restoration |
|
||
|
||
The widget wiring is in `linuxcnc/share/axis/tcl/axis.tcl`: File/Machine/View/
|
||
Help menus are at lines 55-464, toolbar bindings at 490-669, manual and MDI
|
||
controls at 839-1288, sliders at 1396-1538, control groups at 1715-1726 and the
|
||
normative `update_state` formulas at 1767-1888.
|
||
|
||
## Source Surface Inventory
|
||
|
||
This inventory separates source controls from the smaller Web surface. A
|
||
source-only or host-bound entry is documented explicitly rather than silently
|
||
replaced by a different action.
|
||
|
||
| Source surface | Source entries | Web treatment |
|
||
| --- | --- | --- |
|
||
| File menu | Open, Recent Files, Edit, Reload, Save As, Properties, Edit Tool Data, Reload Tool Data, Ladder Editor, Quit | Open and Reload are `SOURCE_ADAPTER` toolbar entries. Edit Tool Data and Quit are visible `SOURCE_BLOCKED` entries. The remaining host/file actions are recorded below and are not silently aliased. |
|
||
| Machine menu | E-stop, Power, Run, Run from selected line, Step, Pause, Resume, Stop, Optional Stop, Block Delete, MDI history actions, six desktop tools, Homing, Unhoming, ten zero-coordinate actions and two tool-touch modes | E-stop/Power/Run/Step/Pause/Resume/Stop/Home/Touch Off are represented; every omitted or ABI-blocked source action is recorded below. |
|
||
| View menu | Five preset views, inches/mm, program/rapid/alpha/live/tool/extents/offset/limit/velocity/DTG layers, grid, large DRO font, PyVCP, commanded/actual, machine/relative, joint/world and Clear Live Plot | The menu has five views; the toolbar additionally has inverted-front `Y2`, for six toolbar presets. Supported projections are `SOURCE_ADAPTER`; every omitted view action is recorded below. |
|
||
| Toolbar | E-stop, Power, Open, Reload, Run, Step, Pause/Resume, Stop, Block Delete, Optional Stop, zoom, six views, rotate, Clear Plot | Same source order and icon assets are retained for supported controls; unsupported controls are disabled with a source/ABI reason. |
|
||
| Manual notebook | Axis/joint selector, continuous/increment jog, Home Axis, Touch Off, Tool Touch Off, Override Limits, spindle direction/stop/speed/brake and coolant | XYZAC axis selector, jog, Home Axis, Touch Off, spindle and coolant are represented. Joint selection, Tool Touch Off and Override Limits are explicitly bounded by the selected configuration/ABI. Tool and probe state is read-only; Prepare/Change/Arm/Disarm are IO/HAL operations, not AXIS main-panel controls. |
|
||
| Web case strip | no AXIS equivalent | Exact TRT case loading and the 32-entry RTCP source library are Web workspace controls. Compatible main programs may only call the documented `PROGRAM_LOAD` transaction; support files and other kinematics remain source-view/download entries and must not introduce a second Run/Power/Home flow. |
|
||
| MDI notebook | MDI entry, Go, history selection/double-click, Up/Down history, Ctrl-M/H/Shift-H clipboard operations | Entry, Go and local history are represented; clipboard/file history operations are host/UI-only and are not sent as machine commands. |
|
||
| Help menu/dialogs | About AXIS, Quick Reference, dialog close buttons and website link | About is `SOURCE_ADAPTER`. Quick Reference and the external website link are not rendered; neither is mapped to a machine action. |
|
||
| Bottom controls | Linear jog speed, angular jog speed, max velocity, spindle override, feed override and rapid override | Linear jog, max velocity, spindle and feed are adapters. Angular jog and rapid override are `SOURCE_BLOCKED`; one must never stand in for the other. |
|
||
| Browser UI persistence | AXIS preferences do not override `[DISPLAY] OPEN_FILE` with executable source text | OPFS may persist presentation preferences such as view, zoom, tabs, units and selected axis. It must not persist or automatically load G-code source/path. |
|
||
|
||
The Web surface may remove duplicate menu entries, but it may not change the
|
||
meaning of a retained command. This is why Machine/View menus are not rendered
|
||
when the same source action already has a toolbar or notebook entry.
|
||
|
||
### Exhaustive native-action ledger
|
||
|
||
This ledger accounts for every interactive family constructed by `axis.tcl` or
|
||
bound by `axis.py`. Separators, labels, scrollbars and read-only status text are
|
||
not actions. Dynamically generated joint and grid entries are counted as
|
||
families because their cardinality comes from the selected INI.
|
||
|
||
| Native action family | Source symbols | Parity disposition |
|
||
| --- | --- | --- |
|
||
| File Open/Recent/Edit/Reload/Save/Properties | `open_file`, `open_file_name`, `edit_program`, `reload_file`, `save_gcode`, `gcode_properties` | Open/Reload: `SOURCE_ADAPTER`; Recent/Edit/Save/Properties: browser file/host boundary, not rendered |
|
||
| Tool table edit/reload, Ladder Editor, Quit | `edit_tooltable`, `reload_tool_table`, `classicladder`, `destroy` | Tool editor/Quit: visible `SOURCE_BLOCKED`; reload/Ladder: host boundary, not rendered |
|
||
| E-stop and Power | `estop_clicked`, `onoff_clicked` | `SOURCE_ADAPTER`; exact edge selection and source widget gates apply |
|
||
| Run, Run from line, Step, Pause, Resume, Stop | `task_run`, `task_run_line`, `task_step`, `task_pause`, `task_resume`, `task_pauseresume`, `task_stop` | Run/Step/toggle Pause-Resume/Stop: `SOURCE_ADAPTER`; Run from line is `SOURCE_BLOCKED` until source-line selection is canonical |
|
||
| 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 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 |
|
||
| Inches/MM, commanded/actual, machine/relative | `metric`, `display_type`, `coord_type` | `SOURCE_ADAPTER`; display projection only |
|
||
| 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/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 | `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 |
|
||
| Linear/angular jog speed, max velocity, spindle/feed/rapid override | `update_*slider_vel`, `set_maxvel`, `set_spindlerate`, `set_feedrate`, `set_rapidrate` | Linear jog/max velocity/spindle/feed: `SOURCE_ADAPTER`; angular jog/rapid: `SOURCE_BLOCKED` |
|
||
| About, Quick Reference, clear notifications | About/keys dialogs and `Ctrl-Space` binding | About: local adapter; Quick Reference and notification-clear are not rendered |
|
||
| Case selector/load, packaged programs, RTCP program catalog, Diagnostics, pan/reset buttons, source editor | no AXIS widget equivalent | `WEB_EXTENSION`; may not be counted as AXIS parity |
|
||
|
||
## Source Keyboard Contract
|
||
|
||
The following bindings are copied from `axis.py` lines 3109-3186 and
|
||
`3194-3327`. The source binds lowercase Tk event sequences even though Quick
|
||
Reference displays several letters in uppercase. Keys requiring an unavailable
|
||
command are blocked instead of being silently mapped to another operation.
|
||
|
||
| Key | Source handler | Web treatment |
|
||
| --- | --- | --- |
|
||
| `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 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. |
|
||
| `` ` ``, digits `0`-`9` | Select joints in joint mode; otherwise set feed override from 0% to 100% | Joint-mode selection is blocked. Feed changes, if bound, must use the same mode-dependent meaning. |
|
||
| `,`/`.`; `<`/`>`; `;`/`'` | Linear jog speed; angular jog speed; maximum velocity | Linear jog/max velocity have adapters; angular jog speed is blocked and must not alias linear speed. |
|
||
| `v`, `d`, `!`, `@`, `#`, `$` | Cycle view, rotate, units, display type, coordinate type, teleop mode | View/rotate/units/display/coordinate actions are projected; teleop mode is explicitly unavailable. |
|
||
| uppercase `B`, lowercase `b` | `brake_on`, `brake_off` | Must preserve the distinct source edges; Quick Reference describes them as Shift-B/B. |
|
||
| `Ctrl-K` | `clear_live_plot` | Worker visual-only `VISUAL_CLEAR`. |
|
||
| `Ctrl-S`, `Ctrl-M/H/Shift-H`, `F3`, `F4`, `F5`, `Ctrl-Space` | Save G-code, MDI history, notebook selection and notification clear | Save/clipboard actions are host boundaries; tabs are local navigation plus their documented mode callback; notification clear has no machine effect. |
|
||
|
||
## State Gates
|
||
|
||
### 源码复核修正(2026-09-08)
|
||
|
||
本节更正旧文档中把实现假设写成源码事实的内容;以下定义优先于历史报告。
|
||
|
||
1. **三个门控层分别记录。** `ui_gates` 只按 `axis.tcl::update_state`
|
||
投影按钮公式;`gates` 为最终命令接收条件;React 只额外处理浏览器加载互斥。
|
||
Run 在 ON+IDLE 时启用,即使尚未回零,点击后仍由 task 拒绝;Step 只要求
|
||
ON+taskfile。MDI 输入/Go 的 UI 只要求 ON+队列未满,`send_mdi` 的
|
||
`manual_ok` 不通过时保留输入且不提交。按钮可用不是命令必然成功。
|
||
2. **OFF 是显示字符串。** `axis.tcl` 将 `STATE_ESTOP_RESET` 显示成 OFF。
|
||
source task state 必须为 ESTOP、ESTOP_RESET、ON,不得由 `last_error=-904`
|
||
猜测状态;清除错误或调整覆盖率不能改变机器的 source state。
|
||
同样,task 的 FAULT 标签不能覆盖 IO 的 ready/estop 位变成假 ESTOP。
|
||
3. **WAITING 必须可暂停。** `emctaskmain.cc` 在解释器读完、TP 尚未排空时
|
||
保持 WAITING;Pause 保存原解释器状态,Resume 恢复该状态,不能把已读完
|
||
的程序重新设为 READING。MDI 在其运动执行期间同样是活动任务。
|
||
4. **Step 的三个分支。** `emctaskmain.cc:1059/1149/1224/1299`:IDLE 首次
|
||
Step 从第 0 行启动并暂停;PAUSED 且有运动队列时调用 `emcTrajStep`,
|
||
按执行 ID 推进并再次暂停;无排队运动时释放下一条 task 指令。
|
||
`motion/control.c:2186` 在执行 ID 改变后暂停 TP,不能“解析一行后永久
|
||
冻结”,也不能一次 Step 把全部已排队运动执行完。Web 已将该边界映射为
|
||
`step_phase`、`step_source_line`、`step_target_id` 和
|
||
`step_waiting_for_motion`,并用 WASM execution-id/pose 断言,不以行数相同
|
||
替代运动完成。
|
||
|
||
---
|
||
|
||
### Execute-next-line 流程(源码复核 2026-09-10)
|
||
|
||
原生入口由 `axis.py:2354-2359` 的 `task_step()` 提供,工具栏
|
||
`axis.tcl:535-541` 和快捷键 `T` 都调用同一个函数。处理顺序固定为:
|
||
|
||
```text
|
||
T / toolbar Step
|
||
-> 清除编辑器高亮;若不是 AUTO+IDLE,执行 run_warn(),用户取消则结束
|
||
-> ensure_mode(AUTO)
|
||
-> c.auto(AUTO_STEP)
|
||
-> emcmodule.cc 将 AUTO_STEP 转为 EMC_TASK_PLAN_STEP_TYPE
|
||
-> emctaskmain 根据 interpState 选择 IDLE / READING / PAUSED / WAITING 分支
|
||
-> task/TP 在后续周期执行一个源码边界或一个当前 execution-id
|
||
-> motion/control.c 在 execution-id 改变时暂停 TP
|
||
-> 发布 current_line、execution_line、pose、joints、queue、stepping
|
||
```
|
||
|
||
| 分支 | 原生动作 | Web/WASM 动作 | 响应要求 |
|
||
|---|---|---|---|
|
||
| IDLE 首次 | `AUTO_RUN(line=0)`,随即 `emcTrajPause()`,保存恢复状态 | `WasmProgramRuntime.start()` 后立即 `pause()`;任务从 READY 进入 RUNNING 再进入 PAUSED | `step_phase=start_pause`,源码行 0,不产生运动 |
|
||
| READING | `stepping=1`、`steppingWait=0`,继续 readahead | 只解析一个 WASM canonical source block;有运动时入 TP 并调用 `stepLine()` | `step_phase=source_line_motion` 或 `source_line_pause`,返回 source line 和 `program_steps` |
|
||
| READING/WAITING 或 PAUSED + queue>0 | `stepping=1`;PAUSED 时调用 `emcTrajStep()` | 运行中的 interpreter 先保存为 PAUSED,再按当前 `active_id` 调用 `sim_linuxcnc_tp_step_line()` | `step_phase=motion_step`,`step_target_id` 固定,等待后续 SIM_STEP 到 execution-id 改变 |
|
||
| PAUSED + queue=0 | 释放 `interpResumeState`,保持 task_paused | 恢复 WASM interpreter,执行一个 source block,再暂停 | 不能重读已执行行;状态仍为 PAUSED |
|
||
| WAITING | 设置 stepping,等待队列/输入完成 | 保留 WAITING 的 program status;只推进尚未完成的 TP 或返回 terminal | 不能把 WAITING 改写成 READING |
|
||
| COMPLETED/ABORTED + queue=0 | task plan 可重新从 line 0 运行 | 先重载当前 source 到 loaded、恢复 STOPPED task,再执行 IDLE 首次分支 | `reopened_taskfile=true`,不得触发 STOPPED->RUNNING 非法转换 |
|
||
| stepping 已进行 | 原生 GUI 不应叠加新的运动步 | Web 重复请求返回幂等观察结果,不重复入队 | `step_phase=motion_step_pending`,保留原 `step_target_id` |
|
||
|
||
Web 的 `ui_gates.step` 必须保持源码公式 `STATE_ON && taskfile`,不能增加
|
||
IDLE-only 条件;WASM task gate 仍负责机器状态、回零、程序存在和 AUTO 模式。
|
||
Step 命令本身不推进 logical tick,运动只由后续 `SIM_STEP`/servo 周期推进。
|
||
一个 source block 产生的 canonical motion 必须在同一 Step 事务中进入 TP 并
|
||
进入 stepping;前端收到 `step_waiting_for_motion=true` 后启动已有的采样定时器。
|
||
命令结果必须包含 `program`、`task`、`wasm_motion`、`motion`、
|
||
`step_phase`、`step_source_line` 和 `step_target_id`(无目标时为 `null`),
|
||
以便程序行、执行 ID、轨迹和机床姿态可以共同审计。错误只返回稳定的
|
||
`axis_gate`、`program_step`、`motion_queue` 或 interpreter 错误,不改变已有
|
||
程序、TP 或 live-path epoch。
|
||
|
||
---
|
||
|
||
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 页,不能只
|
||
改标签样式;命令发出后不可让延迟的 effect 覆盖后续 Run。
|
||
7. **Escape 是 task_stop。** 即使 Stop 按钮因 IDLE 禁用,Escape 仍能调用
|
||
`c.abort()`,包括中止手动连续/增量点动和 MDI 运动。菜单/弹窗 Escape
|
||
先结束当前 UI,文本编辑器不得屏蔽机器急停 F1。
|
||
8. **主轴 direction 与输出 RPM 独立。** `motion.h::spindle_status_t.direction`
|
||
是方向命令,覆盖率设为 0 不得把 CCW 投影成 CW;恢复覆盖率时必须恢复
|
||
之前的未缩放速度。按钮按压态读取 WASM direction,调速量作用于未缩放
|
||
的指令速度,再由覆盖率得到输出转速。
|
||
9. **视图按钮必须改变对应内容。** `.toolbar.rotate` 只切换左键 Drag/Rotate,
|
||
不启动自动旋转;`show_machine_speed` 显示规范速度,`show_extents` 显示
|
||
canonical 路径范围;`show_machine_limits` 使用配置到 WASM 的真实 XYZ
|
||
软限位;`show_offsets` 使用 G5x 平移偏置。所有显示均不改机器/程序状态。
|
||
10. **预置投影。** `glnav.py:376-450` 的 Z/Z2/X/Y/Y2 为正交,P 为透视。
|
||
Z2 是顶视图在屏幕平面旋转 -90 度,不是斜俯视。按源码矩阵,屏幕
|
||
right/up 轴依次是 Z=`X/Y`、Z2=`Y/-X`、X=`Y/Z`、Y=`X/Z`、
|
||
Y2=`Z/X`。浏览器坐标变换必须保持此映射。相机取景距离和尺寸缩放是
|
||
显示适配,坐标标记/刀具图形不得在短程序上放大到遮挡路径。
|
||
|
||
### 尚未取得完整等价证据
|
||
|
||
| 功能 | 原生行为 / 当前边界 | 禁止的错误结论 |
|
||
| --- | --- | --- |
|
||
| Run 警告 | `run_warn` 对 XYZ 预览边界给出确认;当前 WASM 没有完整含刀偏 extents 警告事务 | 不得声称已复制 run_warn 的确认/取消交互 |
|
||
| 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 标签推导真实反馈差异 |
|
||
| TOOL_TOUCH_OFF、rapidrate、optional stop、block delete、unhome、桌面工具 | 原文 ledger 中的具体 ABI/host 缺口继续有效 | SOURCE_BLOCKED 只表示已说明边界,不表示功能完成 |
|
||
|
||
以上差异不能通过修改流程文件降低为“源码本来如此”;必须保留来源、真实
|
||
处理方式及未闭合原因。本次改善以已经存在的控件事务为范围,完整 LinuxCNC
|
||
GUI/伺服移植仍不能由此宣称完成。
|
||
|
||
AXIS does not have one combined `RUNNING/STOPPED/READY` enum. Source parity is
|
||
derived from independent LinuxCNC status dimensions; Web-friendly labels may be
|
||
displayed, but they may not replace these dimensions as gate authority.
|
||
|
||
| Source dimension | Exact values used by AXIS | Meaning |
|
||
| --- | --- | --- |
|
||
| `task_state` | `STATE_ESTOP`, `STATE_ESTOP_RESET`, `STATE_OFF`, `STATE_ON` | Machine E-stop/power state. `emctask.cc::determineState()` publishes only ESTOP, ESTOP_RESET or ON; `STATE_OFF` is an accepted command value and is documented by `emcmodule.cc` as not used as a stable status value. |
|
||
| `task_mode` | `MODE_MANUAL`, `MODE_AUTO`, `MODE_MDI` | Current task command domain. |
|
||
| `interp_state` | `INTERP_IDLE`, `INTERP_READING`, `INTERP_PAUSED`, `INTERP_WAITING` | Interpreter lifecycle used by `axis.tcl::update_state`. |
|
||
| `task_paused` / `paused` | Boolean pause projection | Used by `task_resume` and toolbar relief/icon projection. |
|
||
| `exec_state` | `DONE`, `ERROR`, motion/IO/delay/system-command wait states | Task executor progress; it is not interchangeable with `interp_state`. |
|
||
| `motion_mode` | `TRAJ_MODE_FREE`, `TRAJ_MODE_COORD`, `TRAJ_MODE_TELEOP` | Joint/world motion selection and touch-off availability. |
|
||
| `taskfile`, `homed[]`, `on_any_limit`, `queued_mdi_commands`, `spindle[].direction` | Independent status fields | Additional source gates; none may be inferred from a React label. |
|
||
|
||
The source helper definitions are exact:
|
||
|
||
```text
|
||
running = task_mode in {AUTO, MDI} and interp_state != IDLE
|
||
|
||
manual_ok = task_state == ON
|
||
and not running
|
||
and (interp_state == IDLE
|
||
or (task_mode == MDI
|
||
and queued_mdi_commands < max_queued_mdi_commands))
|
||
```
|
||
|
||
`ensure_mode(m, *p)` polls, returns if the current task mode is an accepted
|
||
mode, otherwise sends `c.mode(m)`, waits for completion and polls again. It is a
|
||
command transaction, not a React state assignment and not a success check that
|
||
may be skipped.
|
||
|
||
### Source-exact widget enable formulas
|
||
|
||
These expressions are copied from `axis.tcl::update_state`; handler and task
|
||
checks still apply after a widget is enabled.
|
||
|
||
| Native widget/family | Exact AXIS UI enable condition |
|
||
| --- | --- |
|
||
| E-stop | Always enabled |
|
||
| Power | `task_state != STATE_ESTOP` |
|
||
| Open | `interp_state == INTERP_IDLE` |
|
||
| Reload | `interp_state == INTERP_IDLE && taskfile != ""` |
|
||
| Run | `task_state == STATE_ON && interp_state == INTERP_IDLE` |
|
||
| Step | `task_state == STATE_ON && taskfile != ""` |
|
||
| Pause menu | `task_state == STATE_ON && interp_state in {INTERP_READING, INTERP_WAITING}` |
|
||
| Resume menu | `task_state == STATE_ON && interp_state == INTERP_PAUSED` |
|
||
| Pause/Resume toolbar | `task_state == STATE_ON && interp_state != INTERP_IDLE` |
|
||
| Stop | `task_state == STATE_ON && interp_state != INTERP_IDLE` |
|
||
| Run from selected line | `task_state == STATE_ON && interp_state == INTERP_IDLE && highlight_line != -1` |
|
||
| Homing/Unhoming/Zero-coordinate menus | `task_state == STATE_ON && interp_state == INTERP_IDLE` |
|
||
| Manual group | `task_state == STATE_ON && interp_state == INTERP_IDLE` |
|
||
| MDI group | `task_state == STATE_ON && queued_mdi_commands < max_queued_mdi_commands` |
|
||
| Touch Off | `task_state == STATE_ON && interp_state == INTERP_IDLE && (motion_mode != TRAJ_MODE_FREE || kinematics_type == KINEMATICS_IDENTITY)` |
|
||
| Tool Touch Off | Touch Off condition plus a loaded tool |
|
||
| Override Limits | `on_any_limit` |
|
||
| Spindle slower/faster | `task_state == STATE_ON && interp_state == INTERP_IDLE && spindle.direction != 0` |
|
||
| Feed/spindle/rapid override and max-velocity sliders | No `update_state` disable formula; setters send their command directly. INI and command-layer range/enable rules still apply. |
|
||
| View controls and Clear Live Plot | No machine-state gate |
|
||
|
||
The Web may disable an action while a browser-only asynchronous load is in
|
||
flight. Any other gate stronger than this table must be identified as a Web
|
||
safety adaptation, not attributed to AXIS.
|
||
|
||
`panel_snapshot.ui_gates` 是面向控件的源公式投影,`gates` 为命令接收门控。
|
||
例如原生 abort 命令可随时接收,但 Stop 按钮必须 ON+非 IDLE;冷却命令可在
|
||
执行过程中接收,但 Manual 页冷却复选框必须 ON+IDLE。不能直接把较宽的
|
||
命令接收条件当作控件启用条件。Spindle 与 Touch Off 的源 handler 会自行
|
||
切换模式,不能要求用户预先处于 MANUAL。F9/F10、B/b 用 `source_keyboard`
|
||
传输标记保留不切换模式的源码分支;该标记不绕过 Worker/WASM 门控。
|
||
|
||
## Control Matrix
|
||
|
||
| Panel control | React command | Source flow and required result |
|
||
| --- | --- | --- |
|
||
| Emergency Stop / Cancel | `ESTOP {active}` | `SOURCE_ADAPTER`: `estop_clicked` sends `STATE_ESTOP_RESET` only when status is `STATE_ESTOP`; every other status sends `STATE_ESTOP`. `emcTaskSetState(ESTOP)` aborts motion, spindle, task and IO, disables trajectory, applies volatile unhome and synchronizes the task plan. |
|
||
| Power on / off | `POWER {active}` | `SOURCE_ADAPTER`: `onoff_clicked` sends `STATE_ON` only from `STATE_ESTOP_RESET`; otherwise it sends `STATE_OFF`. Power off aborts motion/task/IO and volatile homes; the subsequently observed source state is normally `STATE_ESTOP_RESET`, not stable `STATE_OFF`. The selected taskfile path remains status data. |
|
||
| Open G-code file | browser file + `PROGRAM_LOAD` | `SOURCE_ADAPTER`: native UI gate is interpreter IDLE. `open_file_guts` polls, saves mode, ensures MANUAL, processes an optional filter, restores saved mode, resets start line/highlight, `task_plan_synch` + wait, `program_open`, replaces the text/canon, constructs status-derived preview init codes, parses, redraws, then calls `set_mode_from_tab`. A parse error is reported against the newly selected file; AXIS does not roll back to the previous canon. |
|
||
| Load case / packaged program / edited source | `LOAD_WORKSPACE` and/or `PROGRAM_LOAD` | `WEB_EXTENSION` entry points. Once a file is selected they must use the Open/Reload adapter and may add a browser-load/queue exclusion while asynchronous parsing is active. Edited text is committed only through Reload; these controls are not native AXIS buttons. |
|
||
| Switchkins Identity / TCP: XYZAC / User K | `KINEMATICS_SELECT {type}` | `SOURCE_ADAPTER` for the selected INI's HALUI MDI commands: `M429 -> type 0`, `M428 -> type 1`, `M430 -> type 2`; each remap executes `M68 E3 Q<type>` then `M66 E0 L0` and verifies `motion.switchkins-type` in task context. The Web's homed/idle/empty-TP gate is a stated safety strengthening around the source MDI/task gate. |
|
||
| Run | `PROGRAM_RUN` | `run_warn`, `ensure_mode(AUTO)`, `AUTO_RUN` from the selected start line, then periodic task/TP ticks. Normal AXIS Run uses line 0. In `emctaskmain.cc`, an ended or aborted task plan is closed; the next `EMC_TASK_PLAN_RUN` reopens the current taskfile and runs from line 0. Therefore Run after `completed` or `aborted` must work directly and must not require a separate Reload/Restart click. |
|
||
| Run from selected line | not exposed | AXIS `task_run_line` requires an editor highlight and source `AUTO_RUN` start line. The Web editor has no source-line selection command yet, so no partial/fake button is rendered. |
|
||
| Reverse / Forward | not exposed | AXIS `task_reverse`/`task_forward` are keyboard-only source actions; the selected WASM program ABI has no corresponding command and Web preserves the distinction from Run. |
|
||
| Step | `PROGRAM_STEP` | `SOURCE_ADAPTER`: source toolbar gate is ON plus taskfile, not interpreter IDLE. `task_step` clears highlight/runs warning unless already AUTO+IDLE, ensures AUTO and sends `AUTO_STEP`. Worker publishes `step_phase` (`start_pause`, `source_line_pause`, `source_line_motion`, `motion_step`, `terminal`) with source line, execution ID, program/task/motion state. Task-layer homing remains authoritative. |
|
||
| Pause / Resume | `PROGRAM_PAUSE` / `PROGRAM_RESUME` | `SOURCE_ADAPTER`: `task_pause` accepts AUTO plus READING/WAITING. `task_resume` requires `paused` plus mode AUTO or MDI. The combined toolbar calls `task_pauseresume`, accepts AUTO or MDI, blocks resume when `resume_inhibit`, and otherwise pauses any non-IDLE interpreter. Web scheduling must serialize the edge but cannot change these state conditions. |
|
||
| Stop | `PROGRAM_ABORT` | AXIS enables Stop only while the interpreter is non-idle; then it highlights the active line, issues `c.abort()`, waits for completion, and clears the abort edge. The Worker may accept an internal abort edge in more states, but the Web button follows the AXIS UI gate. |
|
||
| Block delete / optional pause | disabled | LinuxCNC source has these controls, but the selected WASM ABI does not expose their canonical state. They are visible as disabled, with `blocked_by_abi`, and never emulate a local toggle. |
|
||
| Preview view, zoom, rotate, clear plot | local view or `VISUAL_CLEAR` | `SOURCE_ADAPTER`: view operations do not change task/interpreter/TP/IO. `Ctrl-K` maps `clear_live_plot()` -> `live_plotter.clear()` -> `positionlogger.clear()` and clears only Live Plot; it never deletes the loaded `AxisCanon` preview. Native Run, Stop, completion and Open/Reload do not call this clear path. |
|
||
| 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`; 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 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. |
|
||
| Spindle CCW / stop / CW | `SPINDLE_COMMAND` | `SOURCE_ADAPTER`: `manual_ok`, ensure MANUAL, then `c.spindle(0)` or `c.spindle(direction, default_spindle_speed)`. Pressed state comes from canonical `spindle[0].direction`, not an RPM-sign inference. |
|
||
| Spindle - / + | `SPINDLE_COMMAND {delta}` → `SPINDLE_CONSTANT` on release | AXIS binds Button-1 to `spindle_decrease`/`spindle_increase` and ButtonRelease to `spindle_constant`; Web preserves this press/release sequence. |
|
||
| Brake | `SPINDLE_BRAKE` | Source brake command, gated by `manual_ok`. |
|
||
| Mist / Flood | `COOLANT_COMMAND` | `SOURCE_ADAPTER`: manual checkboxes belong to the ON+IDLE manual group and call `c.mist(value)`/`c.flood(value)` directly. F7/F8 poll status and send the inverse canonical bit. |
|
||
| Tool / probe status | read-only | AXIS does not put Prepare/Change/Arm/Disarm buttons in this manual notebook. Tool changes remain interpreter/MDI and IO/HAL operations. Web displays canonical tool/probe state but exposes no extra main-panel command buttons. |
|
||
| Jog Speed | `SET_JOG_SCALE` | `SOURCE_ADAPTER`: the slider changes AXIS's linear jog-speed value used by subsequent jog commands; it is not itself a motion command and has no `update_state` power gate. |
|
||
| Angular Jog Speed | not exposed | AXIS has a separate `ajogspeed` control for rotary joints; the selected WASM TP exposes one shared jog scale only, so the Web panel does not alias linear Jog Speed to this control. |
|
||
| Feed Override | `SET_OVERRIDE` | `SOURCE_ADAPTER`: `set_feedrate` sends `c.feedrate(percent/100)` without a machine-state UI gate. Selected INI `MAX_FEED_OVERRIDE=2` makes the range 0-200%. Web debouncing may coalesce pointer events but must preserve the last ordered value. |
|
||
| Spindle Override | `SET_SPINDLE_OVERRIDE` | `SOURCE_ADAPTER`: `set_spindlerate` sends `c.spindleoverride(percent/100)` without an `update_state` power gate. Its maximum defaults to MAX_FEED_OVERRIDE when `MAX_SPINDLE_OVERRIDE` is absent. |
|
||
| Max Velocity | `SET_MAX_VELOCITY` | `SOURCE_ADAPTER`: `set_maxvel` converts display units and sends `c.maxvel(value/60)` without an `update_state` power gate. The selected WASM TP exposes this as its velocity limit/scale. |
|
||
| Rapid Override | disabled | AXIS `set_rapidrate` calls `c.rapidrate` and is distinct from Max Velocity. The selected WASM TP has no rapid-scale setter, so the Web control is disabled with `blocked_by_abi_rapidrate`. |
|
||
| MDI command/history | `MDI_EXECUTE` | `SOURCE_ADAPTER`: `send_mdi` validates `manual_ok`; nonempty text is trimmed, the entry cleared, MDI mode ensured, and the command is inserted unless it equals the immediately preceding history entry, then `c.mdi(command)` is sent. A single click selects history; native double-click executes it. |
|
||
| File tool-data editor / Quit | disabled | AXIS launches a host editor or terminates the desktop process. Browser controls remain visibly disabled with `host_boundary_tool_editor` / `host_boundary_process_quit`; clicking them cannot report a false success. |
|
||
| About AXIS | local dialog | `SOURCE_ADAPTER`: mirrors the source `.about` open/OK-close action and changes no Worker/task/TP/IO state. The native website link is a separate external-host action. |
|
||
|
||
## Complete Web Control Inventory
|
||
|
||
Every rendered actionable element has a stable `data-axis-control` value. This
|
||
table is exhaustive for the selected XYZAC panel. A control may not be added to
|
||
React until its ID, source mapping, gate and result are added here. Repeated MDI
|
||
history rows intentionally share the family ID `mdi-history-select`.
|
||
|
||
| Control ID(s) | Source mapping | Operation and gate | Accepted result / disabled behavior |
|
||
| --- | --- | --- | --- |
|
||
| `menu-file`, `menu-help` | `axis.tcl` File/Help cascades | Local menu disclosure; always available | Opens/closes menu only; no machine state change |
|
||
| `menu-file-edit-tool-data`, `menu-file-quit` | `edit_tooltable`, `quit` host process operations | Permanently disabled in a browser | `host_boundary_tool_editor` / `host_boundary_process_quit`; no fake status success |
|
||
| `menu-help-about`, `about-close` | `.menu.help` About entry and `.about.ok` | Local modal open/close | About visibility changes only |
|
||
| `toolbar-estop` | `.toolbar.machine_estop` -> `estop_clicked` | `ESTOP {active}`; accepted from every task state | Toggle source E-stop edge; active edge aborts interpreter/TP |
|
||
| `toolbar-power` | `.toolbar.machine_power` -> `onoff_clicked` | `POWER {active}`; source widget enabled whenever status is not ESTOP | Send ON only from ESTOP_RESET, otherwise OFF; stable post-off status normally projects ESTOP_RESET |
|
||
| `toolbar-open`, `program-file-input` | `.toolbar.file_open` -> `open_file`/`open_file_guts` | File picker then `PROGRAM_LOAD`; interpreter must be IDLE | Replaces static program preview; retains Live Plot exactly as native Open |
|
||
| `toolbar-load-case` | `WEB_EXTENSION`; uses INI `DISPLAY`, `HAL`, `KINS` and `OPEN_FILE` inputs | `LOAD_WORKSPACE` then Open adapter; IDLE plus browser async/queue exclusion | Reloads the selected exact case; never counts as an AXIS control or adds Power/Home/Run aliases |
|
||
| `toolbar-reload` | `.toolbar.reload` -> `reload_file` | `PROGRAM_LOAD` of current editor source/path; IDLE taskfile required | Replaces preview/interpreter at line 0; retains Live Plot whether or not source text changed |
|
||
| `toolbar-run` | `.toolbar.program_run` -> `task_run` | `PROGRAM_RUN`; native widget ON+IDLE; task layer additionally requires a taskfile and homing unless `NO_FORCE_HOMING=1` | AUTO/READING from line 0; completed/aborted taskfile reopens directly |
|
||
| `toolbar-step` | `.toolbar.program_step` -> `task_step` | `PROGRAM_STEP`; native widget ON+taskfile, then handler/task gates | AUTO_STEP at the next source boundary; do not add an IDLE-only UI gate |
|
||
| `toolbar-pause-resume` | `.toolbar.program_pause` -> `task_pauseresume` | Native widget ON+non-IDLE; handler distinguishes `paused` and accepts AUTO/MDI | One source toggle whose icon/label and command follow canonical pause state and resume-inhibit |
|
||
| `toolbar-stop` | `.toolbar.program_stop` -> `task_stop` | `PROGRAM_ABORT`; native widget ON+non-IDLE | Highlight AUTO running line when nonzero, abort, wait, retain selected taskfile |
|
||
| `toolbar-block-delete`, `toolbar-optional-pause` | Source toolbar toggles | Permanently disabled for selected ABI | `blocked_by_abi`; no React-only toggle |
|
||
| `toolbar-zoom-in`, `toolbar-zoom-out` | `zoomin`, `zoomout` | Local preview camera only | Bounded camera zoom; task/TP unchanged |
|
||
| `toolbar-view-z`, `toolbar-view-z2`, `toolbar-view-x`, `toolbar-view-y`, `toolbar-view-y2`, `toolbar-view-p` | `set_view_z/z2/x/y/y2/p` | Local source view selection | Exactly one pressed view; opens Preview tab; machine state unchanged |
|
||
| `toolbar-rotate` | `.toolbar.rotate` | Local drag/rotate projection | Toggles pressed state and viewer interaction only |
|
||
| `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/XYZBC cases | 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 |
|
||
| `workspace-rtcp-programs`, `rtcp-program-scope`, `rtcp-program-select`, `rtcp-program-source`, `rtcp-program-load`, `rtcp-program-download` | Web RTCP source-program catalog backed by the locked LinuxCNC tree | The default scope follows the active machine: AC=`XYZAC`, BC=`XYZBC`; catalog/source/download are local file operations, while compatible main programs use the same `PROGRAM_LOAD` transaction and IDLE gate as Open | AC and BC programs are separated by kinematics. The optional all-source scope retains all 32 files for inspection; remap/subroutine/reference and mismatched kinematics cannot be sent as an executable main program |
|
||
| `machine-manager-settings`, `machine-manager-import`, `machine-manager-files`, `machine-manager-delete`, `machine-manager-translate`, `machine-manager-rotate`, `machine-manager-role`, `machine-manager-parent`, `machine-manager-show-origin`, `machine-tree-node`, `machine-tree-origin`, `machine-tree-axis-role`, `machine-test-x`, `machine-test-y`, `machine-test-z`, `machine-test-a`, `machine-test-b`, `machine-test-c`, `machine-test-reset`, `machine-test-state`, `machine-manager-apply`, `machine-manager-export` | Web component-level machine assembly extension | GLB `Object3D.children` render as a tree; selecting a node shows its parent-relative origin, dragging records parent overrides, and axis-test inputs drive bound nodes through their actual parent hierarchy without changing the source scene. Imported roots can be deleted. Apply validates AC/BC and then uses `LOAD_WORKSPACE` + `PROGRAM_LOAD` while OFF and IDLE | Axis-test motion is a local hierarchy diagnostic; production task motion, tool offset and RTCP remain Worker/WASM authoritative |
|
||
| `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` | `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 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-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 |
|
||
| `manual-spindle-ccw`, `manual-spindle-stop`, `manual-spindle-cw` | spindle radio group -> `spindle` | `SPINDLE_COMMAND`; `manual_ok`, MANUAL | Canonical signed RPM/direction determines pressed state |
|
||
| `manual-spindle-decrease`, `manual-spindle-increase` | `spindle_decrease/increase`; ButtonRelease -> `spindle_constant` | Enabled only while spindle direction is nonzero, matching `axis.tcl update_state` | Press sends speed edge without crossing through zero into the opposite direction; release/cancel sends `SPINDLE_CONSTANT` |
|
||
| `manual-spindle-brake` | `brake` | `SPINDLE_BRAKE`; same manual source gate | Canonical brake state controls checkbox |
|
||
| `manual-coolant-mist`, `manual-coolant-flood` | manual-group `mist`/`flood` controls | `COOLANT_COMMAND`; checkboxes use the source ON+IDLE manual-group gate | Independent canonical coolant bits; F7/F8 inverse the polled source value |
|
||
| `mdi-command`, `mdi-submit` | MDI entry and `send_mdi` | UI ON+queue capacity; handler separately requires `manual_ok` | Disabled handler retains input; accepted trimmed block enters MDI and receives canonical interpreter result |
|
||
| `mdi-history-select` | `mdi_history_butt_1`, `mdi_history_double_butt_1` | Single click selects; double-click submits through the same MDI gate | Single click copies the block only; double-click executes once, trims/clears entry and de-duplicates adjacent history |
|
||
| `preview-panLeft`, `preview-panRight`, `preview-panUp`, `preview-panDown`, `preview-reset` | Web accessible equivalent of Gremlin mouse pan/reset | Local camera only | Moves/resets camera; no Worker command |
|
||
| `dro-coordinate`, `dro-display`, `dro-units` | `coord_type`, `display_type`, `metric` | Local snapshot projection | Machine/Relative, Actual/Commanded and mm/inch display only |
|
||
| `override-jog-speed` | `update_jog_slider_vel` | `SET_JOG_SCALE`; no native machine-state UI gate | Canonical linear jog value used by later jogs |
|
||
| `override-feed` | `set_feedrate` | Debounced `SET_OVERRIDE`; no native `update_state` power gate; selected INI range 0-200% | Canonical feed override, including while AUTO where command layer permits |
|
||
| `override-spindle` | `set_spindlerate` | `SET_SPINDLE_OVERRIDE`; no native `update_state` power gate | Canonical spindle override |
|
||
| `override-max-velocity` | `set_maxvel` | `SET_MAX_VELOCITY`; no native `update_state` power gate | Canonical TP velocity limit/scale |
|
||
| `override-rapid` | `set_rapidrate` | Permanently disabled for selected ABI | `blocked_by_abi_rapidrate`; never aliases Max Velocity |
|
||
| `preview-layer-path`, `preview-layer-live`, `preview-layer-limits`, `preview-layer-velocity`, `preview-layer-offsets`, `preview-layer-extents` | AXIS View visibility variables | Local visibility only; path maps `show_program` | Shows/hides existing snapshot data without deleting or mutating it |
|
||
| `program-editor` | `WEB_EXTENSION`, not AXIS external Edit | Edits pending source text locally | Does not change loaded interpreter until the Reload adapter is accepted |
|
||
|
||
Tool/probe IO operations (`TOOL_PREPARE`, `TOOL_PREPARED`, `TOOL_CHANGE`,
|
||
`TOOL_CHANGED`, `PROBE_CONFIG`) remain Worker capabilities for interpreter,
|
||
MDI, HAL and focused IO tests. They are deliberately absent from the Web main
|
||
panel because no corresponding AXIS main-panel buttons exist.
|
||
|
||
## Button Dependency Matrix
|
||
|
||
The following matrix describes the side effects that determine the next set of
|
||
enabled controls. The right-hand column is an observable Worker state change;
|
||
React must derive its button gates from that state on the next snapshot.
|
||
|
||
| Action | Must be true before the click | State change after acceptance | Controls affected next |
|
||
| --- | --- | --- | --- |
|
||
| `ESTOP(active=true)` | Always accepted by the task state machine | IO `estop=1`, `ready=0`; interpreter and TP aborted; task `ESTOP`; loaded source retained | Disable power-on, home, jog, MDI, spindle, tool, probe and all program controls except E-stop reset/recovery-safe actions |
|
||
| `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/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; 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 |
|
||
| `PROGRAM_RESUME` | `paused` true, mode AUTO or MDI, and for combined toolbar `resume_inhibit` false | Trajectory resumes and interpreter restores `interpResumeState` | Combined toolbar returns to Pause; manual controls remain disabled until interpreter IDLE |
|
||
| `PROGRAM_ABORT` | AXIS exposes Stop while machine ON and interpreter non-IDLE; the task abort command itself is immediate | Interpreter aborts, TP queue is cleared, current taskfile/path remains selected, and the open task plan is closed | Stop periodic run polling; direct Run is enabled again when the task is idle and reopens the same taskfile from line 0. Reload is not a prerequisite. |
|
||
| `JOG_START` | `manual_ok`, Manual tab visible and a valid selected joint/axis. Homing selects coordinate TELEOP versus joint FREE behavior; it is not an unconditional GUI prerequisite. | One incremental command or one continuous command is sent | Continuous stays active until release/cancel sends `JOG_STOP`; incremental has no stop edge |
|
||
| `JOG_STOP` | An active jog gesture exists | Active jog is aborted/stopped; TP remains runnable | Allows a subsequent jog, MDI or source-gated manual command |
|
||
| `TOUCH_OFF` | Source widget/handler formula plus valid value; task MDI homing enforcement applies unless configured off | MDI `G10 L20` updates the selected coordinate system, reloads preview, then restores saved task/motion mode | Position/DRO/offsets refresh; program execution state remains idle |
|
||
| `SET_MAX_VELOCITY` | No native machine-state UI gate; numeric value follows source unit conversion/range | Source TP maximum velocity changes | Motion duration/velocity changes; jog/feed/rapid controls remain independent |
|
||
| Rapid Override control | Not available in the selected WASM TP | No state change | Rapid Override remains disabled; Max Velocity must not be used as a substitute |
|
||
| Spindle/Coolant | Native manual widgets require ON+IDLE; spindle direction/brake handlers additionally use `manual_ok` and ensure MANUAL where source does; coolant checkbox handlers do not switch mode | Canonical device IO changes only after Worker verification | Direction/checked states update from canonical status; spindle speed +/- also requires nonzero source direction |
|
||
| Feed/Spindle override | No native machine-state UI gate; values follow INI ranges | Send `c.feedrate`/`c.spindleoverride` equivalents | Canonical override changes without inventing an ON-only restriction |
|
||
|
||
### Dependency Flow
|
||
|
||
```text
|
||
ESTOP ──release──> ESTOP_RESET ──POWER ON──> ON
|
||
│
|
||
├──HOME ALL──> homed ON
|
||
│ │
|
||
│ ├──RUN──> AUTO/RUNNING
|
||
│ │ ├──PAUSE──> PAUSED
|
||
│ │ │ └──RESUME──> RUNNING
|
||
│ │ └──STOP/ESTOP/POWER OFF──> idle loaded taskfile
|
||
│ └──MANUAL/MDI──> jog/home/offset/device gates
|
||
└──PROGRAM LOAD──> loaded taskfile (idle only)
|
||
```
|
||
|
||
Any E-stop or power-off edge invalidates active motion immediately. It does not
|
||
delete the selected taskfile, static preview or Live Plot, and only joints
|
||
configured with volatile home are unhomed by the native source. The UI must not
|
||
leave stale enabled controls while waiting for the next canonical snapshot;
|
||
the Worker gate remains final authority if a click races a status transition.
|
||
|
||
## Required Transactions
|
||
|
||
### 原生清图方式(2026-09-08 10:14,北京时间)
|
||
|
||
按最新要求“原生如何清除,Web 也同样方式清除”,本节取代早期自动加载清图
|
||
扩展。以 `axis.py::reload_file/open_file_guts/clear_live_plot`、
|
||
`LivePlotter.clear` 和 `axis.tcl:379/664` 为准:
|
||
|
||
| 操作 | 加工 Live Plot | 静态程序预览 |
|
||
| --- | --- | --- |
|
||
| Open、Reload(同文件或编辑后)、加载 Chips | 保留 | 替换为新文件解析结果 |
|
||
| Run、再次 Run、Pause、Resume、Stop、正常结束 | 保留 | 保留 |
|
||
| Clear Live Plot 工具栏按钮 / Ctrl+K | 清除;运行时重新累积后续实际运动 | 保留 |
|
||
| 隐藏/显示 Live Plot | 仅改变可见性 | 不受影响 |
|
||
|
||
```text
|
||
Clear Live Plot 按钮或 Ctrl+K
|
||
-> axis.py::clear_live_plot -> LivePlotter.clear -> positionlogger.clear
|
||
Web 对应:VISUAL_CLEAR -> Worker clearLivePlot -> live_path_epoch + 1
|
||
-> React 删除旧加工轨迹及待播放样本,保留当前静态预览
|
||
-> 暂停/停止时保持空白,运行时从后续 WASM 运动继续积累
|
||
```
|
||
|
||
Web 不再随 PROGRAM_LOAD 自动清图,也不再发送
|
||
`clear_live_plot_on_replace`。旧请求即使带有该扩展参数,加载路径也不再
|
||
执行清图副作用。该退役参数不能成为隐藏的第二种清图入口。
|
||
清图仍可在暂停时使用,且不能损坏 Resume/Stop 的通信序号和队列。
|
||
|
||
### 暂停后恢复与通信一致性(2026-09-08 09:50,北京时间)
|
||
|
||
本次可复现故障:`PROGRAM_PAUSE(seq=9)` 成功后,UI 仍允许的清图
|
||
`VISUAL_CLEAR(seq=10)` 被旧通信层的 PAUSED 白名单拒绝,`last_seq` 停在 9。
|
||
随后 Resume(seq=11)、Stop(seq=12) 均报 `protocol.sequence_gap`,机器永久
|
||
停在暂停态。暂停后调节主轴倍率、执行 Step 或重复 Pause 也可能触发该问题。
|
||
|
||
源依据:`axis.py::task_pause/task_resume/task_pauseresume`;
|
||
`emctaskmain.cc:2248-2286` 保存/恢复 `interpResumeState` 并调用
|
||
`emcTrajPause/Resume`;AUTO+PAUSED 命令分支继续接收控制命令并按 task 规则
|
||
处理。暂停不关闭 NML 通道。`axis.tcl::update_state` 在暂停时仍启用 Step、
|
||
Resume、Stop,倍率和 Clear Live Plot 也没有暂停禁用公式。
|
||
|
||
```text
|
||
合法、顺序正确的帧 -> 通信层接收 seq(READY/PAUSED 均保持连接)
|
||
-> Worker ledger 与 task gate
|
||
-> 接受:执行相应 WASM 命令 + canonical snapshot
|
||
-> 拒绝:保留 gate_reason + 记录该 seq,不改变正在暂停/运行的运动
|
||
-> 下一合法帧继续使用 seq+1
|
||
|
||
PAUSE -> 保存 READING/WAITING/MDI 的恢复状态,保留解释器与 TP 队列
|
||
-> Clear / Override / Step / 被拒绝的命令不破坏通信序号
|
||
-> RESUME -> 恢复原状态和原队列 -> 后续 SIM_STEP 的位置持续前进
|
||
```
|
||
|
||
一致性约束:
|
||
|
||
- 通信 PAUSED 标记只表示已接收的暂停意图,不再维护另一套机床指令白名单。
|
||
schema/session/sequence/tick/operation_id 的格式校验继续有效;格式错误或
|
||
真正乱序帧仍拒绝,不能无条件跳过序号或自动重发副作用命令。
|
||
- Worker task gate 继续拒绝运行/暂停中的 Load、MDI、Home、Jog 等不合法操作。
|
||
“通信接收”不等于“机床执行”;拒绝必须保留错误和原机床状态。
|
||
- UI 的非致命命令错误不能自行停止仍在运行的 WASM 采样。是否继续采样取决于
|
||
canonical machine/task 状态;真正 ESTOP/OFF/FAULT/恢复过程仍停止采样。
|
||
- Pause/Resume 期间只允许一个在途采样;拒绝命令、清图、倍率操作和重复点击
|
||
后仍能继续。不得以 Reload/重置程序或清 TP 队列作为恢复手段。
|
||
- 连续两次 Pause/Resume、WAITING(文件读完但 TP 未排空)、MDI 暂停、暂停中
|
||
Step、暂停中清图/倍率、非法操作后 Resume、Resume 后 Stop 均需验证。
|
||
- 按上方最新原生规则保留 Open/Reload 的加工轨迹;Chips 的批量绘图与
|
||
实时推进、Home/Jog、主轴/冷却和 OPFS 偏好行为继续回归;不能为修复通信
|
||
删除这些已实现功能或放宽其 task gate。
|
||
|
||
验收以实际命令 seq、错误、队列/位置、恢复后的多个连续采样为准。
|
||
Resume 返回 acknowledged 或按钮图标改变,均不足以证明“继续执行”成功。
|
||
|
||
### 换程序轨迹与长程序性能(2026-09-08)
|
||
|
||
本次问题场景:执行第一份程序后,打开 `linuxcnc/nc_files/3D_Chips.ngc`,
|
||
旧加工轨迹仍可见,且第二份程序运行变慢。
|
||
|
||
**源码事实与本次 Web 要求分别记录。** `axis.py::open_file_guts` 创建新
|
||
`AxisCanon`,但不调用 `LivePlotter.clear()`;`clear_live_plot` 才调用
|
||
positionlogger 清图。因此原生 Open/Reload 保留 Live Plot 不是源码错误。
|
||
此前实现的自动换文件清图扩展已按 10:14 的最新原生要求退役。
|
||
现在所有 Web PROGRAM_LOAD 均保持原生保留语义,清图由用户显式触发。
|
||
|
||
```text
|
||
Web Open / 打包程序 / Reload
|
||
-> PROGRAM_LOAD {source, path}
|
||
-> 原生 Open 门控与解析,旧程序执行必须先结束
|
||
-> 文件解析成功 -> 发布新静态预览和程序状态,live_path_epoch 保持原值
|
||
-> React 替换静态刀路,保留加工轨迹
|
||
取消 / gate 拒绝 / 解析失败 -> 不清加工轨迹
|
||
Clear Live Plot / Ctrl+K -> 显式清除加工轨迹
|
||
```
|
||
|
||
读取/解析期间,画布继续持有最近的 Worker 快照,不能将 `snapshot=null`
|
||
临时投影成 `live_path_epoch=0` 而提前清图。加载成功或失败都保留 Live Plot;
|
||
只有显式清图的 Worker 新 epoch 才删除轨迹。失败文件的静态预览可为空。
|
||
|
||
清图只修改可视历史,不改 task/TP/IO/坐标/偏置/Feed Override。当前程序
|
||
Run 仍需用户单独操作,不能因加载文件而自动上电、回零或运行。
|
||
|
||
**执行时间依据。** 选定 INI 的 SERVO_PERIOD=1 ms、TASK CYCLE_TIME=10 ms。
|
||
一次 `SIM_STEP {cycles:5}` 必须执行 5 个原有 task tick/50 个 servo tick;
|
||
提升速度应减少每个 tick 的额外计算与绘图负担,不能放大位移、进给或
|
||
逻辑步长。`3D_Chips.ngc` 的 F 值以实际文件为准,经 WASM TP 的配置速度
|
||
和加速度限制;文件开头的注释不是替代 F 指令的依据。
|
||
|
||
性能核对要求:
|
||
|
||
- 主程序 source hash 在成功加载源文本时计算并保存;后续 snapshot 读取
|
||
同一不可变文本的 hash,不得每个 servo/task tick 重扫整份 G-code。
|
||
- 连续 servo 子周期内解释器没有变化时,不重复构造完整 program snapshot。
|
||
- 静态预览将 canonical samples 的相邻顶点合并到少量 LineSegments;
|
||
4684 段不能生成 4684 次静态 draw call;合并不得连接不相邻轨迹。
|
||
- 原生 AXIS 程序文本位于带滚动条的固定面板。Web 移动端也必须固定编辑器/
|
||
执行记录的 grid 行高,长程序只增加内部 scrollHeight,不能把整个页面
|
||
撑到数万像素或一次渲染所有行号。截图检查同时验证页面高度和内部滚动。
|
||
- 采样仍保持最多一个在途请求;不因 CPU 慢而叠加定时器或无限补发 tick。
|
||
- 验收记录第一程序完成 → Chips 加载 → 执行 → 再加载 Chips 的用时、
|
||
tick/墙钟比、Worker 请求延迟、绘图调用数;检查 Pause/Stop 响应和
|
||
canonical 路径/位置/状态哈希,不能仅以肉眼感觉变快为证据。
|
||
|
||
从原点加载 Chips 有 4684 段;选定启动程序结束在 Z10 后再加载时,首条
|
||
`G0 Z10` 为零位移,由 WASM 消去,预览为 4683 段。这是当前位置同步的
|
||
正常结果,不能为满足固定段数而插入假轨迹或重置机床位置。
|
||
|
||
基线测量:同一运行时重复读取 200 次快照,139 字节程序约 42 ms,
|
||
200509 字节 Chips 约 797 ms。该差异与重复文本哈希有关;最终性能结果
|
||
以验收报告中的本机前后测量为准。
|
||
|
||
### 全部控件的事件与验收规则
|
||
|
||
上面的 Complete Web Control Inventory 是控件全集。每一行均继承以下规则,
|
||
因此“只有点击回调,没有拒绝、结束或状态回显”的控件不满足本流程。
|
||
|
||
| 控件类别 | 事件入口与前置检查 | 成功路径 | 取消、拒绝和验收 |
|
||
| --- | --- | --- | --- |
|
||
| 机器、程序、回零、MDI、主轴、冷却、覆盖率、switchkins | 使用该行指定的 Worker gate;仅追加启动/文件读取中的异步互斥 | `operation_id → Worker → WASM → COMMAND_RESULT → panel_snapshot`;UI 使用最新快照回显 | 错误保留 `code/message_key/gate_reason` 和操作记录;不显示 acknowledged,不在 React 里补成功状态 |
|
||
| 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,单关节重复回零在确认后 ensure MANUAL;空白/非有限数字/非法 P 或 G 系统标识不提交 |
|
||
| About 和菜单 | 本地打开、关闭、Escape;About 打开时焦点进入,关闭后返回入口 | 显示/隐藏相应内容 | 弹窗打开期间不触发普通机器快捷键;F1 急停仍可用;关闭动作不触发 Stop |
|
||
| ABI/桌面边界控件 | 原生 disabled 属性与明确原因 | 无成功路径 | `SOURCE_BLOCKED` 不得出现机器命令或本地假开关;全部在浏览器清单中检查 |
|
||
|
||
菜单工具项、所有六种预置视图、五个轴选择、正负点动、两种冷却和所有滑块
|
||
都逐一计入验收;不能仅用同组中的一个按钮代表整组。动态历史项只允许
|
||
`mdi-history-select` 家族 ID 重复,其余 ID 必须唯一。
|
||
|
||
### MDI 输入和历史
|
||
|
||
来源:`axis.py:2413` (`mdi_up_cmd`)、`:2430` (`mdi_down_cmd`)、
|
||
`:2448` (`send_mdi`)、`:2454` (`send_mdi_command`)、`:2541` (double-click)。
|
||
历史上限来自 `axis.py:165` 的 1000 条,最后有一个空白输入位置。
|
||
|
||
```text
|
||
Go / Enter / 历史双击
|
||
-> manual_ok + MDI gate
|
||
-> trim 非空命令(Web 对纯空白不提交)
|
||
-> 清空输入、ensure MDI
|
||
-> 若与上一条不同则追加历史(最多 1000 条,按旧到新排序)
|
||
-> MDI_EXECUTE
|
||
-> ACK / interpreter error + canonical snapshot
|
||
单击历史 -> 仅选中并填入输入框
|
||
Up / Down -> 在历史与末尾空白位置循环,不发送命令
|
||
```
|
||
|
||
历史记录的是用户提交意图;解释器报错的命令也保留历史,不能据此判定执行成功。
|
||
浏览器会话内历史属于本地输入状态;写入桌面历史文件是单独的 host boundary。
|
||
`axis.tcl:1715/1724` 的 manualgroup 包含轴单选框,而不包含步长 combobox;
|
||
mdigroup 包含输入框、Go 和历史列表。Web 必须连同历史列表一起投影 mdigroup
|
||
门控;AUTO 活动但 UI 公式允许 MDI 时可以选历史,提交仍受 `manual_ok` 拒绝,
|
||
不能清空输入或追加历史。机床关闭时该组整体禁用。
|
||
|
||
### 快捷键必须使用源码的大小写和修饰键
|
||
|
||
`axis.py:3124` 将 F1 绑定到 `all`,所以编辑器、MDI 输入和弹窗聚焦时 F1
|
||
仍然有效;不得先因 INPUT/TEXTAREA/SELECT 聚焦而返回。非安全字母快捷键
|
||
不抢占文本输入、浏览器 Ctrl/Meta/Alt 组合,也不得通过 `toLowerCase()`
|
||
把没有源码绑定的大写字符转换成机器命令。`Shift-Home` 是清零,不是回零;
|
||
该能力缺失时明确拒绝,不能落入 Home 分支。`o` 必须进入同一 Open 门控。
|
||
|
||
`axis.py:2871/2879` 中 F9/F10 都先检查 spindle direction:任何非零方向
|
||
均发送 OFF,只有已停转时才分别发送 FORWARD/REVERSE。因此 F9 在 CCW
|
||
运行时、F10 在 CW 运行时必须先停转。主轴方向单选按钮仍直接选择方向。
|
||
F11/F12 的每次 Tk KeyPress 调用一次调速,源码并未屏蔽系统按键重复。
|
||
Web 当前抑制重复 keydown 是显式浏览器输入适配,不属于源码限制。
|
||
|
||
### 连续点动的运动权威
|
||
|
||
`axis.py:3241/3268/3282` 定义按下、释放和失焦;
|
||
`src/emc/motion/command.c:769` 的 `EMCMOT_JOG_CONT` 将目标设为该方向的
|
||
点动限位,释放通过 abort 停止。Web 使用同一目标选择规则:
|
||
|
||
```text
|
||
一次 JOG_START {axis, direction, continuous:true}
|
||
-> Worker 将连续模式编码为 TP jog 的 increment=0
|
||
-> C/WASM 从配置限位选择目标、使用配置速度/加速度提交一次轨迹
|
||
-> 浏览器定时器仅发送 SIM_STEP,不再发送 JOG_START 或计算距离
|
||
-> 一次 JOG_STOP -> C/WASM abort -> 队列清空 -> 停止采样
|
||
```
|
||
|
||
正数 increment 保留单次增量点动语义,负值/非有限值拒绝。增量点动也持续
|
||
采样直至 WASM 队列排空,不能只执行一个 tick 后悬停;释放不截断增量。
|
||
选定案例的毫米/角度转换在 Worker 输入边界完成,A/C 不按 25.4 缩放。
|
||
连续点动到达配置软限位后不得超限,反向点动必须仍可执行。
|
||
这属于选定 TP 的 `SOURCE_ADAPTER`:当前 abort 使用 TP 清队列,完整原生
|
||
free/teleop 伺服减速数值对照不属于已验证的按钮语义,不能据此宣称完整 motion parity。
|
||
|
||
### 验收证据与失败条件
|
||
|
||
| 证据 | 必须覆盖 | 失败判定 |
|
||
| --- | --- | --- |
|
||
| 源码契约检查 | Python/Tcl hash、处理函数、精确 gate、每个控件 ID | 源码漂移、漏 ID、出现未记录按钮 |
|
||
| Worker + 实际 WASM | 正常命令、OFF/ESTOP/运行/暂停拒绝、连续/增量点动、错误回传、对刀、重复运行、Live Plot 生命周期 | 无 ACK 或 canonical 输出、拒绝变成功、轨迹越界或错误清图 |
|
||
| 浏览器逐控件审计 | 全部控件及动态 About/历史;按下释放、失焦、取消、快捷键、门控与错误 | 未覆盖控件、重复 ID、按钮标题缺拒绝原因、控制操作仅改变本地状态 |
|
||
| 桌面与移动端 | 实际 Three.js 画布像素、视图交互、资源加载、文字/布局边界 | 空白画布、资源错误、横向溢出或控件遮挡 |
|
||
|
||
运行命令与实际结果记录在 `doc-rtcp/xyzac-panel-button-parity-test-report.md`。
|
||
本地浏览器证据必须标明本地 URL,不能写成已经部署或已验证线上版本。
|
||
|
||
### Startup program selection
|
||
|
||
```text
|
||
native priority: argv[0] -> AXIS_OPEN_FILE -> [DISPLAY] OPEN_FILE
|
||
browser applicable priority: selected INI [DISPLAY] OPEN_FILE
|
||
-> keep preview/program controls in loading state
|
||
-> LOAD_WORKSPACE
|
||
-> exactly one PROGRAM_LOAD for the configured OPEN_FILE
|
||
-> publish the configured program, source hash and preview atomically
|
||
-> enable source-gated controls
|
||
```
|
||
|
||
The UI cache is read only for presentation preferences. A stale cached program
|
||
from an earlier Web version is ignored and replaced on the next UI preference
|
||
save. No default-preview-then-cached-preview transition is permitted.
|
||
|
||
### File replacement
|
||
|
||
```text
|
||
poll
|
||
-> native Open/Reload gate: interpreter IDLE
|
||
-> Web safety adapter also requires TP/MDI queue empty and no active parse
|
||
-> save task mode
|
||
-> ensure MANUAL
|
||
-> optional source FILTER; on failure report and stop
|
||
-> restore saved task mode before PLAN_OPEN-equivalent parsing
|
||
-> set first line 0 and clear previous highlight
|
||
-> task_plan_synch + wait_complete
|
||
-> program_open / PROGRAM_LOAD
|
||
-> replace editor text and AxisCanon/static preview owner
|
||
-> construct preview init codes from canonical status and parse
|
||
-> reapply selected tab mode after the UI refresh
|
||
-> publish one canonical replacement snapshot
|
||
```
|
||
|
||
The replacement is rejected while the TP or an MDI move still has a queued or
|
||
active segment by the Web safety adapter. Native `open_file_guts` builds
|
||
preview initialization from polled machine position, units, tool, modal G/M
|
||
codes and tool offsets. Therefore loading B after A moved the machine must not
|
||
silently initialize relative preview at the origin. A failed filter does not
|
||
open a new taskfile. A G-code preview parse error is reported for the newly
|
||
selected file; native AXIS does not promise rollback to the old static preview.
|
||
|
||
### E-stop recovery and startup
|
||
|
||
```text
|
||
ESTOP(active=true)
|
||
-> emcMotionAbort + spindle/task/IO abort + trajectory disable
|
||
-> volatile-home joints may unhome; task-plan synch
|
||
-> observed task_state ESTOP
|
||
ESTOP(active=false)
|
||
-> send STATE_ESTOP_RESET; abort/synch; observed task_state ESTOP_RESET
|
||
POWER(active=true)
|
||
-> valid from ESTOP_RESET; trajectory enable; observed task_state ON
|
||
HOME(all=true)
|
||
-> manual_ok -> MANUAL -> joint/FREE -> c.home(-1) -> wait
|
||
PROGRAM_RUN
|
||
-> if the previous plan is completed/aborted: reopen current taskfile at line 0
|
||
-> AUTO mode, interpreter READING; browser scheduler drives WASM samples
|
||
```
|
||
|
||
### Run after completion or Stop
|
||
|
||
```text
|
||
RUNNING -> M2/end-of-file -> WAITING -> queue/IO drained -> IDLE/completed
|
||
-> press Run
|
||
-> reopen current taskfile
|
||
-> AUTO_RUN line 0
|
||
|
||
RUNNING -> Stop/abort -> abort interpreter + TP -> close task plan -> IDLE/aborted
|
||
-> press Run
|
||
-> reopen current taskfile
|
||
-> AUTO_RUN line 0
|
||
```
|
||
|
||
This is the source behavior in `emctaskmain.cc`: closing the task plan avoids
|
||
resuming at an aborted line, and `EMC_TASK_PLAN_RUN_TYPE` opens the selected
|
||
file again when no plan is open. The Web runtime may expose `PROGRAM_RESTART`
|
||
internally for recovery/testing, but it is not a required user step and is not
|
||
a second visible Run control. After the reopen/synchronization, a positioning
|
||
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.
|
||
|
||
### Native Homing and State Monitoring (2026-09-09)
|
||
|
||
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.
|
||
The XYZAC position summary and both preview HUDs display X/Y/Z/A/C together
|
||
with the five authoritative J0-J4 position readouts. Numeric homing target
|
||
selection and canonical joint data remain available to the existing control
|
||
logic.
|
||
|
||
```text
|
||
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
|
||
```
|
||
|
||
`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
|
||
|
||
AXIS's `all_systems` list is `P0 Current`, `P1 G54` through `P9 G59.3`.
|
||
`touch_off_system` passes the first token from the selected entry to
|
||
`G10 L20`, so the source command is `G10 L20 P1 X...` for G54 (and `P0` for
|
||
the current system). The Worker accepts the same P-token or a G54..G59.3
|
||
display token, records the normalized `source_system`, and executes the same
|
||
canonical P form. This keeps the source command and the interpreter encoding
|
||
auditable without changing the UI behavior.
|
||
|
||
对刀的数据闭环以 `interp_convert.cc::convert_setup/convert_coordinate_system`
|
||
为参照:G10 只修改指定 P 系统的偏置,不能移动机器当前位置。执行前先用
|
||
TP 实际位置同步解释器;毫米/英寸只转换线性轴,A/C 使用角度值。`G59.1`、
|
||
`G59.2`、`G59.3` 合法,`G54.1` 等非源码系统标识必须拒绝。
|
||
|
||
```text
|
||
TP 实际位置 -> 解释器同步 -> G10 L20 Pn AxisValue
|
||
-> WASM 保存九个坐标系偏置,机器位置不变
|
||
-> 使用相同偏置、当前位置和模态状态重新生成静态 preview
|
||
-> 发布偏置 + machine/relative 显示投影,live epoch 不变
|
||
-> 恢复保存的 task mode(包括错误返回分支)
|
||
```
|
||
|
||
文件 Reload/Open 和 Run 重开当前文件必须保留坐标偏置;临时预览解释器从
|
||
WASM 快照初始化偏置,不能默认所有偏置为零。Worker 的 relative 投影只做
|
||
`TP machine position - WASM active coordinate offset`,不得回写成运动目标。
|
||
带 G92、坐标旋转或刀具长度的完整坐标变换仍属于对应 ABI 的能力边界,
|
||
不得用这个平移投影冒充它们;此处验证当前选定案例的 G54..G59.3 平移偏置。
|
||
|
||
### Continuous jog
|
||
|
||
AXIS binds Button-1 to continuous jog and ButtonRelease to `jog_stop`.
|
||
The source sends one `JOG_CONTINUOUS` command and motion continues until a
|
||
deferred `JOG_STOP`; it does not submit a fresh user command every GUI sample.
|
||
The Web equivalent keeps one active `{axis,direction}` gesture, sends one
|
||
`JOG_START`, advances its WASM servo simulation internally and sends
|
||
`JOG_STOP` exactly once on release, cancel, leave, focus loss or E-stop.
|
||
|
||
### Toolpath display lifecycle
|
||
|
||
The panel renders two different path layers. Both the current Web panel and
|
||
the native AXIS follow the lifecycles below:
|
||
|
||
| Layer | Source owner | Visible/retained | Cleared or replaced |
|
||
| --- | --- | --- | --- |
|
||
| Static program preview | `open_file_guts` assigns a new `AxisCanon`; Gremlin renders that canon | Remains visible during Run, Pause, Resume, Stop and normal completion | Open/Reload replaces the previous canon with the newly selected program's canon and parses into it. A preview error is reported for the new file; native AXIS does not roll back to the old canon. Clear Live Plot does not affect it. |
|
||
| Machining Live Plot | `LivePlotter` owns `linuxcnc.positionlogger`; `show_live_plot` controls visibility | Accumulates independently of the selected static program. Pause freezes and retains it; Resume continues; Stop and normal completion retain it. Opening, reloading, running or rerunning a program also retains the existing trace. Hiding changes visibility only. | Only `clear_live_plot()` calls `LivePlotter.clear()`, whose `clear()` calls `positionlogger.clear()`. No call exists in `open_file_guts`, `reload_file`, `task_run`, `task_step`, `task_pause`, `task_resume` or `task_stop`. |
|
||
|
||
The Worker publishes a monotonic `visual.live_path_epoch`. React may clear the
|
||
machining Live Plot only when this value changes. Array identity, a full versus
|
||
delta snapshot, Pause, Resume, Stop, task mode, queue depth and completion are
|
||
not clear signals. The epoch changes only for `VISUAL_CLEAR` (or restoration
|
||
of a persisted epoch), never as an Open/Reload side effect.
|
||
|
||
```text
|
||
PROGRAM_LOAD accepted -> live epoch unchanged -> replace static preview only
|
||
PROGRAM_RUN accepted -> live epoch unchanged -> continue accumulating live trace
|
||
PROGRAM_PAUSE -> epoch unchanged -> retain/freeze live trace
|
||
PROGRAM_RESUME -> epoch unchanged -> continue live trace
|
||
PROGRAM_ABORT/STOP -> epoch unchanged -> retain live trace
|
||
program completed -> epoch unchanged -> retain live trace
|
||
VISUAL_CLEAR -> increment live_path_epoch -> clear live trace only
|
||
PROGRAM_RESTART -> epoch unchanged -> source has no visible Restart action
|
||
```
|
||
|
||
If Clear Plot is used while motion is still active, history before the clear
|
||
edge is removed and `positionlogger` semantics immediately begin accumulating
|
||
the subsequent motion in the new epoch. At IDLE, the cleared trace stays empty.
|
||
|
||
The native rule above is the current command contract. The previous automatic
|
||
Web replacement-clear extension is retired, including requests sent by an old
|
||
caller with its obsolete flag. Clear Live Plot is an explicit user operation.
|
||
|
||
## Implementation Invariants
|
||
|
||
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-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.
|
||
4. Every accepted operation produces a ledger entry and canonical snapshot;
|
||
every rejected operation produces a stable source/gate reason.
|
||
5. A feature that cannot be represented by the selected ABI is disabled with
|
||
an explicit reason. It must not be approximated with `G92`, a fixed `G43`,
|
||
local booleans or a second JavaScript state machine.
|
||
6. New controls must be added to this matrix, the source symbol inventory and
|
||
a focused Worker/browser regression test before deployment.
|
||
7. Executable program source/path is never part of UI preference persistence;
|
||
refresh performs one INI-authorized startup load.
|
||
8. Live Plot clearing is controlled only by the Worker `live_path_epoch`;
|
||
React object/array replacement is never a lifecycle signal. The
|
||
explicit `VISUAL_CLEAR` source adapter advances the epoch. Program loading
|
||
does not call the clear operation, including same-file Reload and edited text.
|
||
9. Every contract row carries or inherits one of `SOURCE_EXACT`,
|
||
`SOURCE_ADAPTER`, `SOURCE_BLOCKED` or `WEB_EXTENSION`; extensions and blocked
|
||
capabilities are never counted as source parity.
|
||
10. Exact `axis.tcl::update_state` formulas remain the reference UI gates.
|
||
A browser asynchronous-load exclusion must be documented separately; no
|
||
other stronger React gate may be attributed to AXIS.
|
||
|
||
## Change Procedure
|
||
|
||
Focused evidence for this contract is kept in
|
||
`web/worker/test_xyzac_touch_off_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`. 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
|
||
canvas paths are checked by `scripts/test_axis_panel_source_flow_browser.mjs`.
|
||
`web/worker/test_xyzac_source_widget_gates.mjs` checks UI-versus-command gates,
|
||
OFF/ESTOP overrides and the source mode transitions against real WASM.
|
||
`scripts/test_axis_source_ui_oracle.mjs` executes the original Tcl
|
||
`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, KINEMATICS_BOTH
|
||
world-axis rejection and spindle override 0-to-100 restoration using
|
||
the actual WASM runtime.
|
||
`web/worker/test_xyzac_step_flow.mjs` verifies the source-aligned Step phases,
|
||
immediate motion stepping, execution-id boundary completion, duplicate-step
|
||
idempotence, and completed/aborted task-plan reopen from line zero.
|
||
The exhaustive control-ID audit is enforced by
|
||
`scripts/test_axis_control_inventory.mjs` and
|
||
`scripts/test_axis_control_inventory_browser.mjs`; the latter rejects any
|
||
rendered actionable element without a documented ID or with a duplicate ID.
|
||
|
||
When LinuxCNC source behavior or the selected machine configuration changes:
|
||
|
||
1. Update the source baseline and the affected matrix row/transaction above.
|
||
2. Recompute the source-lock hashes and review every changed source symbol.
|
||
3. Update the Worker gate/authority path.
|
||
4. Update the React handler only after the Worker contract is verified.
|
||
5. Add normal, blocked and recovery assertions to the focused test.
|
||
6. Regenerate the relationship graph from its DOT source.
|
||
7. Run the panel browser tests, build the React bundle and record the local
|
||
preview URL. Publishing is a separate explicitly authorized action; local
|
||
evidence must not be represented as a deployment.
|
||
|
||
The document deliberately records ABI blockers and source boundaries. A
|
||
`verified` Web slice means the implemented path matches this contract; it does
|
||
not claim that an unavailable LinuxCNC host or official native oracle has been
|
||
silently reproduced in the browser.
|