6.5 KiB
LinuxCNC to WASM porting steps
This file defines the incremental path for replacing the temporary smoke parser with the LinuxCNC interpreter.
Step 0: Stable simulator ABI
Status: done.
The browser calls only cnc_sim_* functions from core/include/cnc_sim_api.h. This ABI remains stable while the backend changes.
Test:
g++ -std=c++17 -I core/include core/src/cnc_sim_api.cpp core/tests/cnc_sim_api_smoke.cpp -o /tmp/cnc_sim_api_smoke
/tmp/cnc_sim_api_smoke
Step 1: Temporary event parser
Status: in progress.
This parser only exists to test the ABI and UI before Emscripten and LinuxCNC are wired in. It currently handles:
- multiple G/M words on one line
G0,G1,G2,G3G17,G18,G19G20,G21,G70,G71G90,G91G4 P...F,S,T,M3,M4,M5,M6,M2,M30- IJK and R arcs
- numbered and named parameter assignment/reference such as
#1 = ...,#<name> = ...,X#1, and nested expressions likeX[[#<name> + 2] * 3] - expression functions
ABS[],SQRT[],EXP[],LN[], degree-basedSIN[]/COS[]/TAN[]/ASIN[]/ACOS[], LinuxCNC-styleATAN[]/[], andFIX[]/FUP[]/ROUND[] - numeric and named O-word subprograms such as
O100 callandO<name> call - canned cycles
G73,G81,G82,G83,G85,G86,G89withG80,G98,G99,L
It is not the production interpreter.
Step 2: Canon event sink
Status: started.
Create a C++ file that implements the Canon functions declared by LinuxCNC src/emc/nml_intf/canon.hh.
High-priority callbacks:
INIT_CANONUSE_LENGTH_UNITSSELECT_PLANESET_FEED_RATESET_SPINDLE_SPEEDSELECT_TOOLCHANGE_TOOLSTRAIGHT_TRAVERSESTRAIGHT_FEEDARC_FEEDDWELLPROGRAM_ENDFINISH
The sink will translate these callbacks to CncSimEvent.
Current bridge files:
core/src/canon_event_sink.hcore/src/canon_event_sink.cppcore/src/linuxcnc_canon_bridge.hcore/src/linuxcnc_canon_bridge.cpp
The LinuxCNC bridge is optional and not built by default:
cmake -S core -B build/native-linuxcnc \
-DCNC_SIM_ENABLE_LINUXCNC_BRIDGE=ON \
-DCNC_SIM_LINUXCNC_ROOT=/path/to/linuxcnc
This bridge is intentionally thin. The production parser still needs the rs274ngc interpreter linked on top of it.
Bridge smoke test:
./test-linuxcnc-bridge-native.sh
Set LINUXCNC_ROOT=/path/to/linuxcnc if the LinuxCNC source tree is not next to wasm-simulator.
Step 3a: Native librs274 runner
Status: started.
Before porting rs274ngc sources to wasm, use the already-built native LinuxCNC librs274 to validate the bridge and event schema:
./test-linuxcnc-rs274-native.sh
This builds core/tools/linuxcnc_rs274_dump.cpp, links LinuxCNC librs274, and writes:
/tmp/cnc_sim_linuxcnc_basic_motion.json/tmp/cnc_sim_linuxcnc_basic_mill.json
This is a native-only stepping stone. Once stable, the same event sink is used by the wasm build.
T... M6 now works in the native runner after initializing LinuxCNC mmap tooldata with a minimal tool table.
Step 3b: API-level native librs274 backend
Status: started.
The public cnc_sim_api can now select backends through config JSON:
{"backend":"smoke"}
or, in a native build compiled with CNC_SIM_ENABLE_LINUXCNC_RS274_BACKEND:
{"backend":"linuxcnc-rs274"}
API-level native smoke:
./test-linuxcnc-api-native.sh
Step 4a: Source compilation map
Status: started.
Before replacing librs274 with source-level compilation, keep the source manifest and syntax probe green:
./test-linuxcnc-source-syntax.sh
./test-linuxcnc-source-objects.sh
The manifest is:
linuxcnc-rs274-source-files.txtdocs/linuxcnc-rs274-source-map.md
The first compile condition discovered is that LinuxCNC user-space source probes need -DULAPI.
Step 3: Native LinuxCNC interpreter comparison
Build a native adapter that links:
src/emc/rs274ngcsrc/emc/nml_intf- the Canon event sink
Then run the same G-code corpus through both the temporary parser and LinuxCNC-backed parser. Numeric differences are expected around arc canonicalization; they must be recorded and bounded.
Step 4: Remove browser-hostile dependencies
LinuxCNC interpreter sources currently involve Python/Boost.Python remap paths. For the first WASM target:
- disable Python remap
- disable dynamic module loading
- replace file-backed parameter persistence with in-memory buffers
- provide browser-safe tool table and INI/config loading through JSON
Step 5: Emscripten build
Generate:
web/public/cnc_sim.jsweb/public/cnc_sim.wasm
Command:
./build-wasm.sh
Step 6: Controller dialects
Fanuc and Siemens support should remain outside the LinuxCNC core as preprocessors/adapters. They normalize controller-specific constructs into the internal event/interpreter input layer.
Functional parity matrix
This matrix tracks LinuxCNC feature coverage for the web/WASM simulator. A feature is not considered covered until it has a native regression in at least the librs274 runner and the source-link runner.
| Area | Status | Regression |
|---|---|---|
Basic modal motion G0/G1/G2/G3 |
covered | tests/gcode/linuxcnc_basic_motion.ngc, tests/gcode/basic_mill.ngc |
Tool select/change T... M6 |
covered with minimal native tooldata | tests/gcode/basic_mill.ngc |
RTCP controls G43.4/G43.5/G49 |
covered as simulator-owned control lines | tests/gcode/linuxcnc_rtcp_controls.ngc |
Kinematics switch M428/M429/M430 |
covered as simulator-owned control lines | tests/gcode/linuxcnc_rtcp_controls.ngc |
Canned cycle G81/G80 |
covered for drilling expand-to-canon path | tests/gcode/linuxcnc_canned_cycle.ngc |
| Coordinate offset Canon events | bridge-level covered | core/tests/linuxcnc_canon_bridge_smoke.cpp |
| Cutter compensation | covered for explicit-radius G41.1/G42.1/G40 through LinuxCNC native/source backends; tool-table G41/G42 D... remains pending |
tests/gcode/linuxcnc_cutter_comp.ngc |
| O-word subroutines and calls | covered for numeric O... sub/call/return/endsub through LinuxCNC file mode; smoke parser also covers named O<name> sub/call/return/endsub |
tests/gcode/smoke_oword_subprogram.ngc |
Broader canned cycles G73, G82-G89 |
partially covered: G73, G82, G83, G85, G86, G89 |
tests/gcode/linuxcnc_canned_cycles_extended.ngc, smoke API regression |
| Full source-level wasm build | pending | replace Python/HAL/INI/tooldata support dependencies |