Align AXIS Web control lifecycle with LinuxCNC
This commit is contained in:
@@ -7,6 +7,7 @@
|
||||
**原始 AXIS 入口**:[`linuxcnc/share/axis/tcl/axis.tcl`](../linuxcnc/share/axis/tcl/axis.tcl)
|
||||
**配套通信契约**:[前端与通信详细设计](linuxcnc-web-wasm-frontend-communication-design.md)
|
||||
**配套案例契约**:[案例对标计划](linuxcnc-web-wasm-case-parity-plan.md)
|
||||
**控制面板逻辑契约**:[LinuxCNC AXIS Web 控制面板源程序对照逻辑](linuxcnc-axis-web-control-panel-source-logic.md)
|
||||
|
||||
本文件是“Web 主界面完全对标 LinuxCNC 原始 AXIS”的唯一执行规范。它把原始 AXIS 的功能、界面结构、状态门控、快捷键、图标、绘图和外部集成拆成可追溯任务;没有来源、命令序列、状态结果和验收证据的功能,不得标记为完成。
|
||||
|
||||
|
||||
394
docs/linuxcnc-axis-web-control-panel-source-logic.md
Normal file
394
docs/linuxcnc-axis-web-control-panel-source-logic.md
Normal file
@@ -0,0 +1,394 @@
|
||||
# LinuxCNC AXIS Web Control Panel Source Logic
|
||||
|
||||
Status: active implementation contract
|
||||
Scope: the selected `XYZAC TRT` Web/WASM panel and its LinuxCNC-compatible
|
||||
Worker command path
|
||||
Source baseline: LinuxCNC submodule `239dcf4284762ad7e9c65d390bc5524d855c2f8e`
|
||||
|
||||
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
|
||||
```
|
||||
|
||||
The React state is never an authority. A rejected Worker command must remain
|
||||
rejected in the UI, with the source gate reason visible as the disabled-button
|
||||
title and in Diagnostics.
|
||||
|
||||
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).
|
||||
|
||||
On browser startup, the selected INI is the only program-selection authority.
|
||||
For `xyzac-trt.ini`, `[DISPLAY] OPEN_FILE` selects
|
||||
`./demos/xyzac_switchkins.ngc`, matching `axis.py` startup around
|
||||
`initialfile`/`open_file_guts`. Browser UI persistence must not restore a
|
||||
different G-code source or path 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.
|
||||
|
||||
| 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 |
|
||||
|
||||
The widget wiring is in `linuxcnc/share/axis/tcl/axis.tcl`: machine menu and
|
||||
toolbar bindings are around lines 105-170 and 490-669; manual jog, home,
|
||||
touch-off, spindle and coolant bindings are around lines 893-1087.
|
||||
|
||||
## 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/Reload/Load are Worker-backed; editor text is the Web file source; save, external editors, Ladder and Quit are host-boundary status/disabled entries. |
|
||||
| Machine menu | E-stop, Power, Run, Run from selected line, Step, Pause, Resume, Stop, Optional Stop, Block Delete, MDI history, Calibration/HAL tools, Homing, Unhoming, Zero coordinate system, Tool touch-off target | E-stop/Power/Run/Step/Pause/Resume/Stop/Home/Touch Off are represented by documented commands; Run-from-line, MDI clipboard/file actions, calibration/HAL desktop tools and Unhoming are not exposed; Optional Stop, Block Delete, Override Limits and Tool Touch Off remain ABI-blocked. |
|
||||
| View menu | Six preset views, inches/mm, show program/rapids/live plot/tool/extents/offsets/limits/velocity/DTG, grid, DRO font, PyVCP, commanded/actual, machine/relative, joint/world, clear plot | Preset view/zoom/rotate, units, commanded/actual, machine/relative and supported visual layers are Web projections; unsupported teleop, grid/DTG/font/PyVCP settings are not aliased to motion state. |
|
||||
| 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, coolant, tool/probe | XYZAC axis selector, jog, Home Axis, Touch Off, spindle, coolant, tool and probe are represented; joint selector, Tool Touch Off and Override Limits are explicitly bounded by the selected configuration/ABI. |
|
||||
| Web case strip | no AXIS equivalent | `Load exact XYZAC TRT case` is a Web workspace/bootstrap control, not an AXIS source button. It may only call the same documented `LOAD_WORKSPACE` + `PROGRAM_LOAD` transaction 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. |
|
||||
| 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.
|
||||
|
||||
## Source Keyboard Contract
|
||||
|
||||
The following bindings are copied from `axis.py` lines 3109-3171. Keys that
|
||||
would require an unavailable command are listed as blocked instead of being
|
||||
silently mapped to another operation.
|
||||
|
||||
| Key | Source handler | Web treatment |
|
||||
| --- | --- | --- |
|
||||
| `F1`, `F2`, lowercase `r`, `T`, `P`, `S`, `Esc`, `Ctrl-R`, `O`, `F7`-`F12` | E-stop, power, run, step, pause, resume, stop, reload, open, coolant and spindle handlers | Worker-backed commands with the same gate and ordering rules. |
|
||||
| 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`, `End`, `Ctrl-End` | `home_joint`, `home_all_joints`, `touch_off_system`, `touch_off_tool` | Home and system Touch Off are implemented; Tool Touch Off reports the documented ABI blocker. |
|
||||
| `x`, `y`, `z`, `a`, `c`, `-`, `=`, Shift jog keys | Axis selection and `jog_on`/`jog_off` | Axis selection and pointer jog are implemented; browser key-jog remains limited to the visible selected axes. |
|
||||
| `c`, `i`, `I` | Continuous/incremental jog mode | Represented by the jog increment selector; no second local mode state is created. |
|
||||
| `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. |
|
||||
| `Ctrl-K` | `clear_live_plot` | Worker visual-only `VISUAL_CLEAR`. |
|
||||
| `Ctrl-S`, Ctrl-M/H/Shift-H, `F4` | Save G-code, MDI clipboard/history, next tab | Save/clipboard operations are host/UI-boundary; `F4` notebook cycling is a Web navigation action and does not alter machine state. |
|
||||
|
||||
## State Gates
|
||||
|
||||
Every motion or interpreter operation is evaluated against the canonical task,
|
||||
IO and trajectory state before the handler runs.
|
||||
|
||||
| State | Meaning in the panel |
|
||||
| --- | --- |
|
||||
| `ESTOP` | E-stop input asserted. Only the reset edge and diagnostic-safe actions are available. |
|
||||
| `ESTOP_RESET` | E-stop released but power is not on. `POWER(active=true)` is the next machine edge. |
|
||||
| `OFF` | Machine power is off. File inspection/loading is allowed by LinuxCNC, but motion and MDI are not. |
|
||||
| `ON` | IO is ready. Manual operations still require an idle interpreter and the correct task mode. |
|
||||
| `RUNNING`/`PAUSED` | AUTO execution owns the interpreter. Manual, MDI, home, spindle and tool operations are blocked. |
|
||||
| `STOPPED` | A stopped taskfile remains recoverable; the next source-defined transition is `IO_RECOVER`, power or restart as applicable. |
|
||||
|
||||
`manual_ok()` is equivalent to: poll, task state ON, not running, and either
|
||||
an idle interpreter or an MDI queue below its limit. `ensure_mode()` is a
|
||||
command transaction, not a React state assignment.
|
||||
|
||||
## Control Matrix
|
||||
|
||||
| Panel control | React command | Source flow and required result |
|
||||
| --- | --- | --- |
|
||||
| Emergency Stop / Cancel | `ESTOP {active}` | `estop_clicked` toggles `STATE_ESTOP` and `STATE_ESTOP_RESET`; active E-stop aborts the interpreter and TP, then keeps the loaded taskfile. |
|
||||
| Power on / off | `POWER {active}` | `onoff_clicked` toggles `STATE_ON` and `STATE_OFF`; power-off aborts motion but preserves the loaded file. |
|
||||
| Open G-code file | browser file + `PROGRAM_LOAD` | `open_file_guts`: poll, save mode, enter MANUAL, restore the saved tab mode before `PLAN_OPEN/program_open`, set first line, synchronize, parse/preview, then `set_mode_from_tab` after refresh. |
|
||||
| Load case / Load editor | `PROGRAM_LOAD` | Same replacement transaction as `open_file_guts`; old preview is cleared before parsing and never reused after a failed replacement. |
|
||||
| Switchkins Identity / TCP: XYZAC / User K | `KINEMATICS_SELECT {type}` | Selected-case remap equivalent for `M429`/`M428`/`M430` from `xyzac-trt.ini`; requires homed, idle, empty TP queue and canonical HAL switchkins state. |
|
||||
| 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` | `ensure_mode(AUTO)` when needed, issue `AUTO_STEP`, and keep the interpreter at the source line boundary. |
|
||||
| Pause / Resume | `PROGRAM_PAUSE` / `PROGRAM_RESUME` | Pause only while AUTO is reading/waiting; resume only from the paused state. Polling ticks stop around the edge so a servo sample cannot race it. |
|
||||
| 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` | Visual-only operations do not change task, interpreter, TP or IO state. `Ctrl-K` maps AXIS `clear_live_plot()` and clears only the accumulated execution Live Plot; it must not delete the loaded program's static preview. |
|
||||
| DRO coordinate/display/units | local projection | Maps AXIS `coord_type`, `display_type` and `metric` variables; values remain Worker snapshot projections. |
|
||||
| Preview layers | local projection | Maps source `show_live_plot`, `show_machine_limits`, `show_machine_speed`, `show_offsets` and `show_extents` where the selected visual adapter has data; toggling a layer never changes motion. |
|
||||
| Manual / MDI tabs | `SET_MODE` | The tab gesture sends an explicit Worker mode command. No background effect may change MANUAL after AUTO has started. |
|
||||
| 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. |
|
||||
| Jog `-` / `+` | `JOG_START`, repeated `SIM_STEP`, `JOG_STOP` | `jog_on`/`jog_off` semantics. Incremental mode submits one TP segment; Continuous mode samples the source TP jog velocity until pointer release. |
|
||||
| Home Axis | `HOME {axis}` | `manual_ok`, `ensure_mode(MANUAL)`, then source joint-home command. Individual axis home is rejected outside identity kinematics, matching `home_joint`. |
|
||||
| Home All / Re-home All | `HOME {all:true}` | `manual_ok`, `ensure_mode(MANUAL)`, then home all joints. Once the canonical homed mask is complete, the Web label changes to `RE-HOME ALL` so loading another program is not mistaken for a requirement to home again. Activating Re-home retains the source `home_all_joints` confirmation. `PROGRAM_LOAD` never clears the homed mask and never invokes HOME. |
|
||||
| Touch Off | `TOUCH_OFF {axis,value,system,units}` | Prompt for value and one of AXIS's `all_systems` entries (`P0 Current`, `P1 G54` ... `P9 G59.3`), enter MDI, issue `G10 L20 <P-token>`, wait/synchronize, reload the active interpreter state and restore the saved mode. |
|
||||
| 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 requires an active limit and an idle interpreter; the selected WASM limit override ABI is unavailable, so no unsafe local emulation is provided. |
|
||||
| Spindle CCW / stop / CW | `SPINDLE_COMMAND` | `manual_ok`, `ensure_mode(MANUAL)`, then source direction/stop command. The displayed pressed state is derived from canonical signed RPM. |
|
||||
| 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` | Independent source coolant toggles; canonical device IO is returned after every edge. |
|
||||
| Prepare / Change tool | `TOOL_PREPARE` / `TOOL_CHANGE` | Source tool IO authority and acknowledgement path; no simulated completion is reported before the Worker verifies it. |
|
||||
| Arm / Disarm probe | `PROBE_CONFIG` | Source probe IO authority; faults and E-stop remain Worker-owned. |
|
||||
| Jog Speed | `SET_JOG_SCALE` | `update_jog_slider_vel` writes the source linear jog scale. |
|
||||
| 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` | `set_feedrate` writes the source feed override; updates are debounced but ordered in the Worker queue. |
|
||||
| Spindle Override | `SET_SPINDLE_OVERRIDE` | `set_spindlerate` writes canonical spindle override. |
|
||||
| Max Velocity | `SET_MAX_VELOCITY` | AXIS `set_maxvel` calls `c.maxvel` and changes the trajectory velocity limit. The selected WASM TP exposes this as its velocity 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` | `send_mdi` validates `manual_ok`, enters MDI, de-duplicates adjacent history entries and submits `c.mdi`. |
|
||||
| File edit/tool data/quit and desktop diagnostics | disabled or status-only | AXIS source launches external editor, tool editor, Ladder, HAL tools, LinuxCNC status and process quit. These are host-boundary operations and are not represented as browser controls. |
|
||||
|
||||
## 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)` | E-stop input is asserted | IO estop clears; task becomes `STOPPED`/`ESTOP_RESET`; power remains off | Enable Power On; keep all motion/interpreter operations disabled |
|
||||
| `POWER(active=true)` | E-stop clear, interpreter idle, task not running | IO `ready=1`; task `READY`/machine `ON` | Enable Home and source-gated manual/program controls; Run still requires homed and a taskfile |
|
||||
| `POWER(active=false)` | Machine on (source accepts the immediate off edge) | Abort motion/interpreter, IO `ready=0`, loaded taskfile retained | Disable motion, MDI, home and Run; allow Power On after the off edge |
|
||||
| `HOME(all/axis)` | Machine on, interpreter idle, homing gate true | Home-limit authority sets homed mask; individual non-identity home is rejected | Enables Run/MDI/jog only after the canonical homed result is published |
|
||||
| `PROGRAM_LOAD` | Interpreter idle, TP/MDI motion queue empty, source file/path valid | Enters MANUAL for replacement setup, captures the current canonical TP pose, restores the saved mode before PLAN_OPEN-equivalent parsing, replaces the interpreter source, applies the `task_plan_synch` pose before preview/subroutine processing, then reapplies the selected tab mode | Run/Step/Restart gates are recalculated from the new taskfile; old preview/trace is unavailable during parse and incremental coordinates start from the synchronized machine pose |
|
||||
| `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 | Identity is required for individual coordinate-axis homing; a non-empty queue blocks selection |
|
||||
| `SET_MODE(MANUAL)` | Machine on, no active AUTO/MDI motion | Task mode becomes `MANUAL` | Enables manual jog/home/spindle/tool gates when idle; disables AUTO-only pause/resume |
|
||||
| `SET_MODE(MDI)` | Machine on, interpreter idle or MDI queue below limit | Task mode becomes `MDI` | Enables MDI submission; manual controls follow `manual_ok` and queue policy |
|
||||
| `PROGRAM_RUN` | AXIS toolbar projection: machine ON and interpreter IDLE. Task acceptance additionally requires a current taskfile and, unless `NO_FORCE_HOMING` is configured, all required joints homed. `completed` and `aborted` are valid idle starting states. | If the previous task plan ended or was aborted, reopen/rewind the current taskfile at line 0; set mode `AUTO`, program `RUNNING`, and begin TP samples. A short program may pass through RUNNING and reach `completed` before the next UI paint; that is successful execution, not a blocked Run. | Disable Load, MDI, Home, Jog, spindle and tool operations while active; enable Pause and Stop. On completion, Run becomes available again for another line-0 execution. |
|
||||
| `PROGRAM_PAUSE` | AUTO program is reading/waiting | Program/task `PAUSED`; run polling is stopped around the edge | Disable Pause and Stop-as-new-run; enable Resume; keep E-stop and Power Off available |
|
||||
| `PROGRAM_RESUME` | Program/task is paused | Program/task `RUNNING`; TP polling resumes | Re-enable Pause and Stop; keep manual/MDI/home disabled |
|
||||
| `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` | Machine on, idle/manual gate, homed | One incremental segment or repeated continuous TP segments are queued | While held, another jog direction is not started; release/cancel must issue `JOG_STOP` |
|
||||
| `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` | Machine on, homed, idle/manual gate and valid dialog value | MDI `G10 L20` updates the selected coordinate system, then the saved mode is restored | Position/DRO and offsets refresh; program run state is unchanged |
|
||||
| `SET_MAX_VELOCITY` | Machine powered and the override gate permits the update | Source TP velocity limit is changed | Motion duration/velocity changes; jog and feed overrides 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/Tool/Probe | Machine on, idle, source-specific manual gate | Canonical device IO changes only after Worker verification | Their pressed/checked states update from device IO; no React-only optimistic state is allowed |
|
||||
|
||||
### 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 the downstream branch immediately.
|
||||
The UI must not leave a stale enabled button visible while it waits for the
|
||||
next canonical snapshot; the Worker gate remains the final authority even if a
|
||||
click races a state transition.
|
||||
|
||||
## Required Transactions
|
||||
|
||||
### Startup program selection
|
||||
|
||||
```text
|
||||
read selected INI
|
||||
-> resolve [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
|
||||
-> reject if AUTO is running/paused
|
||||
-> save task mode
|
||||
-> ensure MANUAL
|
||||
-> clear previous preview and pending TP/interpreter edges
|
||||
-> restore saved task mode before PLAN_OPEN-equivalent parsing
|
||||
-> capture current canonical TP pose
|
||||
-> set first line / PROGRAM_LOAD
|
||||
-> task_plan_synch equivalent: initialize the new interpreter from that TP pose
|
||||
-> subroutine load + preview from the same synchronized pose
|
||||
-> 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. Loading program B after program A has moved the machine must
|
||||
never reset the interpreter to the origin. For example, if A ends at `X10`, a
|
||||
new B program beginning with `G91 G1 X5` previews and executes from `X10` to
|
||||
`X15`, not from `X0` to `X5`.
|
||||
|
||||
### E-stop recovery and startup
|
||||
|
||||
```text
|
||||
ESTOP(active=true)
|
||||
-> abort interpreter and TP
|
||||
-> task ESTOP, IO estop=1, ready=0
|
||||
ESTOP(active=false)
|
||||
-> IO estop=0, task STOPPED (ESTOP_RESET)
|
||||
POWER(active=true)
|
||||
-> IO ready=1, task READY/ON
|
||||
HOME(all=true)
|
||||
-> MANUAL mode, all joints homed
|
||||
PROGRAM_RUN
|
||||
-> if the previous plan is completed/aborted: reopen current taskfile at line 0
|
||||
-> AUTO mode, RUNNING, periodic SIM_STEP until completion
|
||||
```
|
||||
|
||||
### 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.
|
||||
|
||||
### 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.
|
||||
|
||||
### Continuous jog
|
||||
|
||||
AXIS binds Button-1 to continuous jog and ButtonRelease to `jog_stop`.
|
||||
The Web equivalent keeps a single active `{axis,direction}` gesture, issues
|
||||
one source-TP jog segment per 50 ms sample using the canonical jog velocity,
|
||||
advances one servo sample, and sends `JOG_STOP` exactly once on release,
|
||||
cancel, leave or E-stop.
|
||||
|
||||
### Toolpath display lifecycle
|
||||
|
||||
The panel renders two different path layers. They must never share an implicit
|
||||
clear condition:
|
||||
|
||||
| Layer | Source owner | Visible/retained | Cleared or replaced |
|
||||
| --- | --- | --- | --- |
|
||||
| Static program preview | `open_file_guts` creates `AxisCanon`; Gremlin renders the parsed canon | Remains visible during Run, Pause, Resume, Stop and normal completion | A new `PROGRAM_LOAD` hides the old preview while parsing, then replaces it atomically with the newly parsed program. A failed replacement must not relabel the old path as the new program. |
|
||||
| Machining Live Plot | `LivePlotter`/`linuxcnc.positionlogger`; `show_live_plot` controls visibility | Accumulates during motion. Pause freezes and retains it. Resume continues the same trace. Stop and normal completion retain the accumulated trace. Hiding the Live layer changes visibility only and does not delete data. | AXIS `clear_live_plot()` explicitly calls `logger.clear()`. The Web panel additionally starts a documented new machining epoch for an accepted `PROGRAM_RUN`, `PROGRAM_RESTART`, or `PROGRAM_LOAD`, as required for this panel: the previous machining trace is cleared without changing the static preview or any task/TP state. |
|
||||
|
||||
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.
|
||||
|
||||
```text
|
||||
PROGRAM_LOAD accepted -> increment live_path_epoch -> clear old live trace
|
||||
-> hide old static preview while parsing
|
||||
-> publish new static preview
|
||||
|
||||
PROGRAM_RUN accepted -> increment live_path_epoch -> begin a new 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 -> increment live_path_epoch -> clear live trace
|
||||
```
|
||||
|
||||
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 additional Web epoch at a new Run/load boundary is a presentation
|
||||
lifecycle rule requested for this panel. It does not pretend that AXIS calls
|
||||
`positionlogger.clear()` from `task_run` or `open_file_guts`: the native source
|
||||
does not. Pause/completion retention and explicit Clear Plot behavior remain
|
||||
direct source matches.
|
||||
|
||||
## 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-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.
|
||||
|
||||
## Change Procedure
|
||||
|
||||
Focused evidence for this contract is kept in
|
||||
`web/worker/test_xyzac_touch_off_source_flow.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
|
||||
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`.
|
||||
|
||||
When LinuxCNC source behavior or the selected machine configuration changes:
|
||||
|
||||
1. Update the source baseline and the affected matrix row/transaction above.
|
||||
2. Update the Worker gate/authority path.
|
||||
3. Update the React handler only after the Worker contract is verified.
|
||||
4. Add normal, blocked and recovery assertions to the focused test.
|
||||
5. Run the panel browser test, build the React bundle, and publish a new
|
||||
release directory without replacing the previous rollback target.
|
||||
|
||||
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.
|
||||
18
docs/linuxcnc-submodule-local-changes.md
Normal file
18
docs/linuxcnc-submodule-local-changes.md
Normal file
@@ -0,0 +1,18 @@
|
||||
# LinuxCNC Submodule Local Changes
|
||||
|
||||
The root repository pins the `linuxcnc` submodule at
|
||||
`239dcf4284762ad7e9c65d390bc5524d855c2f8e`.
|
||||
|
||||
Local source-oracle and simulation configuration changes that cannot be
|
||||
represented by the unchanged submodule pointer are archived in
|
||||
`patches/linuxcnc-working-tree.patch`.
|
||||
|
||||
From the repository root, restore them to a clean submodule checkout with:
|
||||
|
||||
```sh
|
||||
git submodule update --init linuxcnc
|
||||
git -C linuxcnc apply ../patches/linuxcnc-working-tree.patch
|
||||
```
|
||||
|
||||
The patch includes tracked modifications and the untracked configuration files
|
||||
present when the root project was saved.
|
||||
Reference in New Issue
Block a user