605 lines
60 KiB
Markdown
605 lines
60 KiB
Markdown
# LinuxCNC AXIS Web Control Panel Source Logic
|
|
|
|
Status: source-locked implementation contract
|
|
Scope: the selected `XYZAC TRT` Web/WASM panel and its LinuxCNC-compatible
|
|
Worker command path
|
|
Source baseline: LinuxCNC submodule `239dcf4284762ad7e9c65d390bc5524d855c2f8e`
|
|
|
|
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
|
|
```
|
|
|
|
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.
|
|
|
|
"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 differs, but the accepted action and observable machine semantics are the same. Any stronger Web safety gate is stated explicitly. |
|
|
| `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 AXIS control exists. The control must be visibly and textually separated from source parity and must not alter the meaning or gate of an AXIS action. |
|
|
|
|
Only `SOURCE_EXACT` and `SOURCE_ADAPTER` count as implemented AXIS parity.
|
|
`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 |
|
|
| `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 |
|
|
| `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 | `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. |
|
|
| 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/selected axis: `SOURCE_ADAPTER`; Unhome and joint-mode selector: `SOURCE_BLOCKED` |
|
|
| 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 and increment selection: `SOURCE_ADAPTER`; native joint selection is `SOURCE_BLOCKED` |
|
|
| Jog negative/positive and key jog | `jog_minus`, `jog_plus`, `jog_on`, `jog_off` | `SOURCE_ADAPTER`; press/release semantics and Manual-tab guard apply |
|
|
| Home Axis, Touch Off, Tool Touch Off, Override Limits | corresponding `zerohome`/`override` widgets | Home/Touch Off: `SOURCE_ADAPTER`; Tool Touch Off/Override Limits: visible `SOURCE_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 3D Chips, 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 and system Touch Off have adapters; 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
|
|
|
|
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.
|
|
|
|
## 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`. 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`; 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`, `SIM_STEP`, `JOG_STOP` | `SOURCE_ADAPTER`: source requires `manual_ok` and the visible Manual tab. Incremental sends one `JOG_INCREMENT`; Continuous sends one `JOG_CONTINUOUS` and motion continues until the deferred release issues `JOG_STOP`. Web servo sampling is transport/runtime work, not repeated user jog commands. |
|
|
| Home Axis | `HOME {axis}` | `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}` | `SOURCE_ADAPTER`: `manual_ok`, ensure MANUAL, if `all_homed()` ask the native re-home confirmation, then `set_motion_teleop(0)`, `c.home(-1)`, wait. Native text remains Home All; the Web `RE-HOME ALL` label is presentation-only and cannot trigger a hidden home during load. |
|
|
| 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 | One replacement transaction; input itself is hidden and only the toolbar button opens it |
|
|
| `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; this is the only visible commit action for edited source |
|
|
| `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 case | Does not load or change machine state until `toolbar-load-case` |
|
|
| `workspace-load-3d-chips` | Web packaged-file equivalent of `open_file_guts` | Fetch published `3D_Chips.ngc`, then `PROGRAM_LOAD`; IDLE only | Same canonical file replacement path as Open; no automatic Run/Home |
|
|
| `manual-home-all` | Machine Homing menu -> `home_all_joints` | `HOME {all:true}`; `manual_ok`, then MANUAL | Repeat asks source confirmation; Web Re-home label is non-authoritative presentation only |
|
|
| `switchkins-0`, `switchkins-1`, `switchkins-2` | `M429`, `M428`, `M430` remaps and `motion.switchkins-type` | `KINEMATICS_SELECT`; ON, homed, IDLE, empty TP | Identity/XYZAC/User K canonical type, or stable gate reason |
|
|
| `tab-manual`, `tab-mdi` | AXIS notebook F3/F5 `ensure_manual`/`ensure_mdi` | `SET_MODE` adapter; source `manual_ok` plus joint/teleop transitions apply | Tab selection plus acknowledged source-equivalent MANUAL/MDI and motion-mode transition |
|
|
| `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 | Supplies the selected axis to Jog/Home/Touch Off; sends no motion by itself |
|
|
| `manual-jog-increment` | `jogincrement` combobox | Local choice: Continuous or configured increment | Determines `JOG_CONTINUOUS` versus `JOG_INCREMENT` payload only |
|
|
| `manual-jog-negative`, `manual-jog-positive` | `jogminus`, `jogplus` -> `jog_on` | `JOG_START`; visible Manual tab and `manual_ok`; source chooses joint/teleop mode from kinematics+homing | Incremental submits once; Continuous remains active until one release/cancel `JOG_STOP` |
|
|
| `manual-home-axis` | `home_joint` | `HOME {axis}`; `manual_ok`, MANUAL, identity kinematics for coordinate-axis home | Canonical joint home; repeated home asks confirmation |
|
|
| `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` | Local text; submit/Enter sends `MDI_EXECUTE` under `manual_ok`/queue gate | Trimmed nonempty block, MDI mode, canonical interpreter result |
|
|
| `mdi-history-select` | AXIS MDI history row selection | Local history selection | Copies selected prior command into entry; does not execute until Submit/Enter |
|
|
| `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/axis)` | AXIS homing UI: ON+IDLE; handler `manual_ok`, then MANUAL | Home authority updates `homed[]`; individual coordinate-axis home is rejected for non-identity/duplicate coordinates | AUTO's task layer may run only when all required joints are homed unless `NO_FORCE_HOMING=1` |
|
|
| `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 | Identity is required for individual coordinate-axis homing; a non-empty queue blocks selection |
|
|
| `SET_MODE(MANUAL)` | Source task rejects leaving active AUTO; tab handler also requires `manual_ok` | Task mode MANUAL plus source joint/teleop selection | 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
|
|
|
|
### 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 mode -> 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.
|
|
|
|
### 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 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. They must never share an implicit
|
|
clear condition:
|
|
|
|
| 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. To match the source, the epoch changes only for the explicit
|
|
`VISUAL_CLEAR` adapter (or restoration of a previously persisted epoch); it
|
|
must not change on a program lifecycle command.
|
|
|
|
```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.
|
|
|
|
This source-exact rule supersedes the earlier Web extension that cleared the
|
|
trace on Run, Restart or Load. That extension contradicted native AXIS and is no
|
|
longer part of this contract. A product variant that wants per-job traces must
|
|
provide a separately named export/archive action; it may not change the AXIS
|
|
Clear Live Plot lifecycle while claiming source parity.
|
|
|
|
## 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, and only the
|
|
explicit `VISUAL_CLEAR` source adapter advances the epoch.
|
|
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_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`.
|
|
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 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.
|