16 KiB
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:
wasm-port/build/native/sim-configs/summary.tsv
Baseline:
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-codesM111.axis/geometry/xyzc.ngc: 1 failure from sim-only user M-codeM110.axis/foam/foam.ngc: 1 failure from missingU/Vaxis support in the LinuxCNCbin/rs274entry point.axis/vismach/5axis/bridgemill/5axisgui.ngc: 1 failure from missingWaxis support in the LinuxCNCbin/rs274entry point.axis/vismach/5axis/table-rotary_spindle-rotary-nutating/demos/incremental_repetition_g533.ngc: 1 failure from an upstream demo line that uses bareX/Y/Zwords afterG53.6without 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.
-
Add a tracked script:
wasm-port/tests/native/verify_sim_configs.sh -
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 underwasm-port/build/native/sim-configs/; - classify programs as
main,macro_load,remap_subroutine, orunsupported_runtime_edge; - fail the script only on unexpected failures.
- scan only
-
Add deterministic classification rules:
- files under
remap_subs/andnc_subroutines/are not standalone main programs; - files with no
M2,M30, or%are load/parse fixtures unless the INI references them throughREMAP; - user M-code files are tested through
USER_M_PATHresolution, not by pretending LinuxCNC native process services exist.
- files under
-
Wire the script into existing validation:
wasm-port/tests/native/verify_native_probes.sh -
Completion check:
wasm-port/tests/native/verify_sim_configs.shLatest result:
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' usedaxis/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:
-
Add a machine-config loader in
runtime/core/linuxcnc_wrap/, for example:linuxcnc_machine_config.hh linuxcnc_machine_config.cpp -
Reuse vendored
inifile.ccto parse:[TRAJ] COORDINATES[KINS] KINEMATICS[DISPLAY] GEOMETRY[RS274NGC] PARAMETER_FILE[RS274NGC] SUBROUTINE_PATH[RS274NGC] USER_M_PATH[EMCIO] TOOL_TABLE
-
Extend
initialize_minimal_interp()/ the runtime equivalent to set the interpreter setup fields from the parsed machine config instead of hardcodedXYZ. -
Add focused native fixtures:
axis_foam.ini+foam.ngcacceptsU/V.bridgemill/5axis.ini+5axisgui.ngcacceptsW.
-
Add the same coverage to the WASM SDK once native is green.
Completion check:
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: unknownM111axis/geometry/xyzc.ngc: unknownM110
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:
-
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.ccsearch/registration behavior and keeps process execution outside CNC semantics. -
Add
USER_M_PATHparsing to the machine-config loader. Done. -
For native standalone tests. Done:
- resolve
M100throughM199against configured search paths; - register only executable files;
- emit deterministic
USER_M_COMMANDboundary events.
- resolve
-
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.
-
Add tests. Done:
M110fromaxis/geometry;M111fromaxis/external_offsets;- minimal WASM
M110andM111fixtures.
Completion check:
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:
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:
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:
-
Preserve upstream behavior where possible:
- inspect vendored LinuxCNC Python plugin interfaces;
- identify exact APIs used by:
configs/sim/gmoccapy/python/toplevel.pyconfigs/sim/gmoccapy/python/remap.pyconfigs/sim/gmoccapy/python/stdglue.pyconfigs/sim/axis/laser/python/toplevel.pyconfigs/sim/axis/laser/python/remap.py
-
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.
-
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.
-
Make Python module path resolution match LinuxCNC:
- INI directory is the base directory;
PYTHONPATHincludes configpython/directories;- remap modules load relative to the sim config.
-
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:
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.ngcfails in the LinuxCNCrs274baseline because line 10 uses barex50y50z150afterG53.6; same-directory demos use explicitG0motion 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:
axis/vismach/5axis/table-rotary_spindle-rotary-nutating/
xyzacb-trsrn_twp/xyzacb-trsrn.ini
xyzbca-trsrn_twp/xyzbca-trsrn.ini
Implementation steps:
-
Improve sim-config mapping. Done:
- if a
.ngcis under ademos/sibling of machine-specific INI directories, map it to the appropriate TWP INI instead of walking upward toaxis/axis.ini; - encode this as explicit metadata in the harness, not a fragile heuristic.
- if a
-
Ensure
SUBROUTINE_PATHincludes../remap_subs:../demosas declared by the TWP INIs. -
Verify remap subroutines:
g69remap.ngcg531remap.ngcg533remap.ngcg536remap.ngc
-
Add a native test for each failing demo.
Latest result:
total: 15
pass: 14
fail: 1
timeout: 0
expected_fail: 1
unexpected_fail: 0
skipped: 0
Completion check:
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.ngcwithaxis_foam.ini, verifying INI-drivenU/Vaxis mask handling in WASM.axis/vismach/5axis/bridgemill/5axisgui.ngcwith5axis.ini, verifying INI-drivenWaxis mask handling and bridge-mill NGC remap execution in WASM.axis/geometry/xyzc.ngcwithxyzc.iniand real executableM110, verifyingUSER_M_PATHregistration in WASM.axis/external_offsets/dyn_demo.ngcwithdynamic_offsets.iniand real executableM111, verifying the same user-M boundary against an upstream sim program.
Completion checks:
wasm-port/tests/wasm/node/verify_sim_configs_wasm.sh
wasm-port/tests/browser/verify_interp_browser.sh
Remaining work:
-
Extend
runtime/core/linuxcnc_wrap/linuxcnc_interp_wasm.cppwith the same machine-config entry point used by native tests. Done for the existingrunFileWithIni()file-execution path. -
Extend
runtime/sdk/src/linuxcnc-interp.jswith a host-boundary method such as: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.
-
Copy required sim config files into the Emscripten FS:
- INI;
- tool table;
- parameter file;
.ngcprogram;SUBROUTINE_PATHfiles;USER_M_PATHhandler files or registered adapter handlers.
Done for the representative Node and browser subsets.
-
Add Node WASM coverage. Done:
wasm-port/tests/wasm/node/verify_sim_configs_wasm.mjs wasm-port/tests/wasm/node/verify_sim_configs_wasm.sh -
Add representative browser coverage. Done in
wasm-port/tests/browser/interp_smoke.htmlthrough the existing browser interpreter smoke and the samerunSimConfigProgram()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.
-
Update
docs/compatibility-validation.mdwith the sim-config matrix. Done. -
Update
docs/source-reuse-map.mdfor newly vendored source files. Done. -
Update
tools/source-manifest.txtandtools/verify_vendor_sync.shif new LinuxCNC files are copied intowasm-port/vendor/linuxcnc. Done for the representativeaxis/foam,axis/geometry, andaxis/external_offsetssim-config files; noverify_vendor_sync.shlogic change was needed. -
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
- Harness first: make
verify_sim_configs.shreproducible. - Axis config next: unblock
U/V/Wfailures. - TWP mapping: complete; remaining TWP demo failures are Python/HAL remap runtime edges.
- User M-code dispatch: small runtime-edge feature, unblocks five files.
- Python remap runtime: largest block; do it after the harness and smaller runtime edges are stable.
- WASM promotion after native parity.
Non-Goals
- Do not implement a new JavaScript or project-authored G-code interpreter.
- Do not edit
linuxcnc/configs/simor any upstreamlinuxcnc/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.