487 lines
16 KiB
Markdown
487 lines
16 KiB
Markdown
# LinuxCNC Sim Config Completion Plan
|
|
|
|
This plan tracks the work needed to run the LinuxCNC programs under
|
|
`linuxcnc/configs/sim` through the standalone native/WASM simulation runtime.
|
|
LinuxCNC source remains the semantic source of truth. Port code must live under
|
|
`wasm-port/`; do not edit `linuxcnc/` in place.
|
|
|
|
## Current Baseline
|
|
|
|
The latest strict harness run used `linuxcnc/configs/sim` as the program source,
|
|
selected the nearest INI/tool table for each `.ngc` unless an explicit sim
|
|
mapping is required, and ran `rs274` from the INI directory so relative
|
|
`SUBROUTINE_PATH` and `REMAP` entries resolve like a real sim config.
|
|
|
|
Result file:
|
|
|
|
```text
|
|
wasm-port/build/native/sim-configs/summary.tsv
|
|
```
|
|
|
|
Baseline:
|
|
|
|
```text
|
|
total: 159
|
|
pass: 151
|
|
fail: 8
|
|
timeout: 0
|
|
expected_fail: 8
|
|
unexpected_fail: 0
|
|
|
|
main: PASS 40, FAIL 8
|
|
macro_load: PASS 46, FAIL 0
|
|
remap_subroutine: PASS 65, FAIL 0
|
|
```
|
|
|
|
Remaining failures are explicit LinuxCNC-native baseline edges:
|
|
|
|
- `axis/external_offsets/*`: 4 failures from sim-only user M-codes `M111`.
|
|
- `axis/geometry/xyzc.ngc`: 1 failure from sim-only user M-code `M110`.
|
|
- `axis/foam/foam.ngc`: 1 failure from missing `U/V` axis support in the
|
|
LinuxCNC `bin/rs274` entry point.
|
|
- `axis/vismach/5axis/bridgemill/5axisgui.ngc`: 1 failure from missing `W`
|
|
axis support in the LinuxCNC `bin/rs274` entry point.
|
|
- `axis/vismach/5axis/table-rotary_spindle-rotary-nutating/demos/incremental_repetition_g533.ngc`:
|
|
1 failure from an upstream demo line that uses bare `X/Y/Z` words after
|
|
`G53.6` without an explicit motion G-code.
|
|
|
|
## Target
|
|
|
|
The first target is not a browser UI feature. It is a repeatable native and
|
|
WASM simulation harness that can load and execute all `linuxcnc/configs/sim`
|
|
programs that are meaningful in a standalone non-hardware simulation context.
|
|
|
|
Acceptance criteria:
|
|
|
|
- The native sim-config harness reports all executable sim programs as `PASS`.
|
|
- Macro/remap files are validated by the correct entry point: direct execution
|
|
only for real programs, load/parse or remap-call validation for subroutines.
|
|
- WASM tests cover the same representative classes after the native harness is
|
|
green.
|
|
- Any remaining unsupported files are explicitly classified as native GUI or
|
|
hardware-only and excluded by rule, not by accident.
|
|
|
|
## Phase 1: Make The Harness A First-Class Test
|
|
|
|
Status: complete. The tracked script exists and is wired into the native
|
|
validation entry point.
|
|
|
|
1. Add a tracked script:
|
|
|
|
```text
|
|
wasm-port/tests/native/verify_sim_configs.sh
|
|
```
|
|
|
|
2. Move the ad hoc test logic into the script:
|
|
|
|
- scan only `linuxcnc/configs/sim`;
|
|
- identify `.ngc`, nearest `.ini`, nearest `.tbl`;
|
|
- run from the INI directory;
|
|
- write `summary.tsv`, stdout, stderr, and interpreter output under
|
|
`wasm-port/build/native/sim-configs/`;
|
|
- classify programs as `main`, `macro_load`, `remap_subroutine`, or
|
|
`unsupported_runtime_edge`;
|
|
- fail the script only on unexpected failures.
|
|
|
|
3. Add deterministic classification rules:
|
|
|
|
- files under `remap_subs/` and `nc_subroutines/` are not standalone main
|
|
programs;
|
|
- files with no `M2`, `M30`, or `%` are load/parse fixtures unless the INI
|
|
references them through `REMAP`;
|
|
- user M-code files are tested through `USER_M_PATH` resolution, not by
|
|
pretending LinuxCNC native process services exist.
|
|
|
|
4. Wire the script into existing validation:
|
|
|
|
```text
|
|
wasm-port/tests/native/verify_native_probes.sh
|
|
```
|
|
|
|
5. Completion check:
|
|
|
|
```bash
|
|
wasm-port/tests/native/verify_sim_configs.sh
|
|
```
|
|
|
|
Latest result:
|
|
|
|
```text
|
|
total: 159
|
|
pass: 151
|
|
fail: 8
|
|
timeout: 0
|
|
expected_fail: 8
|
|
unexpected_fail: 0
|
|
skipped: 0
|
|
```
|
|
|
|
## Phase 2: Load Machine Axes From INI
|
|
|
|
Status: partially complete for the port runtime. The standalone native/WASM
|
|
runtime now parses `[TRAJ] COORDINATES`, updates the standalone external axis
|
|
mask used by LinuxCNC `GET_EXTERNAL_AXIS_MASK()`, and applies the same
|
|
`Interp::_readers` filtering that upstream `rs274ngc_pre.cc` uses. Native
|
|
regression coverage verifies that `axis_foam.ini` enables `U/V` readers and
|
|
`bridgemill/5axis.ini` enables the `W` reader.
|
|
|
|
The `verify_sim_configs.sh` baseline still records the LinuxCNC `bin/rs274`
|
|
entry-point failures as expected failures. That harness is intentionally kept
|
|
as a LinuxCNC-native baseline while the port runtime coverage tracks this
|
|
phase's standalone behavior.
|
|
|
|
Current failures:
|
|
|
|
- `axis/foam/foam.ngc`: `Bad character 'u' used`
|
|
- `axis/vismach/5axis/bridgemill/5axisgui.ngc`: `Bad character 'w' used`
|
|
|
|
Root cause:
|
|
|
|
The current standalone interpreter initialization does not configure the active
|
|
axis mask from `[TRAJ] COORDINATES` / `[KINS] KINEMATICS`. Native LinuxCNC
|
|
accepts `U/V/W` only when the machine config declares those axes.
|
|
|
|
Implementation steps:
|
|
|
|
1. Add a machine-config loader in `runtime/core/linuxcnc_wrap/`, for example:
|
|
|
|
```text
|
|
linuxcnc_machine_config.hh
|
|
linuxcnc_machine_config.cpp
|
|
```
|
|
|
|
2. Reuse vendored `inifile.cc` to parse:
|
|
|
|
- `[TRAJ] COORDINATES`
|
|
- `[KINS] KINEMATICS`
|
|
- `[DISPLAY] GEOMETRY`
|
|
- `[RS274NGC] PARAMETER_FILE`
|
|
- `[RS274NGC] SUBROUTINE_PATH`
|
|
- `[RS274NGC] USER_M_PATH`
|
|
- `[EMCIO] TOOL_TABLE`
|
|
|
|
3. Extend `initialize_minimal_interp()` / the runtime equivalent to set the
|
|
interpreter setup fields from the parsed machine config instead of hardcoded
|
|
`XYZ`.
|
|
|
|
4. Add focused native fixtures:
|
|
|
|
- `axis_foam.ini` + `foam.ngc` accepts `U/V`.
|
|
- `bridgemill/5axis.ini` + `5axisgui.ngc` accepts `W`.
|
|
|
|
5. Add the same coverage to the WASM SDK once native is green.
|
|
|
|
Completion check:
|
|
|
|
```bash
|
|
wasm-port/tests/native/verify_sim_configs.sh --only axis/foam/foam.ngc
|
|
wasm-port/tests/native/verify_sim_configs.sh --only axis/vismach/5axis/bridgemill/5axisgui.ngc
|
|
```
|
|
|
|
## Phase 3: Implement Standalone User M-Code Dispatch
|
|
|
|
Status: complete for the standalone native/WASM runtime boundary. The port now
|
|
reads `[DISPLAY] PROGRAM_PREFIX` and `[RS274NGC] USER_M_PATH`, searches
|
|
executable `M100` through `M199` files using the same order as LinuxCNC task
|
|
initialization, registers them in LinuxCNC's `USER_DEFINED_FUNCTION` table, and
|
|
records `USER_M_COMMAND` canonical boundary events instead of spawning host
|
|
processes. Native probes cover `axis/geometry` `M110` and
|
|
`axis/external_offsets` `M111`; Node WASM covers minimal `M110` and `M111`
|
|
fixtures through the Emscripten filesystem.
|
|
|
|
The `verify_sim_configs.sh` baseline still records these files as expected
|
|
failures because it intentionally runs LinuxCNC `bin/rs274`, not the standalone
|
|
task/runtime adapter.
|
|
|
|
Current failures:
|
|
|
|
- `axis/external_offsets/*.ngc`: unknown `M111`
|
|
- `axis/geometry/xyzc.ngc`: unknown `M110`
|
|
|
|
Root cause:
|
|
|
|
Native LinuxCNC resolves user M-codes through `[DISPLAY] PROGRAM_PREFIX` and
|
|
`[RS274NGC] USER_M_PATH` during task initialization, registers matching
|
|
executable `M100..M199` handlers with the interpreter, and later runs external
|
|
scripts through the task process boundary. The standalone runtime must register
|
|
the same interpreter boundary without running host processes in WASM/browser.
|
|
|
|
Implementation steps:
|
|
|
|
1. Locate the upstream M-code dispatch path in LinuxCNC and vendor the minimum
|
|
source needed to preserve semantics, or add a narrow runtime-edge adapter if
|
|
the upstream path is process-bound. Done: the adapter mirrors
|
|
`src/emc/task/emctask.cc` search/registration behavior and keeps process
|
|
execution outside CNC semantics.
|
|
|
|
2. Add `USER_M_PATH` parsing to the machine-config loader. Done.
|
|
|
|
3. For native standalone tests. Done:
|
|
|
|
- resolve `M100` through `M199` against configured search paths;
|
|
- register only executable files;
|
|
- emit deterministic `USER_M_COMMAND` boundary events.
|
|
|
|
4. For WASM/browser. Done for Node WASM:
|
|
|
|
- do not spawn host processes;
|
|
- use a host-boundary user-M adapter that registers deterministic
|
|
message-emitting handlers for sim-only notification M-codes;
|
|
- document this as a runtime edge, not CNC semantics.
|
|
|
|
5. Add tests. Done:
|
|
|
|
- `M110` from `axis/geometry`;
|
|
- `M111` from `axis/external_offsets`;
|
|
- minimal WASM `M110` and `M111` fixtures.
|
|
|
|
Completion check:
|
|
|
|
```bash
|
|
wasm-port/tests/native/verify_sim_configs.sh --only axis/external_offsets
|
|
wasm-port/tests/native/verify_sim_configs.sh --only axis/geometry/xyzc.ngc
|
|
```
|
|
|
|
Standalone runtime checks:
|
|
|
|
```bash
|
|
wasm-port/tests/native/verify_native_probes.sh
|
|
wasm-port/tests/wasm/node/verify_interp_wasm.sh
|
|
```
|
|
|
|
## Phase 4: Bring Up Python Remap Runtime Edges
|
|
|
|
Status: complete for the native sim-config harness. Current checks:
|
|
|
|
```text
|
|
gmoccapy: total 38, pass 38, fail 0
|
|
axis/laser: total 3, pass 3, fail 0
|
|
```
|
|
|
|
Root cause:
|
|
|
|
The configs use LinuxCNC Python remap modules. Earlier harness runs failed while
|
|
initializing `python/toplevel.py`; current native runs now resolve and execute
|
|
these configs under the LinuxCNC `rs274` baseline.
|
|
|
|
Implementation steps:
|
|
|
|
1. Preserve upstream behavior where possible:
|
|
|
|
- inspect vendored LinuxCNC Python plugin interfaces;
|
|
- identify exact APIs used by:
|
|
- `configs/sim/gmoccapy/python/toplevel.py`
|
|
- `configs/sim/gmoccapy/python/remap.py`
|
|
- `configs/sim/gmoccapy/python/stdglue.py`
|
|
- `configs/sim/axis/laser/python/toplevel.py`
|
|
- `configs/sim/axis/laser/python/remap.py`
|
|
|
|
2. Split the implementation into two layers:
|
|
|
|
- native harness support using the host Python runtime, if available;
|
|
- WASM support using a documented adapter boundary or a Python-free
|
|
equivalent only for runtime edges, not G-code semantics.
|
|
|
|
3. Add runtime state adapters required by Python remap:
|
|
|
|
- selected tool and pocket;
|
|
- tool table access;
|
|
- interpreter status object fields used by stdglue;
|
|
- message/error reporting;
|
|
- canonical tool-change side effects needed by `M6`, `M61`, and laser
|
|
remaps.
|
|
|
|
4. Make Python module path resolution match LinuxCNC:
|
|
|
|
- INI directory is the base directory;
|
|
- `PYTHONPATH` includes config `python/` directories;
|
|
- remap modules load relative to the sim config.
|
|
|
|
5. Add narrowly-scoped tests before running all 38 gmoccapy programs. Done:
|
|
|
|
- one gmoccapy tool-change macro;
|
|
- one gmoccapy lathe macro;
|
|
- one gmoccapy 5-axis example;
|
|
- one laser raster/vector program.
|
|
|
|
Completion check:
|
|
|
|
```bash
|
|
wasm-port/tests/native/verify_sim_configs.sh --only gmoccapy
|
|
wasm-port/tests/native/verify_sim_configs.sh --only axis/laser
|
|
```
|
|
|
|
## Phase 5: Support TWP Remaps Including G69
|
|
|
|
Status: mapping complete. The harness now maps
|
|
`axis/vismach/5axis/table-rotary_spindle-rotary-nutating/demos/*` through the
|
|
explicit `xyzacb-trsrn_twp/xyzacb-trsrn.ini` machine config instead of falling
|
|
back to `axis/axis.ini`. That loads the TWP `G69` remap declarations correctly,
|
|
and 14 of the 15 TWP demo/remap programs now pass.
|
|
|
|
Current failures:
|
|
|
|
- `axis/vismach/5axis/table-rotary_spindle-rotary-nutating/demos/incremental_repetition_g533.ngc`
|
|
fails in the LinuxCNC `rs274` baseline because line 10 uses bare
|
|
`x50y50z150` after `G53.6`; same-directory demos use explicit `G0` motion
|
|
words at this point.
|
|
|
|
Root cause:
|
|
|
|
The demo programs rely on table/spindle rotary TWP remaps. The original test
|
|
mapping fell back to `axis/axis.ini` for these demo files because the actual
|
|
INI is in a child directory:
|
|
|
|
```text
|
|
axis/vismach/5axis/table-rotary_spindle-rotary-nutating/
|
|
xyzacb-trsrn_twp/xyzacb-trsrn.ini
|
|
xyzbca-trsrn_twp/xyzbca-trsrn.ini
|
|
```
|
|
|
|
Implementation steps:
|
|
|
|
1. Improve sim-config mapping. Done:
|
|
|
|
- if a `.ngc` is under a `demos/` sibling of machine-specific INI
|
|
directories, map it to the appropriate TWP INI instead of walking upward
|
|
to `axis/axis.ini`;
|
|
- encode this as explicit metadata in the harness, not a fragile heuristic.
|
|
|
|
2. Ensure `SUBROUTINE_PATH` includes `../remap_subs:../demos` as declared by
|
|
the TWP INIs.
|
|
|
|
3. Verify remap subroutines:
|
|
|
|
- `g69remap.ngc`
|
|
- `g531remap.ngc`
|
|
- `g533remap.ngc`
|
|
- `g536remap.ngc`
|
|
|
|
4. Add a native test for each failing demo.
|
|
|
|
Latest result:
|
|
|
|
```text
|
|
total: 15
|
|
pass: 14
|
|
fail: 1
|
|
timeout: 0
|
|
expected_fail: 1
|
|
unexpected_fail: 0
|
|
skipped: 0
|
|
```
|
|
|
|
Completion check:
|
|
|
|
```bash
|
|
wasm-port/tests/native/verify_sim_configs.sh --only table-rotary_spindle-rotary-nutating
|
|
```
|
|
|
|
## Phase 6: Promote Native Coverage To WASM
|
|
|
|
Status: complete for representative Node and browser WASM coverage. Dedicated
|
|
Node and browser smokes now pass a representative vendored `configs/sim` subset
|
|
through the SDK `runSimConfigProgram()` host boundary, which copies files into
|
|
the Emscripten filesystem and forwards execution to existing LinuxCNC-backed C
|
|
ABI paths. They cover:
|
|
|
|
- `axis/foam/foam.ngc` with `axis_foam.ini`, verifying INI-driven `U/V` axis
|
|
mask handling in WASM.
|
|
- `axis/vismach/5axis/bridgemill/5axisgui.ngc` with `5axis.ini`, verifying
|
|
INI-driven `W` axis mask handling and bridge-mill NGC remap execution in
|
|
WASM.
|
|
- `axis/geometry/xyzc.ngc` with `xyzc.ini` and real executable `M110`, verifying
|
|
`USER_M_PATH` registration in WASM.
|
|
- `axis/external_offsets/dyn_demo.ngc` with `dynamic_offsets.ini` and real
|
|
executable `M111`, verifying the same user-M boundary against an upstream sim
|
|
program.
|
|
|
|
Completion checks:
|
|
|
|
```bash
|
|
wasm-port/tests/wasm/node/verify_sim_configs_wasm.sh
|
|
wasm-port/tests/browser/verify_interp_browser.sh
|
|
```
|
|
|
|
Remaining work:
|
|
|
|
1. Extend `runtime/core/linuxcnc_wrap/linuxcnc_interp_wasm.cpp` with the same
|
|
machine-config entry point used by native tests. Done for the existing
|
|
`runFileWithIni()` file-execution path.
|
|
|
|
2. Extend `runtime/sdk/src/linuxcnc-interp.js` with a host-boundary method such
|
|
as:
|
|
|
|
```js
|
|
runSimConfigProgram({ iniPath, programPath, files })
|
|
```
|
|
|
|
Done. The method only writes caller-provided text files into the
|
|
Emscripten filesystem, applies executable bits for user M-code files, and
|
|
forwards execution to the existing LinuxCNC-backed C ABI path. It does not
|
|
implement CNC semantics in JavaScript.
|
|
|
|
3. Copy required sim config files into the Emscripten FS:
|
|
|
|
- INI;
|
|
- tool table;
|
|
- parameter file;
|
|
- `.ngc` program;
|
|
- `SUBROUTINE_PATH` files;
|
|
- `USER_M_PATH` handler files or registered adapter handlers.
|
|
|
|
Done for the representative Node and browser subsets.
|
|
|
|
4. Add Node WASM coverage. Done:
|
|
|
|
```text
|
|
wasm-port/tests/wasm/node/verify_sim_configs_wasm.mjs
|
|
wasm-port/tests/wasm/node/verify_sim_configs_wasm.sh
|
|
```
|
|
|
|
5. Add representative browser coverage. Done in
|
|
`wasm-port/tests/browser/interp_smoke.html` through the existing browser
|
|
interpreter smoke and the same `runSimConfigProgram()` SDK boundary as Node.
|
|
|
|
## Phase 7: Documentation And Drift Control
|
|
|
|
Status: complete for the current representative sim-config WASM/browser
|
|
coverage. The documentation and manifest now record the native, Node WASM,
|
|
browser, source reuse, and vendor-sync state for the selected sim-config
|
|
programs.
|
|
|
|
1. Update `docs/compatibility-validation.md` with the sim-config matrix. Done.
|
|
|
|
2. Update `docs/source-reuse-map.md` for newly vendored source files. Done.
|
|
|
|
3. Update `tools/source-manifest.txt` and `tools/verify_vendor_sync.sh` if new
|
|
LinuxCNC files are copied into `wasm-port/vendor/linuxcnc`. Done for the
|
|
representative `axis/foam`, `axis/geometry`, and `axis/external_offsets`
|
|
sim-config files; no `verify_vendor_sync.sh` logic change was needed.
|
|
|
|
4. Preserve the latest result summary as a machine-readable artifact, but do
|
|
not commit generated logs unless they are intentionally used as fixtures.
|
|
Done: generated logs remain under build/test output directories, while the
|
|
tracked documentation records only the current summary values and validation
|
|
commands.
|
|
|
|
## Recommended Work Order
|
|
|
|
1. Harness first: make `verify_sim_configs.sh` reproducible.
|
|
2. Axis config next: unblock `U/V/W` failures.
|
|
3. TWP mapping: complete; remaining TWP demo failures are Python/HAL remap
|
|
runtime edges.
|
|
4. User M-code dispatch: small runtime-edge feature, unblocks five files.
|
|
5. Python remap runtime: largest block; do it after the harness and smaller
|
|
runtime edges are stable.
|
|
6. WASM promotion after native parity.
|
|
|
|
## Non-Goals
|
|
|
|
- Do not implement a new JavaScript or project-authored G-code interpreter.
|
|
- Do not edit `linuxcnc/configs/sim` or any upstream `linuxcnc/` file to make
|
|
tests pass.
|
|
- Do not fake path, modal, kinematic, tool, or parameter semantics in the SDK.
|
|
- Do not treat gmoccapy native GUI code as browser UI implementation. Only its
|
|
simulation/remap behavior is relevant to this runtime.
|