按规划继续工作
结论:新增解释器初始化和同步的 WASM/浏览器验证,继续保持核心行为来自 vendored LinuxCNC。
This commit is contained in:
@@ -87,7 +87,11 @@ interpreter harness. It loads the module in Node through
|
||||
`runtime/sdk/src/index.js`, runs the first WASM interpreter fixture
|
||||
group through `Interp::execute()`, and compares emitted canonical events plus
|
||||
required LinuxCNC `_setup` state readback with the matching files in
|
||||
`tests/fixtures/canon/`. It also writes selected G-code fixtures into the
|
||||
`tests/fixtures/canon/`. It also calls vendored `Interp::init()` and
|
||||
`Interp::synch()` through the WASM C ABI to validate the initialization
|
||||
canonical boundary, metric/inch machine-unit status edge, and current/selected
|
||||
tool slot status synchronization already covered by the native init harness.
|
||||
It also writes selected G-code fixtures into the
|
||||
Emscripten filesystem through the SDK and runs them through LinuxCNC
|
||||
`Interp::open()`, `Interp::read()`, and `Interp::execute()` to validate the
|
||||
file execution path. The same Node smoke writes LinuxCNC-format parameter
|
||||
@@ -135,7 +139,10 @@ behavior in JavaScript, and verifies existing canonical fixtures through the
|
||||
exported C ABI backed by vendored LinuxCNC `Interp::execute()` and
|
||||
`Interp::open()`/`read()`/`execute()` paths, including the INI-aware
|
||||
named-parameter file path and negative interpreter fixtures with expected
|
||||
error text plus absent canonical motion output. It also uses real browser OPFS
|
||||
error text plus absent canonical motion output. It also validates vendored
|
||||
`Interp::init()` and `Interp::synch()` through the same SDK/C ABI path,
|
||||
including initialization canonical events, metric/inch machine units, and tool
|
||||
slot readback. It also uses real browser OPFS
|
||||
storage plus the interpreter SDK to restore and save a LinuxCNC parameter file
|
||||
through vendored `Interp::restore_parameters()` and `Interp::save_parameters()`,
|
||||
and directly checks missing-file success plus out-of-order parameter-file
|
||||
@@ -280,7 +287,11 @@ load/save behavior through vendored `tooldata_common.cc`, including the
|
||||
non-random and random-toolchanger `tooldata_init()` branches, with the SDK
|
||||
only copying text into the Emscripten filesystem and calling the exported C
|
||||
ABI; the browser smoke checks the random-toolchanger `tooldata_save()` C ABI
|
||||
result before OPFS persistence writes the saved table text back.
|
||||
result before OPFS persistence writes the saved table text back. The same
|
||||
Node WASM and browser interpreter smokes now validate the exported
|
||||
`Interp::init()`/`Interp::synch()` probe for initialization canonical events,
|
||||
metric/inch `emcStatus` machine-unit conversion, and current/selected tool
|
||||
slot synchronization.
|
||||
OPFS validation covers the JavaScript host-boundary adapter, the INI browser
|
||||
smoke harness, the INI panel UI's machine-session load and G-code run buttons,
|
||||
the raw canonical-event display fed directly by LinuxCNC interpreter WASM
|
||||
|
||||
@@ -29,15 +29,15 @@ semantic rewrites:
|
||||
| Feed-rate state | `SET_FEED_RATE` updates standalone canonical runtime state so vendored `convert_length_units()` can read it back through `GET_EXTERNAL_FEED_RATE()` during G20/G21 changes. |
|
||||
| Tool-data reload | LinuxCNC `RELOAD_TOOLDATA` is captured as a canonical test event; browser/native tool-table reload plumbing remains a future host/runtime adapter. |
|
||||
| Tool table storage | Vendored LinuxCNC `tooldata_common.cc` owns tool-table parsing and formatting; the standalone boundary only supplies the in-memory `tooldata_get()`/`tooldata_put()` callbacks, exposes load/save through the WASM C ABI, and forwards the host random-toolchanger flag to LinuxCNC `tooldata_init()`. |
|
||||
| Tool slot status | Standalone tool adapter state supplies `GET_EXTERNAL_TOOL_SLOT()` and `GET_EXTERNAL_SELECTED_TOOL_SLOT()` for vendored `Interp::synch()`; `linuxcnc_interp_init_harness` guards current/selected slot synchronization. |
|
||||
| Tool slot status | Standalone tool adapter state supplies `GET_EXTERNAL_TOOL_SLOT()` and `GET_EXTERNAL_SELECTED_TOOL_SLOT()` for vendored `Interp::synch()`; `linuxcnc_interp_init_harness` plus Node WASM and browser interpreter smokes guard current/selected slot synchronization. |
|
||||
| Interpreter state tags | LinuxCNC `UPDATE_TAG` callbacks are captured from the state tags packed by vendored interpreter code; standalone code does not derive modal state. |
|
||||
| Rotary indexer lock state | LinuxCNC `UNLOCK_ROTARY` and `LOCK_ROTARY` callbacks are captured from the vendored single-axis indexer path; standalone code does not implement rotary-indexing semantics. |
|
||||
| File flush | LinuxCNC `FINISH` is captured as a canonical test event on the vendored `%`-delimited file-reading path. |
|
||||
| WASM parameter-file backup | LinuxCNC `save_parameters()` calls `link()` to create the `.bak` parameter-file backup; `runtime/core/linuxcnc_wrap/linuxcnc_wasm_posix_stubs.cpp` maps that WASM/MEMFS edge to a file copy so the vendored save path can run unchanged. |
|
||||
| Interpreter reset | LinuxCNC `ON_RESET` is captured as a canonical test event on the vendored interpreter reset/file-open path. |
|
||||
| Interpreter init | LinuxCNC `INIT_CANON` and the canonical initialization sequence from vendored `Interp::init()` are captured as test events. |
|
||||
| Interpreter init | LinuxCNC `INIT_CANON` and the canonical initialization sequence from vendored `Interp::init()` are captured as test events in native, Node WASM, and browser interpreter validation. |
|
||||
| Comment logging | LinuxCNC `LOGOPEN`, `LOG`, `LOGAPPEND`, and `LOGCLOSE` callbacks are captured as canonical test events instead of writing host log files. |
|
||||
| EMC status machine units | A narrow standalone `emcStatus` shim exposes the machine-units field used by vendored interpreter conversion and initialization code; `linuxcnc_emc_status_probe` and `linuxcnc_interp_init_harness` guard the inch/mm boundary. |
|
||||
| EMC status machine units | A narrow standalone `emcStatus` shim exposes the machine-units field used by vendored interpreter conversion and initialization code; `linuxcnc_emc_status_probe`, `linuxcnc_interp_init_harness`, and the interpreter WASM/browser init probe guard the inch/mm boundary. |
|
||||
| Python/remap | Python/remap hooks are stubbed at the runtime edge. |
|
||||
| Dynamic interpreter path | `interp_base.cc` probe uses standalone `EMC2_HOME` compile-time path boundary. |
|
||||
| Realtime scheduler | TP probes seed deterministic status/config data instead of running LinuxCNC realtime process topology. |
|
||||
|
||||
@@ -35,7 +35,7 @@ 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` |
|
||||
| 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 |
|
||||
| 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` |
|
||||
| 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` |
|
||||
@@ -46,7 +46,7 @@ Current validation is intentionally mechanical:
|
||||
| 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 |
|
||||
| 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 | Vendor byte sync, per-file source probes, canonical fixture suite, no standalone `Interp::convert_g()` guard |
|
||||
| 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` |
|
||||
| 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 |
|
||||
| Tool table parsing and formatting | `src/emc/tooldata/tooldata_common.cc` | Copy unchanged plus standalone storage callbacks | Native file parsing/formatting stays in vendored LinuxCNC source; the standalone tool adapter supplies `tooldata_get()`/`tooldata_put()` storage and index lookup, the WASM boundary only selects the LinuxCNC non-random or random-toolchanger branch via `tooldata_init()`, and OPFS remains a host-side persistence boundary | Vendor byte sync, `linuxcnc_tooldata_common_source_probe`, `tests/wasm/node/verify_interp_wasm.sh` non-random/random load/save tool-table assertions |
|
||||
| Dynamic interpreter base | `src/emc/rs274ngc/interp_base.*` | Copy unchanged | `interp_base.cc` source probe uses standalone `EMC2_HOME` compile-time path boundary for LinuxCNC dynamic interpreter lookup | Vendor byte sync, `linuxcnc_interp_base_source_probe` |
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "canon_event_sink.hh"
|
||||
#include "linuxcnc_hal_adapter.hh"
|
||||
#include "linuxcnc_tool_adapter.hh"
|
||||
#include "nml_intf/emc.hh"
|
||||
#include "tooldata.hh"
|
||||
|
||||
namespace {
|
||||
@@ -390,6 +391,62 @@ char *lcinterp_save_tool_table(const char *path)
|
||||
return copy_result(output.str());
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE
|
||||
char *lcinterp_probe_init_and_synch()
|
||||
{
|
||||
std::ostringstream output;
|
||||
|
||||
emcStatus->motion.traj.linearUnits = 1.0;
|
||||
standalone::reset_tool_adapter();
|
||||
Interp interp;
|
||||
standalone::reset_canon_events();
|
||||
const int rc = interp.init();
|
||||
output << "init=" << rc << "\n";
|
||||
output << "setup.length_units=" << static_cast<int>(interp._setup.length_units) << "\n";
|
||||
output << "setup.origin_index=" << interp._setup.origin_index << "\n";
|
||||
output << "setup.distance_mode=" << static_cast<int>(interp._setup.distance_mode) << "\n";
|
||||
output << "setup.feed_mode=" << static_cast<int>(interp._setup.feed_mode) << "\n";
|
||||
output << "setup.motion_mode=" << interp._setup.motion_mode << "\n";
|
||||
output << "canon_event_count=" << standalone::canon_events().size() << "\n";
|
||||
for (const auto &event : standalone::canon_events()) {
|
||||
output << "canon_event=" << event << "\n";
|
||||
}
|
||||
|
||||
emcStatus->motion.traj.linearUnits = 1.0 / 25.4;
|
||||
standalone::reset_tool_adapter();
|
||||
Interp inch_interp;
|
||||
standalone::reset_canon_events();
|
||||
const int inch_rc = inch_interp.init();
|
||||
output << "inch_init=" << inch_rc << "\n";
|
||||
output << "inch_setup.length_units="
|
||||
<< static_cast<int>(inch_interp._setup.length_units) << "\n";
|
||||
output << "inch_external_length_units=" << GET_EXTERNAL_LENGTH_UNITS() << "\n";
|
||||
output << "inch_canon_event_count=" << standalone::canon_events().size() << "\n";
|
||||
for (const auto &event : standalone::canon_events()) {
|
||||
output << "inch_canon_event=" << event << "\n";
|
||||
}
|
||||
|
||||
standalone::reset_tool_adapter();
|
||||
CANON_TOOL_TABLE tool = standalone::tool_entry_init();
|
||||
tool.toolno = 2;
|
||||
tool.pocketno = 2;
|
||||
standalone::set_tool_entry(2, tool);
|
||||
standalone::select_tool(2);
|
||||
standalone::change_selected_tool();
|
||||
|
||||
Interp synch_interp;
|
||||
const int synch_rc = synch_interp.synch();
|
||||
output << "synch=" << synch_rc << "\n";
|
||||
output << "synch.current_pocket=" << synch_interp._setup.current_pocket << "\n";
|
||||
output << "synch.selected_pocket=" << synch_interp._setup.selected_pocket << "\n";
|
||||
output << "synch.tool_0=" << synch_interp._setup.tool_table[0].toolno << "\n";
|
||||
output << "synch.tool_2=" << synch_interp._setup.tool_table[2].toolno << "\n";
|
||||
|
||||
emcStatus->motion.traj.linearUnits = 1.0;
|
||||
standalone::reset_tool_adapter();
|
||||
return copy_result(output.str());
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE
|
||||
void lcinterp_free_string(char *value)
|
||||
{
|
||||
|
||||
@@ -95,5 +95,9 @@ export async function createLinuxCncInterpSdk(moduleOptions = {}) {
|
||||
saveToolTable(path) {
|
||||
return callStringResult(mod, "lcinterp_save_tool_table", path);
|
||||
},
|
||||
|
||||
probeInitAndSynch() {
|
||||
return callStringResult(mod, "lcinterp_probe_init_and_synch");
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -128,6 +128,34 @@
|
||||
},
|
||||
});
|
||||
|
||||
verifyExpectedOutput(
|
||||
"probe_init_and_synch",
|
||||
interp.probeInitAndSynch(),
|
||||
[
|
||||
"init=0",
|
||||
"setup.length_units=2",
|
||||
"setup.origin_index=1",
|
||||
"setup.distance_mode=0",
|
||||
"setup.feed_mode=0",
|
||||
"setup.motion_mode=800",
|
||||
"canon_event=INIT_CANON",
|
||||
"canon_event=USE_LENGTH_UNITS units=2",
|
||||
"canon_event=SET_G5X_OFFSET index=1",
|
||||
"canon_event=SET_G92_OFFSET x=0 y=0 z=0",
|
||||
"canon_event=SET_XY_ROTATION rotation=0",
|
||||
"canon_event=SET_FEED_REFERENCE reference=2",
|
||||
"inch_init=0",
|
||||
"inch_setup.length_units=1",
|
||||
"inch_external_length_units=0.0393701",
|
||||
"inch_canon_event=USE_LENGTH_UNITS units=1",
|
||||
"synch=0",
|
||||
"synch.current_pocket=2",
|
||||
"synch.selected_pocket=2",
|
||||
"synch.tool_0=2",
|
||||
"synch.tool_2=2",
|
||||
].join("\n"),
|
||||
);
|
||||
|
||||
for (const fixtureName of INTERP_BROWSER_MDI_FIXTURES) {
|
||||
const programText = await fetchText(`../fixtures/gcode/${fixtureName}.ngc`);
|
||||
const expectedText = await fetchText(`../fixtures/canon/${fixtureName}.events`);
|
||||
|
||||
@@ -86,6 +86,34 @@ const interp = await createLinuxCncInterpSdk({
|
||||
},
|
||||
});
|
||||
|
||||
verifyExpectedOutput(
|
||||
"probe_init_and_synch",
|
||||
interp.probeInitAndSynch(),
|
||||
[
|
||||
"init=0",
|
||||
"setup.length_units=2",
|
||||
"setup.origin_index=1",
|
||||
"setup.distance_mode=0",
|
||||
"setup.feed_mode=0",
|
||||
"setup.motion_mode=800",
|
||||
"canon_event=INIT_CANON",
|
||||
"canon_event=USE_LENGTH_UNITS units=2",
|
||||
"canon_event=SET_G5X_OFFSET index=1",
|
||||
"canon_event=SET_G92_OFFSET x=0 y=0 z=0",
|
||||
"canon_event=SET_XY_ROTATION rotation=0",
|
||||
"canon_event=SET_FEED_REFERENCE reference=2",
|
||||
"inch_init=0",
|
||||
"inch_setup.length_units=1",
|
||||
"inch_external_length_units=0.0393701",
|
||||
"inch_canon_event=USE_LENGTH_UNITS units=1",
|
||||
"synch=0",
|
||||
"synch.current_pocket=2",
|
||||
"synch.selected_pocket=2",
|
||||
"synch.tool_0=2",
|
||||
"synch.tool_2=2",
|
||||
].join("\n"),
|
||||
);
|
||||
|
||||
for (const fixtureName of INTERP_MDI_FIXTURES) {
|
||||
const programText = readFileSync(
|
||||
resolve(rootDir, `tests/fixtures/gcode/${fixtureName}.ngc`),
|
||||
|
||||
@@ -96,5 +96,5 @@ link_wasm_module \
|
||||
-s STACK_SIZE=2MB \
|
||||
-s NO_EXIT_RUNTIME=1 \
|
||||
-s FORCE_FILESYSTEM=1 \
|
||||
-s EXPORTED_FUNCTIONS='["_malloc","_free","_lcinterp_run_program","_lcinterp_run_program_with_ini","_lcinterp_run_file","_lcinterp_run_file_with_ini","_lcinterp_restore_parameters","_lcinterp_save_parameters","_lcinterp_load_tool_table","_lcinterp_load_tool_table_random","_lcinterp_save_tool_table","_lcinterp_free_string"]' \
|
||||
-s EXPORTED_FUNCTIONS='["_malloc","_free","_lcinterp_run_program","_lcinterp_run_program_with_ini","_lcinterp_run_file","_lcinterp_run_file_with_ini","_lcinterp_restore_parameters","_lcinterp_save_parameters","_lcinterp_load_tool_table","_lcinterp_load_tool_table_random","_lcinterp_save_tool_table","_lcinterp_probe_init_and_synch","_lcinterp_free_string"]' \
|
||||
-s EXPORTED_RUNTIME_METHODS='["FS","UTF8ToString","stringToUTF8","lengthBytesUTF8"]'
|
||||
|
||||
Reference in New Issue
Block a user