按规划持续工作
结论:新增 vendored LinuxCNC trajectory planner WASM 构建和 Node smoke,覆盖线段、圆弧、队列规划探针,并纳入 host 聚合验证。
This commit is contained in:
@@ -24,6 +24,12 @@ The current WASM interpreter-core smoke validation command is:
|
|||||||
wasm-port/tests/wasm/node/verify_interp_wasm.sh
|
wasm-port/tests/wasm/node/verify_interp_wasm.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
|
The current WASM trajectory-planner smoke validation command is:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
wasm-port/tests/wasm/node/verify_tp_wasm.sh
|
||||||
|
```
|
||||||
|
|
||||||
The current OPFS host-boundary validation command is:
|
The current OPFS host-boundary validation command is:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
@@ -110,6 +116,13 @@ negative G-code fixtures into the Emscripten filesystem and verifies their
|
|||||||
LinuxCNC-produced error text through the `Interp::open()`/`read()`/`execute()`
|
LinuxCNC-produced error text through the `Interp::open()`/`read()`/`execute()`
|
||||||
file path.
|
file path.
|
||||||
|
|
||||||
|
The WASM trajectory-planner smoke script builds
|
||||||
|
`build/wasm/tp/linuxcnc_tp.js` and `linuxcnc_tp.wasm` from vendored LinuxCNC
|
||||||
|
TP, TC, TC queue, spherical-arc, blendmath, S-curve, Ruckig-wrapper, C Ruckig
|
||||||
|
support, emcpose, and posemath source files. It loads the module in Node and
|
||||||
|
calls the exported TP probe C ABI to validate the same LinuxCNC linear, arc,
|
||||||
|
and queued-line planner calls covered by the native `linuxcnc_tp_api_probe`.
|
||||||
|
|
||||||
The OPFS host-boundary script validates the JavaScript file-service adapter
|
The OPFS host-boundary script validates the JavaScript file-service adapter
|
||||||
with a Node mock of the browser File System Access handles. It covers nested
|
with a Node mock of the browser File System Access handles. It covers nested
|
||||||
directory creation, text save/load, missing file behavior, invalid relative
|
directory creation, text save/load, missing file behavior, invalid relative
|
||||||
@@ -172,9 +185,9 @@ override INI-derived names before OPFS text is copied into the LinuxCNC-backed
|
|||||||
WASM filesystem, and that absent INI file-name values use the default OPFS
|
WASM filesystem, and that absent INI file-name values use the default OPFS
|
||||||
parameter/tool-table paths in a real browser session.
|
parameter/tool-table paths in a real browser session.
|
||||||
|
|
||||||
The aggregate host smoke script builds the INI and interpreter-core WASM
|
The aggregate host smoke script builds the INI, interpreter-core, and
|
||||||
artifacts once, then runs the Node WASM smokes, the Node OPFS mock smoke, and
|
trajectory-planner WASM artifacts once, then runs the Node WASM smokes, the
|
||||||
the Chromium browser smokes.
|
Node OPFS mock smoke, and the Chromium browser smokes.
|
||||||
|
|
||||||
## Source Coverage
|
## Source Coverage
|
||||||
|
|
||||||
@@ -224,10 +237,11 @@ The validation fails if:
|
|||||||
| --- | --- |
|
| --- | --- |
|
||||||
| `tests/wasm/node/verify_ini_wasm.sh` | Validates the browser-facing INI WASM module can be built from vendored LinuxCNC `inifile.cc`, loaded through the JS SDK in Node, and queried through the exported C ABI, including LinuxCNC-backed boolean conversion and machine-session file-name string lookup. |
|
| `tests/wasm/node/verify_ini_wasm.sh` | Validates the browser-facing INI WASM module can be built from vendored LinuxCNC `inifile.cc`, loaded through the JS SDK in Node, and queried through the exported C ABI, including LinuxCNC-backed boolean conversion and machine-session file-name string lookup. |
|
||||||
| `tests/wasm/node/verify_interp_wasm.sh` | Validates the initial interpreter-core WASM module can be built from vendored LinuxCNC interpreter source, loaded through the interpreter JS SDK, run the first fixture group through `Interp::execute()` and selected file fixtures through `Interp::open()`/`read()`/`execute()`, match the native canonical event plus required state readback fixtures, and run parameter-file restore/save through vendored LinuxCNC `Interp::restore_parameters()` and `Interp::save_parameters()`. |
|
| `tests/wasm/node/verify_interp_wasm.sh` | Validates the initial interpreter-core WASM module can be built from vendored LinuxCNC interpreter source, loaded through the interpreter JS SDK, run the first fixture group through `Interp::execute()` and selected file fixtures through `Interp::open()`/`read()`/`execute()`, match the native canonical event plus required state readback fixtures, and run parameter-file restore/save through vendored LinuxCNC `Interp::restore_parameters()` and `Interp::save_parameters()`. |
|
||||||
|
| `tests/wasm/node/verify_tp_wasm.sh` | Validates a standalone trajectory-planner WASM module can be built from vendored LinuxCNC TP/TC/Ruckig support source, loaded in Node, and run the same linear, arc, and queued-line planner probe paths covered by the native TP harness. |
|
||||||
| `tests/opfs/node/verify_file_service.sh` | Validates the host-owned OPFS text-file adapter, path model, session snapshot store including custom filenames and envelope/path rejection paths, machine file store, G-code text store including filename rejection paths, OPFS-to-WASM parameter/tool-table bridges, and grouped machine-session loading without moving file persistence, parameter semantics, or tool-table semantics into the WASM core. |
|
| `tests/opfs/node/verify_file_service.sh` | Validates the host-owned OPFS text-file adapter, path model, session snapshot store including custom filenames and envelope/path rejection paths, machine file store, G-code text store including filename rejection paths, OPFS-to-WASM parameter/tool-table bridges, and grouped machine-session loading without moving file persistence, parameter semantics, or tool-table semantics into the WASM core. |
|
||||||
| `tests/browser/verify_ini_panel_browser.sh` | Validates the INI SDK, INI/interpreter WASM module loading, LinuxCNC-backed INI machine-session file-name string lookup, OPFS text-file round trip, generic session snapshot round trip plus custom filename and envelope/path rejection paths, machine file text round trip, G-code text round trip plus filename rejection paths, and the INI panel UI's machine-session load with default OPFS parameter/tool-table file mapping, G-code run, and canonical-event display paths in a real browser runtime. |
|
| `tests/browser/verify_ini_panel_browser.sh` | Validates the INI SDK, INI/interpreter WASM module loading, LinuxCNC-backed INI machine-session file-name string lookup, OPFS text-file round trip, generic session snapshot round trip plus custom filename and envelope/path rejection paths, machine file text round trip, G-code text round trip plus filename rejection paths, and the INI panel UI's machine-session load with default OPFS parameter/tool-table file mapping, G-code run, and canonical-event display paths in a real browser runtime. |
|
||||||
| `tests/browser/verify_interp_browser.sh` | Validates the interpreter-core WASM module loads through the interpreter JS SDK in a real browser runtime and runs selected positive and negative canonical fixtures through vendored LinuxCNC `Interp::execute()` plus `Interp::open()`/`read()`/`execute()` via the exported C ABI, including direct browser SDK and OPFS-backed parameter-file restore/save plus non-random/random tool-table load/save through vendored LinuxCNC source. |
|
| `tests/browser/verify_interp_browser.sh` | Validates the interpreter-core WASM module loads through the interpreter JS SDK in a real browser runtime and runs selected positive and negative canonical fixtures through vendored LinuxCNC `Interp::execute()` plus `Interp::open()`/`read()`/`execute()` via the exported C ABI, including direct browser SDK and OPFS-backed parameter-file restore/save plus non-random/random tool-table load/save through vendored LinuxCNC source. |
|
||||||
| `tests/host/verify_host_smokes.sh` | Runs the current host-side Node, WASM interpreter-core, OPFS, and browser smoke validation with shared WASM builds. |
|
| `tests/host/verify_host_smokes.sh` | Runs the current host-side Node, WASM interpreter-core, WASM trajectory-planner, OPFS, and browser smoke validation with shared WASM builds. |
|
||||||
|
|
||||||
## Fixture Coverage
|
## Fixture Coverage
|
||||||
|
|
||||||
|
|||||||
@@ -36,14 +36,14 @@ Current validation is intentionally mechanical:
|
|||||||
| INI parsing | `src/emc/ini/inifile.cc`, `inifile.h`, `inifile.hh` | Copy unchanged | Native file IO remains LinuxCNC-style in the vendored parser; browser OPFS integration remains outside this layer; `runtime/sdk/src/index.js` exports the INI SDK wrapper around the generated WASM C ABI, including LinuxCNC `iniFindBool()` for machine-session flags and LinuxCNC string lookup for INI-declared `[RS274NGC]PARAMETER_FILE` and `[EMCIO]TOOL_TABLE` machine file names | Vendor byte sync, `linuxcnc_ini_probe`, `linuxcnc_inifile_source_probe`, `tests/wasm/node/verify_ini_wasm.sh` boolean plus file-name lookup assertions, `tests/browser/verify_ini_panel_browser.sh`, `tests/host/verify_host_smokes.sh` |
|
| INI parsing | `src/emc/ini/inifile.cc`, `inifile.h`, `inifile.hh` | Copy unchanged | Native file IO remains LinuxCNC-style in the vendored parser; browser OPFS integration remains outside this layer; `runtime/sdk/src/index.js` exports the INI SDK wrapper around the generated WASM C ABI, including LinuxCNC `iniFindBool()` for machine-session flags and LinuxCNC string lookup for INI-declared `[RS274NGC]PARAMETER_FILE` and `[EMCIO]TOOL_TABLE` machine file names | Vendor byte sync, `linuxcnc_ini_probe`, `linuxcnc_inifile_source_probe`, `tests/wasm/node/verify_ini_wasm.sh` boolean plus file-name lookup assertions, `tests/browser/verify_ini_panel_browser.sh`, `tests/host/verify_host_smokes.sh` |
|
||||||
| RTAPI compatibility headers | `src/rtapi/rtapi_*.h` in the manifest | Copy unchanged plus standalone shim include path | `runtime/core/shims/rtapi.h` supplies the minimal standalone RTAPI surface needed by vendored code | Vendor byte sync, compile coverage through dependent source probes |
|
| RTAPI compatibility headers | `src/rtapi/rtapi_*.h` in the manifest | Copy unchanged plus standalone shim include path | `runtime/core/shims/rtapi.h` supplies the minimal standalone RTAPI surface needed by vendored code | Vendor byte sync, compile coverage through dependent source probes |
|
||||||
| Canon/NML-facing interpreter types | `src/emc/nml_intf/canon*.hh`, `emctool.h`, `interp_return.hh`, `motion_types.h`, `emcpose.*`, `emcpos.h`, `debugflags.h`, `src/emc/linuxcnc.h` | Copy unchanged plus narrow standalone status shim | NML transport is not ported; `runtime/core/shims/nml_intf/emc.hh` exposes only the `emcStatus` machine-units status edge currently needed by vendored interpreter conversion and initialization code | Vendor byte sync, dependent source probes, `linuxcnc_emc_status_probe`, `linuxcnc_tp_api_probe`, interpreter harnesses, `tests/wasm/node/verify_interp_wasm.sh` and `tests/browser/verify_interp_browser.sh` `Interp::init()` machine-unit assertions |
|
| Canon/NML-facing interpreter types | `src/emc/nml_intf/canon*.hh`, `emctool.h`, `interp_return.hh`, `motion_types.h`, `emcpose.*`, `emcpos.h`, `debugflags.h`, `src/emc/linuxcnc.h` | Copy unchanged plus narrow standalone status shim | NML transport is not ported; `runtime/core/shims/nml_intf/emc.hh` exposes only the `emcStatus` machine-units status edge currently needed by vendored interpreter conversion and initialization code | Vendor byte sync, dependent source probes, `linuxcnc_emc_status_probe`, `linuxcnc_tp_api_probe`, interpreter harnesses, `tests/wasm/node/verify_interp_wasm.sh` and `tests/browser/verify_interp_browser.sh` `Interp::init()` machine-unit assertions |
|
||||||
| Motion state headers | `src/emc/motion/state_tag.h`, `emcmotcfg.h`, `simple_tp.h`, `motion.h`, `mot_priv.h`, `axis.h` | Copy unchanged | Realtime motion process is not ported; standalone probes seed the small motion status/config state required by TP calls | Vendor byte sync, `linuxcnc_tp_api_probe` |
|
| Motion state headers | `src/emc/motion/state_tag.h`, `emcmotcfg.h`, `simple_tp.h`, `motion.h`, `mot_priv.h`, `axis.h` | Copy unchanged | Realtime motion process is not ported; standalone probes seed the small motion status/config state required by TP calls | Vendor byte sync, `linuxcnc_tp_api_probe`, `tests/wasm/node/verify_tp_wasm.sh` |
|
||||||
| Identity/trivial kinematics | `src/emc/kinematics/kinematics.h`, `cubic.h`, `kins_util.c`, `trivkins.c` | Copy unchanged | HAL component lifecycle and RTAPI module metadata are replaced by standalone shims; forward/inverse mapping behavior remains LinuxCNC source | Vendor byte sync, per-file source probes, `linuxcnc_kinematics_probe` |
|
| Identity/trivial kinematics | `src/emc/kinematics/kinematics.h`, `cubic.h`, `kins_util.c`, `trivkins.c` | Copy unchanged | HAL component lifecycle and RTAPI module metadata are replaced by standalone shims; forward/inverse mapping behavior remains LinuxCNC source | Vendor byte sync, per-file source probes, `linuxcnc_kinematics_probe` |
|
||||||
| Switchable 5-axis bridge kinematics | `src/emc/kinematics/5axiskins.c`, `switchkins.c`, `switchkins.h`, `userkfuncs.c`, plus `src/rtapi/rtapi_ctype.h` | Copy unchanged | HAL pin allocation, HAL component lifecycle, and RTAPI module metadata are standalone runtime edges; switchable 5-axis forward/inverse behavior remains LinuxCNC source | Vendor byte sync, per-file source probes, `linuxcnc_5axis_kinematics_probe` |
|
| Switchable 5-axis bridge kinematics | `src/emc/kinematics/5axiskins.c`, `switchkins.c`, `switchkins.h`, `userkfuncs.c`, plus `src/rtapi/rtapi_ctype.h` | Copy unchanged | HAL pin allocation, HAL component lifecycle, and RTAPI module metadata are standalone runtime edges; switchable 5-axis forward/inverse behavior remains LinuxCNC source | Vendor byte sync, per-file source probes, `linuxcnc_5axis_kinematics_probe` |
|
||||||
| TRT table-rotary kinematics | `src/emc/kinematics/trtfuncs.c`, `xyzac-trt-kins.c`, `xyzbc-trt-kins.c` | Copy unchanged | HAL pin allocation and switchkins lifecycle stay runtime boundaries; XYZAC/XYZBC TRT forward/inverse behavior remains LinuxCNC source | Vendor byte sync, per-file source probes, `linuxcnc_xyzac_trt_kinematics_probe`, `linuxcnc_xyzbc_trt_kinematics_probe` |
|
| TRT table-rotary kinematics | `src/emc/kinematics/trtfuncs.c`, `xyzac-trt-kins.c`, `xyzbc-trt-kins.c` | Copy unchanged | HAL pin allocation and switchkins lifecycle stay runtime boundaries; XYZAC/XYZBC TRT forward/inverse behavior remains LinuxCNC source | Vendor byte sync, per-file source probes, `linuxcnc_xyzac_trt_kinematics_probe`, `linuxcnc_xyzbc_trt_kinematics_probe` |
|
||||||
| Additional non-switchable kinematics | `src/emc/kinematics/corexykins.c`, `rotatekins.c`, `rosekins.c`, `maxkins.c`, `lineardeltakins.c`, `lineardeltakins-common.h`, `rotarydeltakins.c`, `rotarydeltakins-common.h`, `scorbot-kins.c`, `tripodkins.c`, `scarakins.c`, `pumakins.c`, `pumakins.h`, `genhexkins.c`, `genhexkins.h`, `genserfuncs.c`, `genserkins.c`, `genserkins.h`, `ugenserkins.c`, `pentakins.c`, `pentakins.h`, `cubic.c` | Copy unchanged | HAL pin allocation, HAL parameter allocation, HAL component lifecycle, RTAPI module metadata, Go math C/C++ linkage, switchkins iterative-forward warmup, and userspace test-program process entry remain standalone runtime edges; forward/inverse behavior remains LinuxCNC source where the module exposes it | Vendor byte sync, per-file source probes, `linuxcnc_corexy_kinematics_probe`, `linuxcnc_rotate_kinematics_probe`, `linuxcnc_rose_kinematics_probe`, `linuxcnc_max_kinematics_probe`, `linuxcnc_lineardelta_kinematics_probe`, `linuxcnc_rotarydelta_kinematics_probe`, `linuxcnc_scorbot_kinematics_probe`, `linuxcnc_tripod_kinematics_probe`, `linuxcnc_scara_kinematics_probe`, `linuxcnc_puma_kinematics_probe`, `linuxcnc_genser_kinematics_probe`, `linuxcnc_genhex_kinematics_probe`, `linuxcnc_pentakins_kinematics_probe` |
|
| Additional non-switchable kinematics | `src/emc/kinematics/corexykins.c`, `rotatekins.c`, `rosekins.c`, `maxkins.c`, `lineardeltakins.c`, `lineardeltakins-common.h`, `rotarydeltakins.c`, `rotarydeltakins-common.h`, `scorbot-kins.c`, `tripodkins.c`, `scarakins.c`, `pumakins.c`, `pumakins.h`, `genhexkins.c`, `genhexkins.h`, `genserfuncs.c`, `genserkins.c`, `genserkins.h`, `ugenserkins.c`, `pentakins.c`, `pentakins.h`, `cubic.c` | Copy unchanged | HAL pin allocation, HAL parameter allocation, HAL component lifecycle, RTAPI module metadata, Go math C/C++ linkage, switchkins iterative-forward warmup, and userspace test-program process entry remain standalone runtime edges; forward/inverse behavior remains LinuxCNC source where the module exposes it | Vendor byte sync, per-file source probes, `linuxcnc_corexy_kinematics_probe`, `linuxcnc_rotate_kinematics_probe`, `linuxcnc_rose_kinematics_probe`, `linuxcnc_max_kinematics_probe`, `linuxcnc_lineardelta_kinematics_probe`, `linuxcnc_rotarydelta_kinematics_probe`, `linuxcnc_scorbot_kinematics_probe`, `linuxcnc_tripod_kinematics_probe`, `linuxcnc_scara_kinematics_probe`, `linuxcnc_puma_kinematics_probe`, `linuxcnc_genser_kinematics_probe`, `linuxcnc_genhex_kinematics_probe`, `linuxcnc_pentakins_kinematics_probe` |
|
||||||
| Trajectory planner | `src/emc/tp/tp.c`, `tc.c`, `tcq.c`, `spherical_arc.c`, `blendmath.c`, `sp_scurve.c`, `ruckig_wrapper.c`, plus matching `*.h` files | Copy unchanged | Native realtime scheduling and motion process state are replaced by standalone probe setup | Vendor byte sync, per-file source probes, `linuxcnc_tp_api_probe` |
|
| Trajectory planner | `src/emc/tp/tp.c`, `tc.c`, `tcq.c`, `spherical_arc.c`, `blendmath.c`, `sp_scurve.c`, `ruckig_wrapper.c`, plus matching `*.h` files | Copy unchanged | Native realtime scheduling and motion process state are replaced by standalone probe setup; the WASM TP probe uses the same deterministic status/config boundary and calls vendored TP APIs through a narrow C ABI | Vendor byte sync, per-file source probes, `linuxcnc_tp_api_probe`, `tests/wasm/node/verify_tp_wasm.sh` |
|
||||||
| Ruckig C planner support | Selected `src/emc/tp/cruckig/*.c` and `*.h` files in the manifest | Copy unchanged | Used as LinuxCNC planner support code through vendored TP sources | Vendor byte sync, per-file source probes |
|
| Ruckig C planner support | Selected `src/emc/tp/cruckig/*.c` and `*.h` files in the manifest | Copy unchanged | Used as LinuxCNC planner support code through vendored TP sources | Vendor byte sync, per-file source probes, `tests/wasm/node/verify_tp_wasm.sh` |
|
||||||
| Posemath | `src/libnml/posemath/posemath.cc`, `_posemath.c`, `gomath.c`, `sincos.c`, and matching headers | Copy unchanged | `gomath.c` is compiled as C; `rtapi.h` shim is C/C++ compatible for this boundary | Vendor byte sync, per-file source probes, TP probe |
|
| Posemath | `src/libnml/posemath/posemath.cc`, `_posemath.c`, `gomath.c`, `sincos.c`, and matching headers | Copy unchanged | `gomath.c` is compiled as C; `rtapi.h` shim is C/C++ compatible for this boundary | Vendor byte sync, per-file source probes, TP native and WASM probes |
|
||||||
| RS274 interpreter state and parser | `src/emc/rs274ngc/modal_state.*`, `interp_internal.*`, `interp_read.cc`, `interp_check.cc`, `interp_execute.cc`, `interp_find.cc`, `interp_array.cc`, `interp_queue.*`, `rs274ngc*`, `units.h` | Copy unchanged | Python/remap/runtime edges are isolated in standalone wrappers and shims; parser and execution logic remain LinuxCNC source | Vendor byte sync, per-file source probes, interpreter harness fixtures |
|
| RS274 interpreter state and parser | `src/emc/rs274ngc/modal_state.*`, `interp_internal.*`, `interp_read.cc`, `interp_check.cc`, `interp_execute.cc`, `interp_find.cc`, `interp_array.cc`, `interp_queue.*`, `rs274ngc*`, `units.h` | Copy unchanged | Python/remap/runtime edges are isolated in standalone wrappers and shims; parser and execution logic remain LinuxCNC source | Vendor byte sync, per-file source probes, interpreter harness fixtures |
|
||||||
| RS274 conversion semantics | `src/emc/rs274ngc/interp_convert.cc`, `interp_arc.cc`, `interp_inverse.cc`, `interp_cycles.cc`, `interp_g7x.cc`, `interp_o_word.cc`, `interp_write.cc` | Copy unchanged | Canonical calls are captured by standalone event sink functions; conversion behavior stays in vendored LinuxCNC files; feed-rate state is read back through the canonical runtime boundary during length-unit conversion; single-axis rotary indexer lock/unlock dispatch remains vendored LinuxCNC `issue_straight_index()` behavior | Vendor byte sync, per-file source probes, canonical fixture suite, no standalone `Interp::convert_g()` guard, `linuxcnc_indexer_harness`, `tests/wasm/node/verify_interp_wasm.sh` and `tests/browser/verify_interp_browser.sh` rotary-indexer assertions |
|
| RS274 conversion semantics | `src/emc/rs274ngc/interp_convert.cc`, `interp_arc.cc`, `interp_inverse.cc`, `interp_cycles.cc`, `interp_g7x.cc`, `interp_o_word.cc`, `interp_write.cc` | Copy unchanged | Canonical calls are captured by standalone event sink functions; conversion behavior stays in vendored LinuxCNC files; feed-rate state is read back through the canonical runtime boundary during length-unit conversion; single-axis rotary indexer lock/unlock dispatch remains vendored LinuxCNC `issue_straight_index()` behavior | Vendor byte sync, per-file source probes, canonical fixture suite, no standalone `Interp::convert_g()` guard, `linuxcnc_indexer_harness`, `tests/wasm/node/verify_interp_wasm.sh` and `tests/browser/verify_interp_browser.sh` rotary-indexer assertions |
|
||||||
| Named parameters and tool slot status | `src/emc/rs274ngc/interp_namedparams.cc`, related interpreter headers | Copy unchanged | `_ini[...]` and `_hal[...]` resolve through standalone INI/HAL adapters while lookup order stays LinuxCNC-derived; current/selected tool slot reads for vendored `Interp::synch()` come from the standalone tool adapter | Vendor byte sync, source probe, `linuxcnc_namedparam_harness`, `linuxcnc_interp_init_harness`, `tests/wasm/node/verify_interp_wasm.sh` and `tests/browser/verify_interp_browser.sh` `Interp::synch()` tool-slot assertions plus `Interp::init_named_parameters()`/`find_named_param()` named-parameter lookup assertions |
|
| Named parameters and tool slot status | `src/emc/rs274ngc/interp_namedparams.cc`, related interpreter headers | Copy unchanged | `_ini[...]` and `_hal[...]` resolve through standalone INI/HAL adapters while lookup order stays LinuxCNC-derived; current/selected tool slot reads for vendored `Interp::synch()` come from the standalone tool adapter | Vendor byte sync, source probe, `linuxcnc_namedparam_harness`, `linuxcnc_interp_init_harness`, `tests/wasm/node/verify_interp_wasm.sh` and `tests/browser/verify_interp_browser.sh` `Interp::synch()` tool-slot assertions plus `Interp::init_named_parameters()`/`find_named_param()` named-parameter lookup assertions |
|
||||||
@@ -71,14 +71,15 @@ Current validation is intentionally mechanical:
|
|||||||
userspace genser flows are not yet established.
|
userspace genser flows are not yet established.
|
||||||
- Cutter compensation positive motion and negative interpreter paths are
|
- Cutter compensation positive motion and negative interpreter paths are
|
||||||
fixture-covered through vendored `interp_convert.cc` and `interp_queue.cc`.
|
fixture-covered through vendored `interp_convert.cc` and `interp_queue.cc`.
|
||||||
- Browser/WASM C ABI and JS SDK layers are now present for the INI parser and
|
- Browser/WASM C ABI and JS SDK layers are now present for the INI parser, the
|
||||||
the current interpreter-core smoke scope. The interpreter SDK is a thin
|
current interpreter-core smoke scope, and a trajectory-planner TP probe. The interpreter SDK is a thin
|
||||||
allocation, filesystem, and C ABI wrapper over vendored LinuxCNC execution
|
allocation, filesystem, and C ABI wrapper over vendored LinuxCNC execution
|
||||||
paths, including parameter-file restore/save through vendored
|
paths, including parameter-file restore/save through vendored
|
||||||
`rs274ngc_pre.cc` and non-random/random tool-table load/save through
|
`rs274ngc_pre.cc` and non-random/random tool-table load/save through
|
||||||
vendored `tooldata_common.cc`; it does not define G-code, parameter, or
|
vendored `tooldata_common.cc`; it does not define G-code, parameter, or
|
||||||
tool-table semantics. Full planner/session SDK coverage remains future
|
tool-table semantics. The TP WASM probe calls vendored LinuxCNC planner APIs
|
||||||
work.
|
directly and does not expose a browser planner SDK yet; full planner/session
|
||||||
|
SDK coverage remains future work.
|
||||||
- OPFS persistence is connected to the INI panel through the host-side
|
- OPFS persistence is connected to the INI panel through the host-side
|
||||||
`runtime/opfs/file-service.js` adapter. `runtime/opfs/path-model.js` now
|
`runtime/opfs/file-service.js` adapter. `runtime/opfs/path-model.js` now
|
||||||
defines paths for INI, tool table, parameter file, G-code program,
|
defines paths for INI, tool table, parameter file, G-code program,
|
||||||
|
|||||||
442
wasm-port/runtime/core/linuxcnc_wrap/linuxcnc_tp_wasm.c
Normal file
442
wasm-port/runtime/core/linuxcnc_wrap/linuxcnc_tp_wasm.c
Normal file
@@ -0,0 +1,442 @@
|
|||||||
|
#include <math.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include <emscripten/emscripten.h>
|
||||||
|
|
||||||
|
#include "emc/motion/motion.h"
|
||||||
|
#include "emc/nml_intf/motion_types.h"
|
||||||
|
#include "emc/tp/tp.h"
|
||||||
|
|
||||||
|
static emcmot_status_t status;
|
||||||
|
static emcmot_config_t config;
|
||||||
|
|
||||||
|
static void dio_write(int index, char value)
|
||||||
|
{
|
||||||
|
(void)index;
|
||||||
|
(void)value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void aio_write(int index, double value)
|
||||||
|
{
|
||||||
|
(void)index;
|
||||||
|
(void)value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void set_rotary_unlock(int joint, int unlock)
|
||||||
|
{
|
||||||
|
(void)joint;
|
||||||
|
(void)unlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int get_rotary_unlock(int joint)
|
||||||
|
{
|
||||||
|
(void)joint;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static double axis_vel_limit(int axis)
|
||||||
|
{
|
||||||
|
return axis >= 0 && axis < EMCMOT_MAX_AXIS ? 10.0 : 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static double axis_acc_limit(int axis)
|
||||||
|
{
|
||||||
|
return axis >= 0 && axis < EMCMOT_MAX_AXIS ? 20.0 : 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void init_motion_state(void)
|
||||||
|
{
|
||||||
|
memset(&status, 0, sizeof(status));
|
||||||
|
memset(&config, 0, sizeof(config));
|
||||||
|
|
||||||
|
config.numJoints = 3;
|
||||||
|
config.numSpindles = 1;
|
||||||
|
config.numDIO = 4;
|
||||||
|
config.numAIO = 4;
|
||||||
|
config.arcBlendOptDepth = 0;
|
||||||
|
config.arcBlendEnable = 0;
|
||||||
|
config.arcBlendFallbackEnable = 0;
|
||||||
|
config.arcBlendGapCycles = 4;
|
||||||
|
config.arcBlendRampFreq = 20.0;
|
||||||
|
config.arcBlendTangentKinkRatio = 0.1;
|
||||||
|
config.maxFeedScale = 1.0;
|
||||||
|
|
||||||
|
status.net_feed_scale = 1.0;
|
||||||
|
status.feed_scale = 1.0;
|
||||||
|
status.rapid_scale = 1.0;
|
||||||
|
status.enables_new = FS_ENABLED | SS_ENABLED;
|
||||||
|
status.enables_queued = status.enables_new;
|
||||||
|
status.spindle_status[0].at_speed = 1;
|
||||||
|
status.spindle_status[0].direction = 1;
|
||||||
|
status.spindleSync = 0;
|
||||||
|
status.jerk = 0.0;
|
||||||
|
status.planner_type = 0;
|
||||||
|
|
||||||
|
tpMotData(&status, &config);
|
||||||
|
tpMotFunctions(
|
||||||
|
dio_write,
|
||||||
|
aio_write,
|
||||||
|
set_rotary_unlock,
|
||||||
|
get_rotary_unlock,
|
||||||
|
axis_vel_limit,
|
||||||
|
axis_acc_limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int pose_near(const EmcPose *actual, const EmcPose *expected)
|
||||||
|
{
|
||||||
|
return fabs(actual->tran.x - expected->tran.x) < 1e-9 &&
|
||||||
|
fabs(actual->tran.y - expected->tran.y) < 1e-9 &&
|
||||||
|
fabs(actual->tran.z - expected->tran.z) < 1e-9;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void append(char *out, size_t size, size_t *offset, const char *text)
|
||||||
|
{
|
||||||
|
if (*offset >= size) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const int written = snprintf(out + *offset, size - *offset, "%s", text);
|
||||||
|
if (written > 0) {
|
||||||
|
*offset += (size_t)written;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void append_linear_probe(char *out, size_t size, size_t *offset)
|
||||||
|
{
|
||||||
|
init_motion_state();
|
||||||
|
|
||||||
|
TP_STRUCT tp;
|
||||||
|
EmcPose start;
|
||||||
|
EmcPose end;
|
||||||
|
struct state_tag_t tag;
|
||||||
|
memset(&tp, 0, sizeof(tp));
|
||||||
|
memset(&start, 0, sizeof(start));
|
||||||
|
memset(&end, 0, sizeof(end));
|
||||||
|
memset(&tag, 0, sizeof(tag));
|
||||||
|
|
||||||
|
end.tran.x = 1.0;
|
||||||
|
|
||||||
|
const int create_rc = tpCreate(&tp, TP_DEFAULT_QUEUE_SIZE, 1);
|
||||||
|
const int set_cycle_rc = tpSetCycleTime(&tp, 0.001);
|
||||||
|
const int set_pos_rc = tpSetPos(&tp, &start);
|
||||||
|
const int set_vmax_rc = tpSetVmax(&tp, 1.0, 1.0);
|
||||||
|
const int set_vlimit_rc = tpSetVlimit(&tp, 1.0);
|
||||||
|
const int set_amax_rc = tpSetAmax(&tp, 10.0);
|
||||||
|
const int set_term_rc = tpSetTermCond(&tp, TC_TERM_COND_STOP, 0.0);
|
||||||
|
const int add_line_rc = tpAddLine(
|
||||||
|
&tp,
|
||||||
|
end,
|
||||||
|
EMC_MOTION_TYPE_FEED,
|
||||||
|
1.0,
|
||||||
|
1.0,
|
||||||
|
10.0,
|
||||||
|
100.0,
|
||||||
|
status.enables_new,
|
||||||
|
0,
|
||||||
|
-1,
|
||||||
|
tag);
|
||||||
|
|
||||||
|
int cycle_rc = 0;
|
||||||
|
int cycles = 0;
|
||||||
|
for (; cycles < 10000 && !tpIsDone(&tp); ++cycles) {
|
||||||
|
cycle_rc = tpRunCycle(&tp, 1000000);
|
||||||
|
if (cycle_rc < 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
EmcPose final_pos;
|
||||||
|
memset(&final_pos, 0, sizeof(final_pos));
|
||||||
|
const int get_pos_rc = tpGetPos(&tp, &final_pos);
|
||||||
|
|
||||||
|
char line[1024];
|
||||||
|
snprintf(line, sizeof(line),
|
||||||
|
"tp_create=%d\n"
|
||||||
|
"tp_set_cycle_time=%d\n"
|
||||||
|
"tp_set_pos=%d\n"
|
||||||
|
"tp_set_vmax=%d\n"
|
||||||
|
"tp_set_vlimit=%d\n"
|
||||||
|
"tp_set_amax=%d\n"
|
||||||
|
"tp_set_term_cond=%d\n"
|
||||||
|
"tp_add_line=%d\n"
|
||||||
|
"tp_cycle_rc=%d\n"
|
||||||
|
"tp_cycles=%d\n"
|
||||||
|
"tp_get_pos=%d\n"
|
||||||
|
"tp_done_after_line=%d\n"
|
||||||
|
"tp_queue_depth=%d\n"
|
||||||
|
"tp_final_pos=%.12g,%.12g,%.12g\n",
|
||||||
|
create_rc,
|
||||||
|
set_cycle_rc,
|
||||||
|
set_pos_rc,
|
||||||
|
set_vmax_rc,
|
||||||
|
set_vlimit_rc,
|
||||||
|
set_amax_rc,
|
||||||
|
set_term_rc,
|
||||||
|
add_line_rc,
|
||||||
|
cycle_rc,
|
||||||
|
cycles,
|
||||||
|
get_pos_rc,
|
||||||
|
tpIsDone(&tp),
|
||||||
|
tpQueueDepth(&tp),
|
||||||
|
final_pos.tran.x,
|
||||||
|
final_pos.tran.y,
|
||||||
|
final_pos.tran.z);
|
||||||
|
append(out, size, offset, line);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void append_arc_probe(char *out, size_t size, size_t *offset)
|
||||||
|
{
|
||||||
|
init_motion_state();
|
||||||
|
|
||||||
|
TP_STRUCT tp;
|
||||||
|
EmcPose start;
|
||||||
|
EmcPose end;
|
||||||
|
PmCartesian center;
|
||||||
|
PmCartesian normal;
|
||||||
|
struct state_tag_t tag;
|
||||||
|
memset(&tp, 0, sizeof(tp));
|
||||||
|
memset(&start, 0, sizeof(start));
|
||||||
|
memset(&end, 0, sizeof(end));
|
||||||
|
memset(¢er, 0, sizeof(center));
|
||||||
|
memset(&normal, 0, sizeof(normal));
|
||||||
|
memset(&tag, 0, sizeof(tag));
|
||||||
|
|
||||||
|
start.tran.x = 1.0;
|
||||||
|
end.tran.y = 1.0;
|
||||||
|
normal.z = 1.0;
|
||||||
|
|
||||||
|
const int create_rc = tpCreate(&tp, TP_DEFAULT_QUEUE_SIZE, 2);
|
||||||
|
const int set_cycle_rc = tpSetCycleTime(&tp, 0.001);
|
||||||
|
const int set_pos_rc = tpSetPos(&tp, &start);
|
||||||
|
const int set_vmax_rc = tpSetVmax(&tp, 1.0, 1.0);
|
||||||
|
const int set_vlimit_rc = tpSetVlimit(&tp, 1.0);
|
||||||
|
const int set_amax_rc = tpSetAmax(&tp, 10.0);
|
||||||
|
const int set_term_rc = tpSetTermCond(&tp, TC_TERM_COND_STOP, 0.0);
|
||||||
|
const int add_circle_rc = tpAddCircle(
|
||||||
|
&tp,
|
||||||
|
end,
|
||||||
|
center,
|
||||||
|
normal,
|
||||||
|
0,
|
||||||
|
EMC_MOTION_TYPE_ARC,
|
||||||
|
1.0,
|
||||||
|
1.0,
|
||||||
|
10.0,
|
||||||
|
100.0,
|
||||||
|
status.enables_new,
|
||||||
|
0,
|
||||||
|
tag);
|
||||||
|
|
||||||
|
int cycle_rc = 0;
|
||||||
|
int cycles = 0;
|
||||||
|
for (; cycles < 10000 && !tpIsDone(&tp); ++cycles) {
|
||||||
|
cycle_rc = tpRunCycle(&tp, 1000000);
|
||||||
|
if (cycle_rc < 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
EmcPose final_pos;
|
||||||
|
memset(&final_pos, 0, sizeof(final_pos));
|
||||||
|
const int get_pos_rc = tpGetPos(&tp, &final_pos);
|
||||||
|
const int near_end = pose_near(&final_pos, &end);
|
||||||
|
|
||||||
|
char line[1024];
|
||||||
|
snprintf(line, sizeof(line),
|
||||||
|
"tp_arc_create=%d\n"
|
||||||
|
"tp_arc_set_cycle_time=%d\n"
|
||||||
|
"tp_arc_set_pos=%d\n"
|
||||||
|
"tp_arc_set_vmax=%d\n"
|
||||||
|
"tp_arc_set_vlimit=%d\n"
|
||||||
|
"tp_arc_set_amax=%d\n"
|
||||||
|
"tp_arc_set_term_cond=%d\n"
|
||||||
|
"tp_add_circle=%d\n"
|
||||||
|
"tp_arc_cycle_rc=%d\n"
|
||||||
|
"tp_arc_cycles=%d\n"
|
||||||
|
"tp_arc_get_pos=%d\n"
|
||||||
|
"tp_done_after_arc=%d\n"
|
||||||
|
"tp_arc_queue_depth=%d\n"
|
||||||
|
"tp_arc_final_pos_near_end=%d\n"
|
||||||
|
"tp_arc_final_pos=%.12g,%.12g,%.12g\n",
|
||||||
|
create_rc,
|
||||||
|
set_cycle_rc,
|
||||||
|
set_pos_rc,
|
||||||
|
set_vmax_rc,
|
||||||
|
set_vlimit_rc,
|
||||||
|
set_amax_rc,
|
||||||
|
set_term_rc,
|
||||||
|
add_circle_rc,
|
||||||
|
cycle_rc,
|
||||||
|
cycles,
|
||||||
|
get_pos_rc,
|
||||||
|
tpIsDone(&tp),
|
||||||
|
tpQueueDepth(&tp),
|
||||||
|
near_end,
|
||||||
|
final_pos.tran.x,
|
||||||
|
final_pos.tran.y,
|
||||||
|
final_pos.tran.z);
|
||||||
|
append(out, size, offset, line);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void append_queued_lines_probe(char *out, size_t size, size_t *offset)
|
||||||
|
{
|
||||||
|
init_motion_state();
|
||||||
|
|
||||||
|
TP_STRUCT tp;
|
||||||
|
EmcPose start;
|
||||||
|
EmcPose end1;
|
||||||
|
EmcPose end2;
|
||||||
|
struct state_tag_t tag;
|
||||||
|
memset(&tp, 0, sizeof(tp));
|
||||||
|
memset(&start, 0, sizeof(start));
|
||||||
|
memset(&end1, 0, sizeof(end1));
|
||||||
|
memset(&end2, 0, sizeof(end2));
|
||||||
|
memset(&tag, 0, sizeof(tag));
|
||||||
|
|
||||||
|
end1.tran.x = 1.0;
|
||||||
|
end2.tran.x = 1.0;
|
||||||
|
end2.tran.y = 1.0;
|
||||||
|
|
||||||
|
const int create_rc = tpCreate(&tp, TP_DEFAULT_QUEUE_SIZE, 3);
|
||||||
|
const int set_cycle_rc = tpSetCycleTime(&tp, 0.001);
|
||||||
|
const int set_pos_rc = tpSetPos(&tp, &start);
|
||||||
|
const int set_vmax_rc = tpSetVmax(&tp, 1.0, 1.0);
|
||||||
|
const int set_vlimit_rc = tpSetVlimit(&tp, 1.0);
|
||||||
|
const int set_amax_rc = tpSetAmax(&tp, 10.0);
|
||||||
|
const int set_term_rc = tpSetTermCond(&tp, TC_TERM_COND_STOP, 0.0);
|
||||||
|
const int add_line1_rc = tpAddLine(
|
||||||
|
&tp,
|
||||||
|
end1,
|
||||||
|
EMC_MOTION_TYPE_FEED,
|
||||||
|
1.0,
|
||||||
|
1.0,
|
||||||
|
10.0,
|
||||||
|
100.0,
|
||||||
|
status.enables_new,
|
||||||
|
0,
|
||||||
|
-1,
|
||||||
|
tag);
|
||||||
|
const int depth_after_line1 = tpQueueDepth(&tp);
|
||||||
|
const int add_line2_rc = tpAddLine(
|
||||||
|
&tp,
|
||||||
|
end2,
|
||||||
|
EMC_MOTION_TYPE_FEED,
|
||||||
|
1.0,
|
||||||
|
1.0,
|
||||||
|
10.0,
|
||||||
|
100.0,
|
||||||
|
status.enables_new,
|
||||||
|
0,
|
||||||
|
-1,
|
||||||
|
tag);
|
||||||
|
const int depth_after_line2 = tpQueueDepth(&tp);
|
||||||
|
|
||||||
|
int cycle_rc = 0;
|
||||||
|
int cycles = 0;
|
||||||
|
for (; cycles < 20000 && !tpIsDone(&tp); ++cycles) {
|
||||||
|
cycle_rc = tpRunCycle(&tp, 1000000);
|
||||||
|
if (cycle_rc < 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
EmcPose final_pos;
|
||||||
|
memset(&final_pos, 0, sizeof(final_pos));
|
||||||
|
const int get_pos_rc = tpGetPos(&tp, &final_pos);
|
||||||
|
const int near_end = pose_near(&final_pos, &end2);
|
||||||
|
|
||||||
|
char line[1024];
|
||||||
|
snprintf(line, sizeof(line),
|
||||||
|
"tp_queue_create=%d\n"
|
||||||
|
"tp_queue_set_cycle_time=%d\n"
|
||||||
|
"tp_queue_set_pos=%d\n"
|
||||||
|
"tp_queue_set_vmax=%d\n"
|
||||||
|
"tp_queue_set_vlimit=%d\n"
|
||||||
|
"tp_queue_set_amax=%d\n"
|
||||||
|
"tp_queue_set_term_cond=%d\n"
|
||||||
|
"tp_queue_add_line1=%d\n"
|
||||||
|
"tp_queue_depth_after_line1=%d\n"
|
||||||
|
"tp_queue_add_line2=%d\n"
|
||||||
|
"tp_queue_depth_after_line2=%d\n"
|
||||||
|
"tp_queue_cycle_rc=%d\n"
|
||||||
|
"tp_queue_cycles=%d\n"
|
||||||
|
"tp_queue_get_pos=%d\n"
|
||||||
|
"tp_done_after_queued_lines=%d\n"
|
||||||
|
"tp_queue_final_depth=%d\n"
|
||||||
|
"tp_queue_final_pos_near_end=%d\n"
|
||||||
|
"tp_queue_final_pos=%.12g,%.12g,%.12g\n",
|
||||||
|
create_rc,
|
||||||
|
set_cycle_rc,
|
||||||
|
set_pos_rc,
|
||||||
|
set_vmax_rc,
|
||||||
|
set_vlimit_rc,
|
||||||
|
set_amax_rc,
|
||||||
|
set_term_rc,
|
||||||
|
add_line1_rc,
|
||||||
|
depth_after_line1,
|
||||||
|
add_line2_rc,
|
||||||
|
depth_after_line2,
|
||||||
|
cycle_rc,
|
||||||
|
cycles,
|
||||||
|
get_pos_rc,
|
||||||
|
tpIsDone(&tp),
|
||||||
|
tpQueueDepth(&tp),
|
||||||
|
near_end,
|
||||||
|
final_pos.tran.x,
|
||||||
|
final_pos.tran.y,
|
||||||
|
final_pos.tran.z);
|
||||||
|
append(out, size, offset, line);
|
||||||
|
}
|
||||||
|
|
||||||
|
EMSCRIPTEN_KEEPALIVE
|
||||||
|
char *lctp_run_probe(void)
|
||||||
|
{
|
||||||
|
char *out = (char *)malloc(8192);
|
||||||
|
if (!out) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
out[0] = '\0';
|
||||||
|
size_t offset = 0;
|
||||||
|
|
||||||
|
TP_STRUCT tp;
|
||||||
|
TC_STRUCT tc;
|
||||||
|
EmcPose pose;
|
||||||
|
memset(&tp, 0, sizeof(tp));
|
||||||
|
memset(&tc, 0, sizeof(tc));
|
||||||
|
memset(&pose, 0, sizeof(pose));
|
||||||
|
|
||||||
|
pose.tran.x = 1.0;
|
||||||
|
pose.tran.y = 2.0;
|
||||||
|
pose.tran.z = 3.0;
|
||||||
|
|
||||||
|
char line[512];
|
||||||
|
snprintf(line, sizeof(line),
|
||||||
|
"sizeof_TP_STRUCT=%zu\n"
|
||||||
|
"sizeof_TC_STRUCT=%zu\n"
|
||||||
|
"tp_default_queue_size=%d\n"
|
||||||
|
"tp_err_ok=%d\n"
|
||||||
|
"tc_linear=%d\n"
|
||||||
|
"tc_circular=%d\n"
|
||||||
|
"pose_xyz=%.12g,%.12g,%.12g\n",
|
||||||
|
sizeof(tp),
|
||||||
|
sizeof(tc),
|
||||||
|
TP_DEFAULT_QUEUE_SIZE,
|
||||||
|
TP_ERR_OK,
|
||||||
|
TC_LINEAR,
|
||||||
|
TC_CIRCULAR,
|
||||||
|
pose.tran.x,
|
||||||
|
pose.tran.y,
|
||||||
|
pose.tran.z);
|
||||||
|
append(out, 8192, &offset, line);
|
||||||
|
append_linear_probe(out, 8192, &offset);
|
||||||
|
append_arc_probe(out, 8192, &offset);
|
||||||
|
append_queued_lines_probe(out, 8192, &offset);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
EMSCRIPTEN_KEEPALIVE
|
||||||
|
void lctp_free_string(char *value)
|
||||||
|
{
|
||||||
|
free(value);
|
||||||
|
}
|
||||||
@@ -5,8 +5,10 @@ ROOT_DIR="$(cd "$(dirname "$0")/../.." && pwd)"
|
|||||||
|
|
||||||
"$ROOT_DIR/tools/build_ini_panel.sh"
|
"$ROOT_DIR/tools/build_ini_panel.sh"
|
||||||
"$ROOT_DIR/tools/build_wasm_core.sh"
|
"$ROOT_DIR/tools/build_wasm_core.sh"
|
||||||
|
"$ROOT_DIR/tools/build_tp_wasm.sh"
|
||||||
SKIP_INI_BUILD=1 "$ROOT_DIR/tests/wasm/node/verify_ini_wasm.sh"
|
SKIP_INI_BUILD=1 "$ROOT_DIR/tests/wasm/node/verify_ini_wasm.sh"
|
||||||
SKIP_INTERP_BUILD=1 "$ROOT_DIR/tests/wasm/node/verify_interp_wasm.sh"
|
SKIP_INTERP_BUILD=1 "$ROOT_DIR/tests/wasm/node/verify_interp_wasm.sh"
|
||||||
|
SKIP_TP_BUILD=1 "$ROOT_DIR/tests/wasm/node/verify_tp_wasm.sh"
|
||||||
"$ROOT_DIR/tests/opfs/node/verify_file_service.sh"
|
"$ROOT_DIR/tests/opfs/node/verify_file_service.sh"
|
||||||
SKIP_INI_BUILD=1 SKIP_INTERP_BUILD=1 "$ROOT_DIR/tests/browser/verify_ini_panel_browser.sh"
|
SKIP_INI_BUILD=1 SKIP_INTERP_BUILD=1 "$ROOT_DIR/tests/browser/verify_ini_panel_browser.sh"
|
||||||
SKIP_INI_BUILD=1 SKIP_INTERP_BUILD=1 "$ROOT_DIR/tests/browser/verify_interp_browser.sh"
|
SKIP_INI_BUILD=1 SKIP_INTERP_BUILD=1 "$ROOT_DIR/tests/browser/verify_interp_browser.sh"
|
||||||
|
|||||||
83
wasm-port/tests/wasm/node/verify_tp_wasm.mjs
Normal file
83
wasm-port/tests/wasm/node/verify_tp_wasm.mjs
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
import { readFileSync } from "node:fs";
|
||||||
|
import { fileURLToPath } from "node:url";
|
||||||
|
import { dirname, resolve } from "node:path";
|
||||||
|
import assert from "node:assert/strict";
|
||||||
|
|
||||||
|
import createLinuxCncTpModule from "../../../build/wasm/tp/linuxcnc_tp.js";
|
||||||
|
|
||||||
|
function verifyExpectedOutput(fixtureName, output, expectedText) {
|
||||||
|
const expectedLines = expectedText.split("\n").filter(Boolean);
|
||||||
|
|
||||||
|
for (const expectedLine of expectedLines) {
|
||||||
|
assert.equal(
|
||||||
|
output.includes(expectedLine),
|
||||||
|
true,
|
||||||
|
`${fixtureName}: ${expectedLine}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const __filename = fileURLToPath(import.meta.url);
|
||||||
|
const __dirname = dirname(__filename);
|
||||||
|
const rootDir = resolve(__dirname, "../../..");
|
||||||
|
const wasmPath = resolve(rootDir, "build/wasm/tp/linuxcnc_tp.wasm");
|
||||||
|
|
||||||
|
const tp = await createLinuxCncTpModule({
|
||||||
|
wasmBinary: readFileSync(wasmPath),
|
||||||
|
print() {},
|
||||||
|
printErr(message) {
|
||||||
|
console.error(message);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const resultPtr = tp._lctp_run_probe();
|
||||||
|
assert.notEqual(resultPtr, 0);
|
||||||
|
try {
|
||||||
|
const output = tp.UTF8ToString(resultPtr);
|
||||||
|
verifyExpectedOutput(
|
||||||
|
"tp_wasm_probe",
|
||||||
|
output,
|
||||||
|
[
|
||||||
|
"tp_default_queue_size=32",
|
||||||
|
"tp_err_ok=0",
|
||||||
|
"tc_linear=1",
|
||||||
|
"tc_circular=2",
|
||||||
|
"pose_xyz=1,2,3",
|
||||||
|
"tp_create=0",
|
||||||
|
"tp_set_cycle_time=0",
|
||||||
|
"tp_set_pos=0",
|
||||||
|
"tp_set_vmax=0",
|
||||||
|
"tp_set_vlimit=0",
|
||||||
|
"tp_set_amax=0",
|
||||||
|
"tp_set_term_cond=0",
|
||||||
|
"tp_add_line=0",
|
||||||
|
"tp_cycle_rc=4",
|
||||||
|
"tp_get_pos=0",
|
||||||
|
"tp_done_after_line=1",
|
||||||
|
"tp_queue_depth=0",
|
||||||
|
"tp_final_pos=1,0,0",
|
||||||
|
"tp_arc_create=0",
|
||||||
|
"tp_add_circle=0",
|
||||||
|
"tp_arc_cycle_rc=4",
|
||||||
|
"tp_arc_get_pos=0",
|
||||||
|
"tp_done_after_arc=1",
|
||||||
|
"tp_arc_queue_depth=0",
|
||||||
|
"tp_arc_final_pos_near_end=1",
|
||||||
|
"tp_queue_create=0",
|
||||||
|
"tp_queue_add_line1=0",
|
||||||
|
"tp_queue_depth_after_line1=1",
|
||||||
|
"tp_queue_add_line2=0",
|
||||||
|
"tp_queue_depth_after_line2=2",
|
||||||
|
"tp_queue_cycle_rc=4",
|
||||||
|
"tp_queue_get_pos=0",
|
||||||
|
"tp_done_after_queued_lines=1",
|
||||||
|
"tp_queue_final_depth=0",
|
||||||
|
"tp_queue_final_pos_near_end=1",
|
||||||
|
"tp_queue_final_pos=1,1,0",
|
||||||
|
].join("\n"),
|
||||||
|
);
|
||||||
|
} finally {
|
||||||
|
tp._lctp_free_string(resultPtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("tp_wasm_node_smoke=ok");
|
||||||
9
wasm-port/tests/wasm/node/verify_tp_wasm.sh
Executable file
9
wasm-port/tests/wasm/node/verify_tp_wasm.sh
Executable file
@@ -0,0 +1,9 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
ROOT_DIR="$(cd "$(dirname "$0")/../../.." && pwd)"
|
||||||
|
|
||||||
|
if [[ "${SKIP_TP_BUILD:-0}" != "1" ]]; then
|
||||||
|
"$ROOT_DIR/tools/build_tp_wasm.sh"
|
||||||
|
fi
|
||||||
|
node "$ROOT_DIR/tests/wasm/node/verify_tp_wasm.mjs"
|
||||||
108
wasm-port/tools/build_tp_wasm.sh
Executable file
108
wasm-port/tools/build_tp_wasm.sh
Executable file
@@ -0,0 +1,108 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
ROOT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
|
||||||
|
VENDOR_DIR="$ROOT_DIR/vendor/linuxcnc"
|
||||||
|
WRAP_DIR="$ROOT_DIR/runtime/core/linuxcnc_wrap"
|
||||||
|
SHIM_DIR="$ROOT_DIR/runtime/core/shims"
|
||||||
|
INCLUDE_DIR="$ROOT_DIR/runtime/core/include"
|
||||||
|
OUT_DIR="$ROOT_DIR/build/wasm/tp"
|
||||||
|
OBJ_DIR="$OUT_DIR/obj"
|
||||||
|
|
||||||
|
source "$ROOT_DIR/tools/wasm_incremental_build_lib.sh"
|
||||||
|
|
||||||
|
mkdir -p "$OUT_DIR" "$OBJ_DIR"
|
||||||
|
|
||||||
|
TARGET="linuxcnc_tp_wasm"
|
||||||
|
: > "$OUT_DIR/$TARGET.stdout.log"
|
||||||
|
: > "$OUT_DIR/$TARGET.stderr.log"
|
||||||
|
|
||||||
|
COMMON_FLAGS=(
|
||||||
|
-O2
|
||||||
|
-D_GNU_SOURCE
|
||||||
|
-DM_PI=3.14159265358979323846
|
||||||
|
-I"$WRAP_DIR"
|
||||||
|
-I"$SHIM_DIR"
|
||||||
|
-I"$INCLUDE_DIR"
|
||||||
|
-I"$VENDOR_DIR/src"
|
||||||
|
-I"$VENDOR_DIR/src/rtapi"
|
||||||
|
-I"$VENDOR_DIR/src/emc"
|
||||||
|
-I"$VENDOR_DIR/src/emc/nml_intf"
|
||||||
|
-I"$VENDOR_DIR/src/emc/motion"
|
||||||
|
-I"$VENDOR_DIR/src/emc/tp"
|
||||||
|
-I"$VENDOR_DIR/src/emc/kinematics"
|
||||||
|
-I"$VENDOR_DIR/src/libnml/posemath"
|
||||||
|
)
|
||||||
|
|
||||||
|
C_FLAGS=(
|
||||||
|
-std=gnu11
|
||||||
|
"${COMMON_FLAGS[@]}"
|
||||||
|
)
|
||||||
|
|
||||||
|
CXX_FLAGS=(
|
||||||
|
-std=c++20
|
||||||
|
-fpermissive
|
||||||
|
"${COMMON_FLAGS[@]}"
|
||||||
|
)
|
||||||
|
|
||||||
|
SOURCES=(
|
||||||
|
"$VENDOR_DIR/src/emc/tp/tp.c"
|
||||||
|
"$VENDOR_DIR/src/emc/tp/tc.c"
|
||||||
|
"$VENDOR_DIR/src/emc/tp/tcq.c"
|
||||||
|
"$VENDOR_DIR/src/emc/tp/spherical_arc.c"
|
||||||
|
"$VENDOR_DIR/src/emc/tp/blendmath.c"
|
||||||
|
"$VENDOR_DIR/src/emc/tp/sp_scurve.c"
|
||||||
|
"$VENDOR_DIR/src/emc/tp/ruckig_wrapper.c"
|
||||||
|
"$VENDOR_DIR/src/emc/tp/cruckig/block.c"
|
||||||
|
"$VENDOR_DIR/src/emc/tp/cruckig/brake.c"
|
||||||
|
"$VENDOR_DIR/src/emc/tp/cruckig/calculator.c"
|
||||||
|
"$VENDOR_DIR/src/emc/tp/cruckig/cruckig.c"
|
||||||
|
"$VENDOR_DIR/src/emc/tp/cruckig/input_parameter.c"
|
||||||
|
"$VENDOR_DIR/src/emc/tp/cruckig/output_parameter.c"
|
||||||
|
"$VENDOR_DIR/src/emc/tp/cruckig/profile.c"
|
||||||
|
"$VENDOR_DIR/src/emc/tp/cruckig/roots.c"
|
||||||
|
"$VENDOR_DIR/src/emc/tp/cruckig/trajectory.c"
|
||||||
|
"$VENDOR_DIR/src/emc/tp/cruckig/position_first_step1.c"
|
||||||
|
"$VENDOR_DIR/src/emc/tp/cruckig/position_first_step2.c"
|
||||||
|
"$VENDOR_DIR/src/emc/tp/cruckig/position_second_step1.c"
|
||||||
|
"$VENDOR_DIR/src/emc/tp/cruckig/position_second_step2.c"
|
||||||
|
"$VENDOR_DIR/src/emc/tp/cruckig/position_third_step1.c"
|
||||||
|
"$VENDOR_DIR/src/emc/tp/cruckig/position_third_step2.c"
|
||||||
|
"$VENDOR_DIR/src/emc/tp/cruckig/velocity_second_step1.c"
|
||||||
|
"$VENDOR_DIR/src/emc/tp/cruckig/velocity_second_step2.c"
|
||||||
|
"$VENDOR_DIR/src/emc/tp/cruckig/velocity_third_step1.c"
|
||||||
|
"$VENDOR_DIR/src/emc/tp/cruckig/velocity_third_step2.c"
|
||||||
|
"$VENDOR_DIR/src/emc/nml_intf/emcpose.c"
|
||||||
|
"$VENDOR_DIR/src/libnml/posemath/posemath.cc"
|
||||||
|
"$VENDOR_DIR/src/libnml/posemath/_posemath.c"
|
||||||
|
"$VENDOR_DIR/src/libnml/posemath/sincos.c"
|
||||||
|
"$WRAP_DIR/linuxcnc_tp_wasm.c"
|
||||||
|
)
|
||||||
|
|
||||||
|
OBJECTS=()
|
||||||
|
for source in "${SOURCES[@]}"; do
|
||||||
|
obj="$(source_object_path "$source" "$ROOT_DIR" "$OBJ_DIR")"
|
||||||
|
OBJECTS+=("$obj")
|
||||||
|
case "$source" in
|
||||||
|
*.cc|*.cpp|*.cxx)
|
||||||
|
compile_wasm_object "$TARGET" "$source" "$obj" "$OUT_DIR" "${CXX_FLAGS[@]}"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
compile_wasm_object "$TARGET" "$source" "$obj" "$OUT_DIR" "${C_FLAGS[@]}"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
link_wasm_module \
|
||||||
|
"$TARGET" \
|
||||||
|
"$OUT_DIR/linuxcnc_tp.js" \
|
||||||
|
"$OUT_DIR" \
|
||||||
|
-O2 \
|
||||||
|
"${OBJECTS[@]}" \
|
||||||
|
-s MODULARIZE=1 \
|
||||||
|
-s EXPORT_ES6=1 \
|
||||||
|
-s ENVIRONMENT=web,node \
|
||||||
|
-s ALLOW_MEMORY_GROWTH=1 \
|
||||||
|
-s NO_EXIT_RUNTIME=1 \
|
||||||
|
-s EXPORTED_FUNCTIONS='["_malloc","_free","_lctp_run_probe","_lctp_free_string"]' \
|
||||||
|
-s EXPORTED_RUNTIME_METHODS='["UTF8ToString"]'
|
||||||
Reference in New Issue
Block a user