结论:已将 vendored LinuxCNC impeller-7bl-xyzac.ngc 纳入五轴 TRT remap/tool-table/file 执行 baseline,native、Node WASM、browser 和 UI 均通过同源验证,未实现自有 M428/M429/M430 或运动学语义。
37 KiB
LinuxCNC WASM Porting Steps
Goal
Build a separate WASM-based CNC simulation program that:
- uses LinuxCNC source as the semantic source of truth,
- does not modify the original
linuxcnc/source tree, - is managed independently from native LinuxCNC,
- provides HTML + JavaScript frontend plus OPFS persistence,
- matches LinuxCNC software behavior as closely as practical except for realtime hardware driving.
Non-Negotiable Constraints
linuxcnc/is upstream and read-only for the port effort.- Any source adaptation needed for WASM happens on copied or generated files under
wasm-port/. - No direct edits inside
linuxcnc/src,linuxcnc/lib,linuxcnc/tests, orlinuxcnc/webare part of the port workflow. - LinuxCNC GUI code is reference-only. The migrated UI is rebuilt in HTML + JavaScript.
- LinuxCNC compute logic should be reused before any reimplementation is considered.
Workspace Structure
Create and keep these directories under wasm-port/:
docs/Planning, architecture, and validation documents.vendor/linuxcnc/Copied source files selected for the port.patches/Patch files against the vendored copies.tools/Scripts that extract files from../linuxcnc, apply patches, and verify drift.runtime/core/WASM-targeted C/C++ code and wrappers.runtime/sdk/JavaScript/TypeScript wrapper over the WASM module.runtime/ui/HTML + JavaScript frontend.runtime/opfs/Browser file adapter.tests/native/Native extracted-core regression tests.tests/browser/Browser/WASM regression and smoke tests.
Ported Program Directory Structure
The migrated program itself should be managed as a standalone product under
wasm-port/, with LinuxCNC acting as an upstream source provider.
The recommended final structure is:
wasm-port/
├── docs/
├── vendor/
│ └── linuxcnc/
│ └── src/
│ ├── emc/
│ │ ├── ini/
│ │ ├── kinematics/
│ │ ├── rs274ngc/
│ │ └── tp/
│ ├── hal/
│ │ └── components/
│ └── libnml/
│ └── posemath/
├── patches/
├── tools/
├── runtime/
│ ├── core/
│ │ ├── include/
│ │ ├── shims/
│ │ ├── adapters/
│ │ ├── canon/
│ │ ├── session/
│ │ ├── simulation/
│ │ ├── linuxcnc_wrap/
│ │ └── c_api/
│ ├── sdk/
│ │ └── src/
│ ├── ui/
│ │ ├── public/
│ │ └── src/
│ │ ├── panels/
│ │ ├── preview/
│ │ ├── state/
│ │ ├── machine/
│ │ └── files/
│ └── opfs/
├── tests/
│ ├── native/
│ ├── wasm/
│ └── fixtures/
├── build/
│ ├── native/
│ └── wasm/
└── dist/
├── sdk/
└── web/
Directory Responsibilities
vendor/linuxcnc/Holds extracted upstream LinuxCNC source files. These are copied or generated from../linuxcncand are the only place where source-level port patches are applied.patches/Stores every patch applied to vendored LinuxCNC files. Patches are tracked here instead of being mixed into the original source tree.tools/Holds extraction, sync, verification, manifest generation, and compatibility-check scripts.runtime/core/The standalone simulation runtime. This is where vendored LinuxCNC source is wrapped, adapted, and exposed to the rest of the ported program.runtime/core/include/Public internal headers for the standalone runtime.runtime/core/shims/Small compatibility headers and implementation stubs required to compile vendored LinuxCNC code outside the native runtime.runtime/core/adapters/Host boundary adapters such as file IO, logging, simulation HAL, and runtime-state providers.runtime/core/canon/Canonical motion event collection and serialization.runtime/core/session/Per-simulation session ownership for interpreter state, planner state, machine state, and controller state.runtime/core/simulation/Higher-level simulation orchestration built on top of reused LinuxCNC compute modules.runtime/core/linuxcnc_wrap/Thin wrappers around vendored LinuxCNC entry points. Prefer wrappers here over editing vendored source directly.runtime/core/c_api/Stable C ABI exported to the WASM layer.runtime/sdk/JavaScript/TypeScript SDK that calls the WASM module and hides memory management and ABI details from the frontend.runtime/ui/The actual CNC simulation web application built with HTML + JavaScript.runtime/ui/src/panels/Operator panels, machine configuration panels, parameter editors, and controller-status panels.runtime/ui/src/preview/2D/3D path preview, 5-axis visualization, joint/world overlays, and playback views.runtime/ui/src/state/Browser-side state management for session lifecycle and UI coordination.runtime/ui/src/machine/Machine-model-specific UI logic.runtime/ui/src/files/File import/export and project/session handling UI logic.runtime/opfs/OPFS-backed file services, snapshot persistence, and path mapping.tests/native/Native extracted-core regression tests run before WASM build validation.tests/wasm/WASM tests for Node and browser environments.tests/fixtures/Shared INI, G-code, parameter, tool-table, and machine fixtures.build/Intermediate build output. This is disposable.dist/Deliverable artifacts such as generated web bundles and SDK packages.
Source Ownership Rule
The ported program's own source code is expected to live under:
runtime/core/runtime/sdk/runtime/ui/runtime/opfs/tests/tools/docs/
Vendored LinuxCNC code must live under:
vendor/linuxcnc/
The original upstream tree must remain outside the ported program's source ownership boundary:
../linuxcnc/
Patch Placement Rule
If a LinuxCNC source file needs adaptation:
- extract it into
vendor/linuxcnc/; - patch the vendored copy only;
- record the patch in
patches/; - document why the patch exists in
docs/or in the patch header.
Do not place LinuxCNC source patches under runtime/.
Build Graph Rule
The standalone build should flow like this:
tools/extracts upstream files intovendor/patches/are applied to vendored copiesruntime/core/compiles vendored files plus wrappersruntime/sdk/consumes the generated WASM moduleruntime/ui/consumes the SDKruntime/opfs/provides browser persistence servicestests/validate native and browser behavior
This ensures the ported program remains independently buildable while still tracking LinuxCNC as the semantic source of truth.
Phase 0: Freeze Upstream Reference
Purpose: Make the LinuxCNC source baseline explicit before extraction starts.
Steps:
- Record the exact upstream commit from
linuxcnc/.git. - Record local build assumptions:
- compiler version
- emscripten version
- python version
- node version
- Record the first supported LinuxCNC fixture set:
- one 3-axis machine
- one non-trivial kinematics case
- one 5-axis machine
- Record the first G-code feature set:
- linear motion
- arc motion
- canned cycles
- offsets and coordinate systems
- subroutines
- numeric and named variables
- representative 5-axis programs
Outputs:
- upstream revision note
- supported feature baseline
- supported machine baseline
Phase 1: Build the Source Reuse Map
Purpose: Identify exactly which LinuxCNC source files are needed.
Steps:
- Map each required capability to LinuxCNC files:
- G-code interpreter:
../linuxcnc/src/emc/rs274ngc/* - parameter tables and named variables:
../linuxcnc/src/emc/rs274ngc/interp_* - INI parsing:
../linuxcnc/src/emc/ini/inifile.* - planner:
../linuxcnc/src/emc/tp/* - kinematics:
../linuxcnc/src/emc/kinematics/*and selected files from../linuxcnc/src/hal/components/*.comp - posemath:
../linuxcnc/src/libnml/posemath/*
- G-code interpreter:
- For each file, classify it:
- copy unchanged
- copy plus shim
- copy plus light patch
- not included in phase 1
- For each file, record dependencies:
- HAL
- RTAPI
- NML
- native file IO
- Python
- GUI
- Save the mapping as a table under
wasm-port/docs/.
Outputs:
- file-level reuse matrix
- dependency matrix
Phase 2: Build the Extraction Pipeline
Purpose: Keep LinuxCNC source untouched while making port-specific copies available.
Steps:
- Write extraction scripts in
wasm-port/tools/. - Copy selected upstream files into
wasm-port/vendor/linuxcnc/. - Preserve relative structure where useful, for example:
vendor/linuxcnc/src/emc/rs274ngc/...vendor/linuxcnc/src/emc/ini/...
- Store every modification as:
- a patch in
wasm-port/patches/, or - a thin wrapper outside the vendored file
- a patch in
- Add a verification script that compares upstream file hashes against the vendored source list.
Rules:
- if upstream changes, re-run extraction;
- reapply patches only in the standalone workspace;
- never patch
../linuxcncdirectly.
Outputs:
- reproducible extraction pipeline
- vendored source tree
Phase 3: Build the Native Extracted Core
Purpose: Prove the reusable LinuxCNC compute code works outside the full runtime.
Steps:
- Create
wasm-port/runtime/core/as the portable core layer. - Add wrapper translation units instead of editing vendored files where possible.
- Start with these subsystems in order:
- INI parser
- numeric parameter table
- named parameter logic
- interpreter core
- planner
- kinematics
- Build a native CLI harness first, before any WASM build.
- Replace host edges with abstractions:
- file provider
- HAL adapter
- runtime state provider
- logging adapter
Outputs:
- portable native core
- native harness executable
Current verified progress:
tools/build_native_probes.shbuilds the INI parser probe, interpreter state probe, named-parameter harness, RS274 compile probe, and the minimal interpreter harness from the standalonewasm-port/workspace.tests/native/verify_native_probes.shvalidates that all native probe exit codes are zero and that the minimal interpreter harness emits aSTRAIGHT_TRAVERSEcanonical event forG0 X1.0 Y2.0, plusSET_FEED_RATEandSTRAIGHT_FEEDcanonical events forG1 X3.0 Y4.0 F120.0.- The same validation is now fixture-driven through
tests/fixtures/gcode/minimal_linear.ngcandtests/fixtures/canon/minimal_linear.events. tests/fixtures/gcode/modal_incremental.ngcandtests/fixtures/canon/modal_incremental.eventsaddG90/G91distance-mode switching plus modalG1carry-forward coverage. The temporary wrapper behavior is based on LinuxCNCinterp_convert.cc::convert_distance_mode()andinterp_convert.cc::convert_straight().tests/fixtures/gcode/position_params.ngcandtests/fixtures/canon/position_params.eventscover Z-axis motion plus current-position parameter visibility for#5420,#5421, and#5422. The parameter source basis is LinuxCNCinterp_parameter_def.hhandinterp_namedparams.cc.tests/fixtures/gcode/canned_cycles.ngcandtests/fixtures/canon/canned_cycles.eventscover LinuxCNC canned-cycle conversion through vendoredinterp_cycles.cc, includingG81,G82,G83,G80cancellation, dwell, peck drilling, and incrementalLrepeats.runtime/core/linuxcnc_wrap/linuxcnc_interp_minimal_runtime.cppnow records coordinate-system canonical boundary calls emitted by vendored LinuxCNC conversion code:SET_G5X_OFFSET,SET_G92_OFFSET,SET_XY_ROTATION,CANON_UPDATE_END_POINT,USE_LENGTH_UNITS, andSELECT_PLANE.tests/fixtures/gcode/coordinate_offsets.ngcandtests/fixtures/canon/coordinate_offsets.eventspinG55, activeG10 L2,G92,G92.1, andG54behavior frominterp_convert.cc::convert_coordinate_system(),interp_convert.cc::convert_setup(), andinterp_convert.cc::convert_axis_offsets().tests/fixtures/gcode/length_units.ngcandtests/fixtures/canon/length_units.eventspinG20/G21unit switching and theUSE_LENGTH_UNITScanonical boundary emitted by vendoredinterp_convert.cc::convert_length_units().tests/fixtures/gcode/plane_selection.ngcandtests/fixtures/canon/plane_selection.eventspinG17/G18/G19plane switching and theSELECT_PLANEcanonical boundary emitted by vendoredinterp_convert.cc::convert_set_plane().tests/fixtures/gcode_errors/cutter_comp_plane_change.ngcandtests/fixtures/canon_errors/cutter_comp_plane_change.expectedpin the LinuxCNC error path for attempting a plane change afterG41.1enables cutter radius compensation. The source basis is vendoredinterp_convert.cc::convert_cutter_compensation_on()andinterp_convert.cc::convert_set_plane().runtime/core/linuxcnc_wrap/linuxcnc_runtime_state_stubs.cppnow initializessetup::cutter_comp_firstmoveto the same initial value as vendoredrs274ngc_pre.cc, allowing the first cutter-compensated straight move to follow LinuxCNCinterp_convert.cc::convert_straight_comp1()instead of the subsequent-move path.tests/fixtures/gcode/cutter_comp_motion.ngcandtests/fixtures/canon/cutter_comp_motion.eventspin positiveG41.1/G40compensated straight-feed output through vendoredinterp_convert.ccandinterp_queue.cc.tests/fixtures/gcode/g53_machine_coordinates.ngcandtests/fixtures/canon/g53_machine_coordinates.eventspinG53machine coordinate straight-traverse behavior through vendoredinterp_find.cc::find_ends()andinterp_convert.cc::convert_straight().tests/fixtures/gcode_errors/g53_incremental.ngcandtests/fixtures/canon_errors/g53_incremental.expectedpin the LinuxCNC rejection path forG53while incremental distance mode is active.runtime/core/linuxcnc_wrap/linuxcnc_interp_minimal_runtime.cppnow records feed/control canonical boundary calls emitted by vendored LinuxCNC conversion and queue code:SET_TRAVERSE_RATE,SET_FEED_REFERENCE,SET_FEED_MODE,SET_MOTION_CONTROL_MODE, andSET_NAIVECAM_TOLERANCE.tests/fixtures/gcode/feed_control_modes.ngcandtests/fixtures/canon/feed_control_modes.eventspinG93,G94,G95,G61,G61.1, andG64 P/Qbehavior frominterp_convert.cc::convert_feed_mode(),interp_convert.cc::convert_control_mode(), andinterp_queue.cc.runtime/core/linuxcnc_wrap/linuxcnc_interp_minimal_runtime.cppnow records probe canonical boundary calls emitted by vendoredinterp_convert.cc::convert_probe():TURN_PROBE_ON,STRAIGHT_PROBE, andTURN_PROBE_OFF.tests/fixtures/gcode/probe_semantics.ngcandtests/fixtures/canon/probe_semantics.eventspinG38.2,G38.3,G38.4, andG38.5probe type handling.runtime/core/linuxcnc_wrap/linuxcnc_interp_minimal_runtime.cppnow records speed/feed synchronization and rigid-tap canonical boundary calls emitted by vendoredinterp_convert.cc::convert_straight():START_SPEED_FEED_SYNCH,STOP_SPEED_FEED_SYNCH, andRIGID_TAP.tests/fixtures/gcode/threading_sync.ngcandtests/fixtures/canon/threading_sync.eventspinG33spindle-synchronized straight feed andG33.1rigid tap behavior.runtime/core/linuxcnc_wrap/linuxcnc_interp_minimal_runtime.cppnow records NURBS G5 canonical boundary calls emitted by vendoredinterp_convert.cc::convert_nurbs():NURBS_G5_FEED.tests/fixtures/gcode/nurbs_g5_semantics.ngcandtests/fixtures/canon/nurbs_g5_semantics.eventspinG5.2control-point collection andG5.3NURBS feed emission.runtime/core/linuxcnc_wrap/linuxcnc_interp_minimal_runtime.cppnow records NURBS G6 canonical boundary calls emitted by vendoredinterp_convert.cc::convert_nurbs():NURBS_G6_FEED.tests/fixtures/gcode/nurbs_g6_semantics.ngcandtests/fixtures/canon/nurbs_g6_semantics.eventspinG6.2order, interpolation mode, control-point, weight, and K segment handling.runtime/core/linuxcnc_wrap/linuxcnc_interp_minimal_runtime.cppnow records spindle-orient canonical boundary calls emitted by vendored LinuxCNC conversion and queue code:ORIENT_SPINDLEandWAIT_SPINDLE_ORIENT_COMPLETE.tests/fixtures/gcode/spindle_orient.ngcandtests/fixtures/canon/spindle_orient.eventspinM19 R/P/Qbehavior frominterp_convert.cc::convert_m()andinterp_queue.cc.runtime/core/linuxcnc_wrap/linuxcnc_interp_minimal_runtime.cppnow records tool-table canonical boundary calls emitted by vendoredinterp_convert.cc::convert_setup_tool():SET_TOOL_TABLE_ENTRY.tests/fixtures/gcode/tool_table_setup.ngcandtests/fixtures/canon/tool_table_setup.eventspinG10 L1tool offset, diameter, front/back angle, and orientation behavior.runtime/core/linuxcnc_wrap/linuxcnc_interp_minimal_runtime.cppnow records the tool-data reload boundary call emitted by vendoredinterp_convert.cc::convert_modal_0():RELOAD_TOOLDATA.tests/fixtures/gcode/tool_reload.ngcandtests/fixtures/canon/tool_reload.eventspinG10 L0dispatch without adding standalone tool-table reload semantics.runtime/core/linuxcnc_wrap/linuxcnc_interp_minimal_runtime.cppnow records interpreter state-tag boundary calls emitted by vendored LinuxCNCinterp_write.cc::write_state_tag()andinterp_convert.cc::update_tag():UPDATE_TAG.tests/fixtures/gcode/state_tag_motion.ngcandtests/fixtures/canon/state_tag_motion.eventspin straight-motion state tag emission without deriving modal state in standalone code.runtime/core/linuxcnc_wrap/linuxcnc_interp_minimal_runtime.cppnow records rotary indexer lock/unlock boundary calls emitted by vendoredinterp_convert.cc::issue_straight_index():UNLOCK_ROTARYandLOCK_ROTARY. A dedicatedlinuxcnc_indexer_harnesspins the LinuxCNC single-axisG0 A...indexer path, including the surrounding motion-control boundary calls, without adding standalone rotary-indexing semantics.runtime/core/linuxcnc_wrap/linuxcnc_interp_minimal_runtime.cppnow records the canonical flush boundary emitted by vendored LinuxCNC file-reading code:FINISH.tests/fixtures/gcode/percent_file_finish.ngcandtests/fixtures/canon/percent_file_finish.eventspin%-delimited file handling fromrs274ngc_pre.cc::open()andinterp_read.cc::read_text(). The native verification script treats this fixture as file-mode-only because%is a LinuxCNC program-file delimiter, not a valid MDI command.runtime/core/linuxcnc_wrap/linuxcnc_interp_minimal_runtime.cppnow records the reset/queue-drop boundary emitted by vendoredrs274ngc_pre.cc::reset():ON_RESET.tests/fixtures/gcode/file_open_reset.ngcandtests/fixtures/canon/file_open_reset.eventspin the LinuxCNC file-open reset path without adding standalone queue-management semantics.runtime/core/linuxcnc_wrap/linuxcnc_interp_minimal_runtime.cppnow records the interpreter initialization boundary emitted by vendoredrs274ngc_pre.cc::init():INIT_CANON. A dedicatedlinuxcnc_interp_init_harnesscalls vendoredInterp::init()and pins the LinuxCNC initialization sequence:INIT_CANON,USE_LENGTH_UNITS,SET_G5X_OFFSET,SET_G92_OFFSET,SET_XY_ROTATION, andSET_FEED_REFERENCE, without changing the minimal G-code fixture harness startup path.runtime/core/linuxcnc_wrap/linuxcnc_interp_minimal_runtime.cppnow records comment logging canonical boundary calls emitted by vendoredinterp_convert.cc::convert_comment():LOGOPEN,LOG,LOGAPPEND, andLOGCLOSE.tests/fixtures/gcode/comment_logging.ngcandtests/fixtures/canon/comment_logging.eventspin LinuxCNC comment logging dispatch without adding standalone comment semantics.tools/verify_native_linuxcnc_fixture_baseline.shnow runs an expanded side-by-side baseline against upstream../linuxcnc/bin/rs274. It normalizes native LinuxCNC canonical output for simple motion, offsets, feed-control, comment/logging, numbered-parameter, spindle-orient, file-finish, and tool-reload fixtures. It now also includes file-open reset and O-word subroutine fixture coverage, threading/rigid tap coverage, NURBS dispatch boundary coverage, comparable canonical runtime edge calls, and the program-end cleanup calls emitted afterM2. Native output is filtered to the event classes each standalone fixture explicitly expects, while upstreamrs274output gaps such asWAIT, hidden NURBS control-point detail, and standalone modal-state assertions remain covered by the standalone harness rather than being treated as side-by-side evidence. The comparison does not introduce a project-authored CNC semantics oracle.tests/fixtures/gcode_errors/g1_zero_feed.ngcandtests/fixtures/canon_errors/g1_zero_feed.expectedpin the negativeG1zero-feed case. The source basis is LinuxCNCinterp_convert.cc::convert_straight()andrs274ngc_return.hh::NCE_CANNOT_DO_G1_WITH_ZERO_FEED_RATE.- This proves the current extracted interpreter slice can parse and execute a small fixture set through a standalone canonical event sink.
- Important direction change: the minimal wrapper behavior is a migration
probe, not the program body. Do not expand it into a separate CNC
implementation. The next work must retire hand-written wrapper semantics and
move execution through vendored LinuxCNC interpreter source such as
interp_convert.cc,interp_read.cc,interp_check.cc, andinterp_execute.cc. tools/build_native_probes.shnow includeslinuxcnc_interp_convert_source_probe, which directly compiles vendoredinterp_convert.cc. The requiredemcStatusshim is limited to the native status boundary used bytag_arc()for machine units; it is not a project-authored CNC behavior implementation.tools/build_native_probes.shnow also includes direct source compile probes for vendoredinterp_read.cc,interp_check.cc, andinterp_execute.cc. These probes keep the next interpreter-core migration work focused on LinuxCNC source entry points and expose missing standalone runtime shims before wrapper behavior is expanded.- The direct source compile probes now cover the remaining vendored
rs274ngcinterpreter core files used by the standalone harness:modal_state.cc,interp_array.cc,interp_internal.cc,interp_arc.cc,interp_inverse.cc,interp_cycles.cc,interp_g7x.cc,interp_queue.cc,interp_find.cc,interp_namedparams.cc,interp_write.cc,interp_o_word.cc, andrs274ngc_pre.cc.rs274ngc_pre.ccis compiled with the existing standaloneUNIT_TEST/LINUXCNC_STANDALONE_USE_RS274_PRE_STATEboundary that isolates Python runtime integration from the browser simulation core. tools/build_native_probes.shnow includes direct source compile probes for the vendored LinuxCNC trajectory-planner and posemath files used bylinuxcnc_tp_api_probe:tp.c,tc.c,tcq.c,spherical_arc.c,blendmath.c,sp_scurve.c,ruckig_wrapper.c, the selectedcruckig/*.csources,emcpose.c,posemath.cc,_posemath.c, andsincos.c. These probes use the sameTP_FLAGSas the standalone TP harness, including the existing-fpermissiveboundary required by upstream enum conversions intp.c.tools/verify_vendor_sync.shnow validates the LinuxCNC source extraction boundary before native probes run. It rejects duplicate manifest entries, missing or extra vendored files, and byte-level drift between each manifest file undervendor/linuxcnc/and the matching file under../linuxcnc/.tools/source-manifest.txtwas also de-duplicated so the manifest is a single authoritative extraction list.- Direct source compile probes now also cover vendored
interp_base.ccandgomath.c.interp_base.ccuses a standaloneEMC2_HOMEcompile-time path boundary for LinuxCNC's dynamic interpreter lookup, andgomath.cis compiled as C withgccso its LinuxCNC C linkage is preserved. The standalonertapi.hshim was made C/C++ compatible for this C-source boundary without changing vendored LinuxCNC files. inifile.ccnow has its own direct source compile probe in addition to the existing INI parser harness. With this probe, every.cand.ccfile listed intools/source-manifest.txthas a native source-level compile check under the standalone build boundary.tools/build_native_probes.shnow emitsbuild/native/source-probes.tsvwhile compiling vendored*_source_probetargets. The native verification script compares that map against every.cand.ccentry intools/source-manifest.txt, so future LinuxCNC source additions fail validation unless they also get an explicit standalone source compile probe.tools/verify_no_standalone_cnc_semantics.shnow guards against reintroducing a standaloneInterp::convert_g()definition outsidevendor/linuxcnc/. This keeps G-code group conversion on the vendored LinuxCNCinterp_convert.ccpath instead of allowing the wrapper layer to grow another project-authored conversion implementation.docs/scope-and-baseline.mdrecords the current upstream LinuxCNC commit, local tool versions, and fixture baseline.tools/verify_upstream_baseline.shnow runs before vendor sync validation so extraction drift is checked against the intended upstream HEAD, not an accidental checkout change.docs/source-reuse-map.mdrecords the current vendored LinuxCNC source reuse matrix and dependency matrix, tying each extracted group to its standalone runtime boundary and validation path.docs/compatibility-validation.mdrecords the current validation chain, source coverage requirements, native harnesses, fixture coverage, and validation boundaries.docs/drift-report.mdrecords current no-drift enforcement, allowed standalone runtime boundaries, known gaps, and the current drift conclusion.
Phase 4: Port INI Parsing Without Editing Upstream
Purpose: Move LinuxCNC config parsing into the standalone runtime.
Steps:
- Vendor:
../linuxcnc/src/emc/ini/inifile.cc../linuxcnc/src/emc/ini/inifile.hh../linuxcnc/src/emc/ini/inifile.h
- Add shim headers under
wasm-port/runtime/core/shims/for small dependencies only. - Replace file loading through:
- wrapper-level adapter, preferred
- minimal vendored patch only if unavoidable
- Preserve:
#INCLUDE- relative includes
- recursion checks
- line continuation
- duplicate section merge behavior
- typed query behavior
- Add tests for INI semantics under
tests/native/.
Involved LinuxCNC source:
src/emc/ini/inifile.ccsrc/emc/ini/inifile.hhsrc/emc/ini/inifile.h
Phase 5: Port Parameter Tables and Variable Files
Purpose: Preserve LinuxCNC numeric parameter behavior exactly enough for simulation.
Steps:
- Vendor:
../linuxcnc/src/emc/rs274ngc/interp_parameter_def.hh../linuxcnc/src/emc/rs274ngc/interp_array.cc../linuxcnc/src/emc/rs274ngc/interp_internal.hh../linuxcnc/src/emc/rs274ngc/rs274ngc_pre.cc
- Extract:
setup.parameters[]required_parameters[]readonly_parameters[]- parameter file load/save logic
- Replace native file writes with a standalone file service abstraction.
- Keep LinuxCNC’s parameter text format in phase 1.
- Add regression tests for:
- missing file
- out-of-order parameters
- zero-fill behavior
- required parameter persistence
- read-only protection
Involved LinuxCNC source:
src/emc/rs274ngc/interp_parameter_def.hhsrc/emc/rs274ngc/interp_array.ccsrc/emc/rs274ngc/interp_internal.hhsrc/emc/rs274ngc/rs274ngc_pre.cc
Phase 6: Port Named Parameters and Interpreter State
Purpose: Preserve LinuxCNC variable semantics and controller-visible state.
Steps:
- Vendor:
../linuxcnc/src/emc/rs274ngc/interp_namedparams.cc../linuxcnc/src/emc/rs274ngc/interp_internal.hh../linuxcnc/src/emc/rs274ngc/interp_fwd.hh- selected interpreter files needed by setup/state handling
- Preserve:
context.named_paramsPA_READONLYPA_GLOBALPA_USE_LOOKUPPA_FROM_INI- built-in named parameters from
init_named_parameters()
- Preserve lookup order:
- local
- global
_ini[...]_hal[...]- optional Python providers later
- Export state outward rather than redesigning it in JS.
- Add regression cases for:
- local/global scoping
- built-in state variables
_ini[...]_hal[...]- read-only errors
Involved LinuxCNC source:
src/emc/rs274ngc/interp_namedparams.ccsrc/emc/rs274ngc/interp_internal.hhsrc/emc/rs274ngc/interp_fwd.hhsrc/emc/rs274ngc/interpmodule.cc
Phase 7: Replace HAL Runtime With a Simulation HAL Adapter
Purpose: Keep LinuxCNC interpreter-visible HAL behavior without migrating HAL itself.
Steps:
- Do not vendor the whole HAL runtime as a target runtime dependency.
- Use LinuxCNC HAL source as reference only for interface semantics:
../linuxcnc/src/hal/hal.h../linuxcnc/src/hal/halmodule.cc../linuxcnc/src/emc/ini/inihal.cc
- Define a standalone HAL adapter interface:
- lookup by name
- typed numeric value
- connection/existence status
- Make
_hal[...]reads resolve through this adapter. - Seed the adapter from simulation config and runtime state.
- Add tests for:
- existing names
- missing names
- disconnected signals
- type conversion
Involved LinuxCNC source:
src/hal/hal.hsrc/hal/halmodule.ccsrc/emc/rs274ngc/interp_namedparams.ccsrc/emc/ini/inihal.cc
Phase 8: Port the Interpreter Core
Purpose: Build the standalone G-code execution engine without touching upstream files.
Steps:
- Vendor selected files from
../linuxcnc/src/emc/rs274ngc/. - Keep original source as intact as possible in
vendor/. - Add wrappers or minimal patches only in the standalone area.
- Replace these external edges:
- file open/read
- world sync
- HAL reads
- logging
- runtime callbacks
- Preserve:
- modal state
- subroutines
- offsets
- tool handling
- parameter interactions
- error semantics
- Add a canonical event sink interface in standalone code.
Involved LinuxCNC source:
src/emc/rs274ngc/interp_execute.ccsrc/emc/rs274ngc/interp_read.ccsrc/emc/rs274ngc/interp_check.ccsrc/emc/rs274ngc/interp_convert.ccsrc/emc/rs274ngc/interp_cycles.ccsrc/emc/rs274ngc/interp_find.ccsrc/emc/rs274ngc/interp_write.ccsrc/emc/rs274ngc/interp_o_word.ccsrc/emc/rs274ngc/rs274ngc_pre.ccsrc/emc/rs274ngc/rs274ngc_interp.hh
Phase 9: Port Planner and Kinematics
Purpose: Preserve LinuxCNC motion planning and 5-axis simulation behavior.
Steps:
- Vendor selected planner files from
../linuxcnc/src/emc/tp/. - Vendor selected kinematics files from:
../linuxcnc/src/emc/kinematics/- selected
.compsources mirrored into standalone code where needed
- Replace loadable-module assumptions with a registry in the standalone runtime.
- Keep original math and state logic intact as far as practical.
- Add tests for:
- planner outputs
- forward/inverse kinematics
- 5-axis world/joint transforms
- LinuxCNC five-axis
M428/M429/M430remap assets and switchkins machine configuration links
Current five-axis switchkins status:
- Vendored LinuxCNC
5axiskins,xyzac-trt-kins, andxyzbc-trt-kinssources are compiled and probed natively. - Vendored LinuxCNC sample machine assets now cover bridge-mill, table-dual-rotary, and table-rotary-tilting INI/HAL/tool/demo/remap files.
M428,M429, andM430remain LinuxCNCREMAPentries backed by vendored LinuxCNC NGC subroutines; do not replace them with standalone M-code handlers.linuxcnc_remap_parse_harnessnow links vendoredinterp_remap.ccand validates the LinuxCNCInterp::parse_remap()path forxyzac-trtandxyzbc-trtM428/M429/M430NGC remap descriptors.linuxcnc_remap_hal_sync_harnessvalidates vendored LinuxCNCM68andM66synchronization through the standalone HAL adapter boundary.linuxcnc_5axis_remap_execute_harnessexecutes thexyzac-trtandxyzbc-trtswitchkinsM429 -> M428 -> M430 -> M429paths, loads vendored machine tool tables through LinuxCNCtooldata_load(), and runs vendoredxyzac_switchkins.ngc,xyzbc_switchkins.ngc,xyzac_switchkins_test_1.ngc,xyzac_switchkins_test_3.ngc,boat-xyzac.ngc,boat-xyzbc.ngc, andimpeller-7bl-xyzac.ngcthrough LinuxCNC remap/file execution paths.- The WASM interpreter core now links vendored
interp_remap.ccplus the Python-only runtime edge stub, and the Node WASM smoke runs vendoredxyzac_switchkins.ngc,xyzbc_switchkins.ngc,boat-xyzac.ngc, andboat-xyzbc.ngc, plusimpeller-7bl-xyzac.ngcthrough the SDK C ABI without JavaScript M-code or kinematics semantics. - Browser smoke and the INI panel UI now expose the same validated 5-axis remap execution path by copying vendored LinuxCNC sample-machine files into the interpreter WASM filesystem and calling the SDK C ABI.
Next work:
- Continue broadening five-axis fixture coverage through the same source-backed execution boundary.
- Evaluate additional vendored LinuxCNC five-axis sample machines and demos after the TRT boat and impeller demos are stable in native, Node WASM, browser, and UI remap paths.
Involved LinuxCNC source:
src/emc/tp/tp.csrc/emc/tp/tc.csrc/emc/tp/tcq.csrc/emc/tp/blendmath.csrc/emc/tp/sp_scurve.csrc/emc/tp/ruckig_wrapper.csrc/emc/kinematics/*.csrc/hal/components/xyzab_tdr_kins.compsrc/hal/components/xyzacb_trsrn.compsrc/hal/components/xyzbca_trsrn.compconfigs/sim/axis/vismach/5axis/bridgemill/*configs/sim/axis/vismach/5axis/table-dual-rotary/*configs/sim/axis/vismach/5axis/table-rotary-tilting/*
Phase 10: Build the Standalone WASM Program
Purpose: Keep the migrated program completely outside native LinuxCNC management.
Steps:
- Build the standalone native core first.
- Add a standalone WASM export layer under:
wasm-port/runtime/core/wasm-port/runtime/sdk/
- Use
vendor/sources plus standalone wrappers as build input. - Do not compile from
../linuxcncdirectly in the final WASM product build. - Emit:
wasmmodule- JS loader
- standalone SDK
Outputs:
- independently managed WASM simulation core
Phase 11: Build the Frontend and OPFS Layer
Purpose: Keep the standalone port program separate from LinuxCNC GUI code and storage.
Steps:
- Build frontend files under:
wasm-port/runtime/ui/wasm-port/runtime/opfs/
- Implement:
- HTML shell
- JavaScript control panel
- OPFS persistence
- file import/export
- machine/controller state views
- Keep LinuxCNC GUI code reference-only.
- Ensure the frontend depends only on the standalone SDK, not on native LinuxCNC binaries.
Outputs:
- standalone browser program
Phase 12: Validate Drift Against Upstream
Purpose: Prove the standalone port still tracks LinuxCNC behavior.
Steps:
- Use native LinuxCNC tests and fixtures as semantic baselines.
- Compare:
- LinuxCNC native behavior
- standalone native extracted core
- standalone WASM behavior
- Maintain a drift report.
- Re-run extraction if upstream source changes.
- Keep patches small and traceable.
Outputs:
- drift report
- compatibility regression suite
Management Rules For Daily Development
Use these rules continuously:
- Never edit files under
linuxcnc/as part of the port. - Any needed modification to upstream logic must be applied to vendored copies only.
- Any upstream sync must be script-driven and repeatable.
- Every shim must be documented.
- Every local patch against vendored source must be stored as a patch file or clearly isolated wrapper.
Recommended Document Set
Keep these documents under wasm-port/docs/:
scope-and-baseline.mdsource-reuse-map.mdstate-porting-strategy.mdwasm-build-strategy.mdfrontend-architecture.mdopfs-file-model.mdcompatibility-validation.mddrift-report.md
Immediate Next Step
Continue from the current verified extracted-core baseline without adding project-authored CNC semantics:
- Keep all
Interp::...interpreter member behavior on vendored LinuxCNC source. Standalone code may only provide documented runtime-edge stubs such as the current Python/remap boundary. - Expand WASM interpreter coverage by routing more existing native fixture
paths through
runtime/core/linuxcnc_wrap/linuxcnc_interp_wasm.cpp, using the same vendored interpreter source set as the native harness. - Promote remaining standalone-only fixture expectations to native LinuxCNC baselines where possible, especially adapter-heavy paths such as INI/HAL named parameters, tool-change host state, and richer machine session state.
- Move browser-facing work through SDK and OPFS adapters only after the core behavior is validated against native LinuxCNC or vendored-source harnesses.
- Before adding any CNC feature, update
tools/source-manifest.txt, extract the LinuxCNC source file, add a source probe or harness, and document the reuse boundary indocs/source-reuse-map.md.