按建议继续完成后续工作
结论:native 兼容性验证已接入 interpreter init、rotary indexer、canonical 边界 fixture,并新增 upstream rs274 side-by-side 基线;完整 verify_native_probes.sh 已通过。
This commit is contained in:
@@ -24,10 +24,14 @@ The native validation script runs these checks in order:
|
||||
vendored file exists, and every vendored file is byte-identical to upstream.
|
||||
3. `tools/verify_no_standalone_cnc_semantics.sh`
|
||||
Confirms standalone code has not reintroduced `Interp::convert_g()`.
|
||||
4. `tools/build_native_probes.sh`
|
||||
4. `tools/verify_native_linuxcnc_fixture_baseline.sh`
|
||||
Runs a narrow side-by-side fixture baseline through upstream
|
||||
`../linuxcnc/bin/rs274` and compares normalized canonical events for
|
||||
fixtures that do not require standalone-only runtime adapters.
|
||||
5. `tools/build_native_probes.sh`
|
||||
Builds native source probes and standalone harnesses from vendored
|
||||
LinuxCNC source plus narrow runtime wrappers.
|
||||
5. `tests/native/verify_native_probes.sh`
|
||||
6. `tests/native/verify_native_probes.sh`
|
||||
Checks probe exit codes, source-probe coverage, harness stdout, canonical
|
||||
fixture events, and expected error behavior.
|
||||
|
||||
@@ -51,6 +55,8 @@ The validation fails if:
|
||||
| `linuxcnc_namedparam_harness` | Validates LinuxCNC named parameter behavior, `_ini[...]`, and `_hal[...]` adapter resolution. |
|
||||
| `linuxcnc_interp_minimal_harness` | Runs G-code fixtures through vendored LinuxCNC parser/execution/conversion code and captures canonical events. |
|
||||
| `linuxcnc_parameter_file_harness` | Validates LinuxCNC parameter file restore/save behavior and required/read-only parameter handling. |
|
||||
| `linuxcnc_interp_init_harness` | Validates vendored LinuxCNC `Interp::init()` emits canonical initialization boundaries through the standalone event sink. |
|
||||
| `linuxcnc_indexer_harness` | Validates vendored LinuxCNC single-axis rotary indexer dispatch emits lock/unlock and motion boundaries through the standalone event sink. |
|
||||
| `linuxcnc_tp_api_probe` | Validates vendored LinuxCNC trajectory planner calls for linear, arc, and queued motion paths. |
|
||||
| `linuxcnc_kinematics_probe` | Validates vendored LinuxCNC `trivkins.c` plus `kins_util.c` initialize and perform identity forward/inverse mapping through the standalone HAL/RTAPI boundary. |
|
||||
| `linuxcnc_5axis_kinematics_probe` | Validates vendored LinuxCNC `5axiskins.c` through `switchkins.c`, including 5-axis forward/inverse round-trip behavior and switching to identity kinematics. |
|
||||
@@ -75,6 +81,11 @@ Positive G-code fixtures currently cover:
|
||||
- spindle orient
|
||||
- tool semantics
|
||||
- tool table setup
|
||||
- tool-data reload boundary
|
||||
- interpreter state-tag boundary
|
||||
- percent-delimited file `FINISH` boundary
|
||||
- file-open `ON_RESET` boundary
|
||||
- comment logging canonical calls
|
||||
- named and numbered parameters
|
||||
- O-word subroutines
|
||||
- program-end modal reset
|
||||
@@ -96,9 +107,11 @@ Negative fixtures currently cover:
|
||||
Current validation is native-only. WASM, browser, SDK, OPFS, and full
|
||||
machine-session validation remain future work.
|
||||
|
||||
The current fixture expectations validate standalone behavior against the
|
||||
vendored LinuxCNC source path. They do not yet run a side-by-side native
|
||||
LinuxCNC executable comparison for each fixture.
|
||||
The current fixture expectations validate standalone behavior against both the
|
||||
vendored LinuxCNC source path and a first upstream `rs274` side-by-side
|
||||
baseline for simple parser/conversion fixtures. Fixtures that depend on
|
||||
standalone-only runtime adapters, HAL/INI/tool table setup, or richer machine
|
||||
session state still need dedicated native LinuxCNC baselines.
|
||||
|
||||
The kinematics probes currently cover LinuxCNC identity/trivial kinematics,
|
||||
the switchable `5axiskins` XYZBCW bridge-mill model, and the TRT `xyzac`/`xyzbc`
|
||||
|
||||
@@ -26,6 +26,13 @@ semantic rewrites:
|
||||
| HAL lookup | Standalone HAL adapter for `_hal[...]` named parameter reads. |
|
||||
| INI lookup | Standalone INI adapter around vendored LinuxCNC INI parser behavior. |
|
||||
| Canonical output | Canonical calls are captured as test events instead of driving hardware. |
|
||||
| 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. |
|
||||
| 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. |
|
||||
| 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. |
|
||||
| Comment logging | LinuxCNC `LOGOPEN`, `LOG`, `LOGAPPEND`, and `LOGCLOSE` callbacks are captured as canonical test events instead of writing host log files. |
|
||||
| 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. |
|
||||
@@ -58,8 +65,10 @@ semantic rewrites:
|
||||
- Positive cutter-compensated motion and cutter compensation rejection paths
|
||||
now have standalone interpreter fixture coverage through vendored LinuxCNC
|
||||
source.
|
||||
- Fixture expectations are currently checked against the standalone vendored
|
||||
source path, not by running a native LinuxCNC binary for every fixture.
|
||||
- Fixture expectations are checked against the standalone vendored source
|
||||
path. A first upstream `rs274` side-by-side baseline now covers simple
|
||||
parser/conversion fixtures; adapter-heavy fixtures still need dedicated
|
||||
native LinuxCNC baselines.
|
||||
|
||||
## Current Drift Conclusion
|
||||
|
||||
|
||||
@@ -456,6 +456,58 @@ Current verified progress:
|
||||
`tests/fixtures/gcode/tool_table_setup.ngc` and
|
||||
`tests/fixtures/canon/tool_table_setup.events` pin `G10 L1` tool offset,
|
||||
diameter, front/back angle, and orientation behavior.
|
||||
- `runtime/core/linuxcnc_wrap/linuxcnc_interp_minimal_runtime.cpp` now records
|
||||
the tool-data reload boundary call emitted by vendored
|
||||
`interp_convert.cc::convert_modal_0()`: `RELOAD_TOOLDATA`.
|
||||
`tests/fixtures/gcode/tool_reload.ngc` and
|
||||
`tests/fixtures/canon/tool_reload.events` pin `G10 L0` dispatch without
|
||||
adding standalone tool-table reload semantics.
|
||||
- `runtime/core/linuxcnc_wrap/linuxcnc_interp_minimal_runtime.cpp` now records
|
||||
interpreter state-tag boundary calls emitted by vendored LinuxCNC
|
||||
`interp_write.cc::write_state_tag()` and
|
||||
`interp_convert.cc::update_tag()`: `UPDATE_TAG`.
|
||||
`tests/fixtures/gcode/state_tag_motion.ngc` and
|
||||
`tests/fixtures/canon/state_tag_motion.events` pin straight-motion state tag
|
||||
emission without deriving modal state in standalone code.
|
||||
- `runtime/core/linuxcnc_wrap/linuxcnc_interp_minimal_runtime.cpp` now records
|
||||
rotary indexer lock/unlock boundary calls emitted by vendored
|
||||
`interp_convert.cc::issue_straight_index()`: `UNLOCK_ROTARY` and
|
||||
`LOCK_ROTARY`. A dedicated `linuxcnc_indexer_harness` pins the LinuxCNC
|
||||
single-axis `G0 A...` indexer path, including the surrounding motion-control
|
||||
boundary calls, without adding standalone rotary-indexing semantics.
|
||||
- `runtime/core/linuxcnc_wrap/linuxcnc_interp_minimal_runtime.cpp` now records
|
||||
the canonical flush boundary emitted by vendored LinuxCNC file-reading
|
||||
code: `FINISH`. `tests/fixtures/gcode/percent_file_finish.ngc` and
|
||||
`tests/fixtures/canon/percent_file_finish.events` pin `%`-delimited file
|
||||
handling from `rs274ngc_pre.cc::open()` and `interp_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.cpp` now records
|
||||
the reset/queue-drop boundary emitted by vendored
|
||||
`rs274ngc_pre.cc::reset()`: `ON_RESET`.
|
||||
`tests/fixtures/gcode/file_open_reset.ngc` and
|
||||
`tests/fixtures/canon/file_open_reset.events` pin the LinuxCNC file-open
|
||||
reset path without adding standalone queue-management semantics.
|
||||
- `runtime/core/linuxcnc_wrap/linuxcnc_interp_minimal_runtime.cpp` now records
|
||||
the interpreter initialization boundary emitted by vendored
|
||||
`rs274ngc_pre.cc::init()`: `INIT_CANON`. A dedicated
|
||||
`linuxcnc_interp_init_harness` calls vendored `Interp::init()` and pins the
|
||||
LinuxCNC initialization sequence: `INIT_CANON`, `USE_LENGTH_UNITS`,
|
||||
`SET_G5X_OFFSET`, `SET_G92_OFFSET`, `SET_XY_ROTATION`, and
|
||||
`SET_FEED_REFERENCE`, without changing the minimal G-code fixture harness
|
||||
startup path.
|
||||
- `runtime/core/linuxcnc_wrap/linuxcnc_interp_minimal_runtime.cpp` now records
|
||||
comment logging canonical boundary calls emitted by vendored
|
||||
`interp_convert.cc::convert_comment()`: `LOGOPEN`, `LOG`, `LOGAPPEND`,
|
||||
and `LOGCLOSE`. `tests/fixtures/gcode/comment_logging.ngc` and
|
||||
`tests/fixtures/canon/comment_logging.events` pin LinuxCNC comment logging
|
||||
dispatch without adding standalone comment semantics.
|
||||
- `tools/verify_native_linuxcnc_fixture_baseline.sh` now runs a first
|
||||
side-by-side baseline against upstream `../linuxcnc/bin/rs274`. It normalizes
|
||||
native LinuxCNC canonical output for simple parser/conversion fixtures
|
||||
(`minimal_linear`, `length_units`, `plane_selection`, and
|
||||
`modal_incremental`) and compares it with the standalone fixture events,
|
||||
without introducing a project-authored CNC semantics oracle.
|
||||
- `tests/fixtures/gcode_errors/g1_zero_feed.ngc` and
|
||||
`tests/fixtures/canon_errors/g1_zero_feed.expected` pin the negative
|
||||
`G1` zero-feed case. The source basis is LinuxCNC
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
#define private public
|
||||
#include "emc/rs274ngc/rs274ngc_interp.hh"
|
||||
#undef private
|
||||
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
|
||||
#include "canon_event_sink.hh"
|
||||
#include "linuxcnc_hal_adapter.hh"
|
||||
#include "linuxcnc_tool_adapter.hh"
|
||||
|
||||
namespace {
|
||||
|
||||
void initialize_indexer_interp(Interp &interp)
|
||||
{
|
||||
standalone::reset_hal_adapter();
|
||||
standalone::reset_tool_adapter();
|
||||
|
||||
interp._setup.length_units = CANON_UNITS_MM;
|
||||
interp._setup.distance_mode = DISTANCE_MODE::ABSOLUTE;
|
||||
interp._setup.ijk_distance_mode = DISTANCE_MODE::ABSOLUTE;
|
||||
interp._setup.feed_mode = FEED_MODE::UNITS_PER_MINUTE;
|
||||
interp._setup.plane = CANON_PLANE::XY;
|
||||
interp._setup.motion_mode = G_0;
|
||||
interp._setup.percent_flag = false;
|
||||
interp._setup.sequence_number = 1;
|
||||
interp._setup.parameter_occurrence = 0;
|
||||
interp._setup.num_spindles = 1;
|
||||
interp._setup.a_indexer_jnum = 0;
|
||||
interp._setup.parameters[5599] = 1.0;
|
||||
std::memcpy(interp._readers, Interp::default_readers, sizeof(Interp::default_readers));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int main()
|
||||
{
|
||||
Interp interp;
|
||||
standalone::reset_canon_events();
|
||||
initialize_indexer_interp(interp);
|
||||
|
||||
const int rc = interp.execute("G0 A90\n");
|
||||
std::cout << "execute=" << rc << "\n";
|
||||
std::cout << "post_a=" << interp._setup.AA_current << "\n";
|
||||
std::cout << "canon_event_count=" << standalone::canon_events().size() << "\n";
|
||||
for (const auto &event : standalone::canon_events()) {
|
||||
std::cout << "canon_event=" << event << "\n";
|
||||
}
|
||||
|
||||
return rc == INTERP_OK ? 0 : 1;
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
#define private public
|
||||
#include "emc/rs274ngc/rs274ngc_interp.hh"
|
||||
#undef private
|
||||
|
||||
#include <cstdlib>
|
||||
#include <filesystem>
|
||||
#include <iostream>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "canon_event_sink.hh"
|
||||
|
||||
namespace {
|
||||
|
||||
std::filesystem::path make_temp_dir()
|
||||
{
|
||||
std::string pattern = "/tmp/linuxcnc-init-XXXXXX";
|
||||
char *path = mkdtemp(pattern.data());
|
||||
if (path == nullptr) {
|
||||
std::perror("mkdtemp");
|
||||
std::exit(2);
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int main()
|
||||
{
|
||||
const auto temp_dir = make_temp_dir();
|
||||
std::filesystem::current_path(temp_dir);
|
||||
|
||||
Interp interp;
|
||||
standalone::reset_canon_events();
|
||||
|
||||
const int rc = interp.init();
|
||||
std::cout << "init=" << rc << "\n";
|
||||
std::cout << "setup.length_units=" << static_cast<int>(interp._setup.length_units) << "\n";
|
||||
std::cout << "setup.origin_index=" << interp._setup.origin_index << "\n";
|
||||
std::cout << "setup.distance_mode=" << static_cast<int>(interp._setup.distance_mode) << "\n";
|
||||
std::cout << "setup.feed_mode=" << static_cast<int>(interp._setup.feed_mode) << "\n";
|
||||
std::cout << "setup.motion_mode=" << interp._setup.motion_mode << "\n";
|
||||
std::cout << "canon_event_count=" << standalone::canon_events().size() << "\n";
|
||||
for (const auto &event : standalone::canon_events()) {
|
||||
std::cout << "canon_event=" << event << "\n";
|
||||
}
|
||||
|
||||
std::filesystem::remove_all(temp_dir);
|
||||
return rc == INTERP_OK ? 0 : 1;
|
||||
}
|
||||
@@ -36,8 +36,8 @@ const std::vector<std::string> &canon_events()
|
||||
} // namespace standalone
|
||||
|
||||
bool GET_BLOCK_DELETE(void) { return false; }
|
||||
void FINISH(void) {}
|
||||
void ON_RESET(void) {}
|
||||
void FINISH(void) { standalone::push_canon_event("FINISH"); }
|
||||
void ON_RESET(void) { standalone::push_canon_event("ON_RESET"); }
|
||||
|
||||
USER_DEFINED_FUNCTION_TYPE USER_DEFINED_FUNCTION[USER_DEFINED_FUNCTION_NUM] = {};
|
||||
|
||||
@@ -50,7 +50,7 @@ int USER_DEFINED_FUNCTION_ADD(USER_DEFINED_FUNCTION_TYPE func, int num)
|
||||
return num;
|
||||
}
|
||||
|
||||
void INIT_CANON() {}
|
||||
void INIT_CANON() { standalone::push_canon_event("INIT_CANON"); }
|
||||
void SET_G5X_OFFSET(int index,
|
||||
double x, double y, double z,
|
||||
double a, double b, double c,
|
||||
@@ -307,7 +307,7 @@ void CHANGE_TOOL_NUMBER(int pocket)
|
||||
oss << "CHANGE_TOOL_NUMBER pocket=" << pocket;
|
||||
standalone::push_canon_event(oss.str());
|
||||
}
|
||||
void RELOAD_TOOLDATA(void) {}
|
||||
void RELOAD_TOOLDATA(void) { standalone::push_canon_event("RELOAD_TOOLDATA"); }
|
||||
void CLAMP_AXIS(CANON_AXIS) {}
|
||||
void DISABLE_ADAPTIVE_FEED() { standalone::push_canon_event("DISABLE_ADAPTIVE_FEED"); }
|
||||
void ENABLE_ADAPTIVE_FEED() { standalone::push_canon_event("ENABLE_ADAPTIVE_FEED"); }
|
||||
@@ -390,15 +390,52 @@ int WAIT(int index, int input_type, int wait_type, double timeout)
|
||||
standalone::push_canon_event(oss.str());
|
||||
return 0;
|
||||
}
|
||||
int UNLOCK_ROTARY(int, int) { return 0; }
|
||||
int LOCK_ROTARY(int, int) { return 0; }
|
||||
void UPDATE_TAG(const StateTag &) {}
|
||||
int UNLOCK_ROTARY(int line_no, int joint_num)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << "UNLOCK_ROTARY line=" << line_no << " joint=" << joint_num;
|
||||
standalone::push_canon_event(oss.str());
|
||||
return 0;
|
||||
}
|
||||
int LOCK_ROTARY(int line_no, int joint_num)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << "LOCK_ROTARY line=" << line_no << " joint=" << joint_num;
|
||||
standalone::push_canon_event(oss.str());
|
||||
return 0;
|
||||
}
|
||||
void UPDATE_TAG(const StateTag &tag)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << "UPDATE_TAG"
|
||||
<< " line=" << tag.fields[GM_FIELD_LINE_NUMBER]
|
||||
<< " g0=" << tag.fields[GM_FIELD_G_MODE_0]
|
||||
<< " motion=" << tag.fields[GM_FIELD_MOTION_MODE]
|
||||
<< " plane=" << tag.fields[GM_FIELD_PLANE]
|
||||
<< " origin=" << tag.fields[GM_FIELD_ORIGIN]
|
||||
<< " feed=" << tag.fields_float[GM_FIELD_FLOAT_FEED]
|
||||
<< " speed=" << tag.fields_float[GM_FIELD_FLOAT_SPEED]
|
||||
<< " flags=" << tag.flags.to_ulong();
|
||||
standalone::push_canon_event(oss.str());
|
||||
}
|
||||
|
||||
void MESSAGE(char *s) { standalone::push_canon_event(std::string("MESSAGE: ") + (s ? s : "")); }
|
||||
void LOG(char *) {}
|
||||
void LOGOPEN(char *) {}
|
||||
void LOGAPPEND(char *) {}
|
||||
void LOGCLOSE() {}
|
||||
void LOG(char *s)
|
||||
{
|
||||
standalone::push_canon_event(std::string("LOG: ") + (s ? s : ""));
|
||||
}
|
||||
void LOGOPEN(char *s)
|
||||
{
|
||||
standalone::push_canon_event(std::string("LOGOPEN: ") + (s ? s : ""));
|
||||
}
|
||||
void LOGAPPEND(char *s)
|
||||
{
|
||||
standalone::push_canon_event(std::string("LOGAPPEND: ") + (s ? s : ""));
|
||||
}
|
||||
void LOGCLOSE()
|
||||
{
|
||||
standalone::push_canon_event("LOGCLOSE");
|
||||
}
|
||||
|
||||
void CANON_ERROR(const char *fmt, ...)
|
||||
{
|
||||
|
||||
@@ -187,9 +187,9 @@ setup::setup()
|
||||
a_axis_wrapped(0),
|
||||
b_axis_wrapped(0),
|
||||
c_axis_wrapped(0),
|
||||
a_indexer_jnum(0),
|
||||
b_indexer_jnum(0),
|
||||
c_indexer_jnum(0),
|
||||
a_indexer_jnum(-1),
|
||||
b_indexer_jnum(-1),
|
||||
c_indexer_jnum(-1),
|
||||
lathe_diameter_mode(0),
|
||||
mdi_interrupt(0),
|
||||
feature_set(0),
|
||||
|
||||
4
wasm-port/tests/fixtures/canon/comment_logging.events
vendored
Normal file
4
wasm-port/tests/fixtures/canon/comment_logging.events
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
canon_event=LOGOPEN: session.log
|
||||
canon_event=LOG: feed log line
|
||||
canon_event=LOGAPPEND: append log line
|
||||
canon_event=LOGCLOSE
|
||||
2
wasm-port/tests/fixtures/canon/file_open_reset.events
vendored
Normal file
2
wasm-port/tests/fixtures/canon/file_open_reset.events
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
canon_event=ON_RESET
|
||||
canon_event=STRAIGHT_TRAVERSE line=1 x=1 y=0 z=0 a=0 b=0 c=0 u=0 v=0 w=0
|
||||
2
wasm-port/tests/fixtures/canon/percent_file_finish.events
vendored
Normal file
2
wasm-port/tests/fixtures/canon/percent_file_finish.events
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
canon_event=STRAIGHT_TRAVERSE line=2 x=1 y=0 z=0 a=0 b=0 c=0 u=0 v=0 w=0
|
||||
canon_event=FINISH
|
||||
2
wasm-port/tests/fixtures/canon/state_tag_motion.events
vendored
Normal file
2
wasm-port/tests/fixtures/canon/state_tag_motion.events
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
canon_event=UPDATE_TAG line=1
|
||||
canon_event=UPDATE_TAG line=2
|
||||
1
wasm-port/tests/fixtures/canon/tool_reload.events
vendored
Normal file
1
wasm-port/tests/fixtures/canon/tool_reload.events
vendored
Normal file
@@ -0,0 +1 @@
|
||||
canon_event=RELOAD_TOOLDATA
|
||||
4
wasm-port/tests/fixtures/gcode/comment_logging.ngc
vendored
Normal file
4
wasm-port/tests/fixtures/gcode/comment_logging.ngc
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
(LOGOPEN,session.log)
|
||||
(LOG,feed log line)
|
||||
(LOGAPPEND,append log line)
|
||||
(LOGCLOSE)
|
||||
1
wasm-port/tests/fixtures/gcode/file_open_reset.ngc
vendored
Normal file
1
wasm-port/tests/fixtures/gcode/file_open_reset.ngc
vendored
Normal file
@@ -0,0 +1 @@
|
||||
G0 X1
|
||||
3
wasm-port/tests/fixtures/gcode/percent_file_finish.ngc
vendored
Normal file
3
wasm-port/tests/fixtures/gcode/percent_file_finish.ngc
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
%
|
||||
G0 X1
|
||||
%
|
||||
2
wasm-port/tests/fixtures/gcode/state_tag_motion.ngc
vendored
Normal file
2
wasm-port/tests/fixtures/gcode/state_tag_motion.ngc
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
G90 G17 G0 X1 Y2
|
||||
G1 X3 Y4 F120
|
||||
1
wasm-port/tests/fixtures/gcode/tool_reload.ngc
vendored
Normal file
1
wasm-port/tests/fixtures/gcode/tool_reload.ngc
vendored
Normal file
@@ -0,0 +1 @@
|
||||
G10 L0
|
||||
@@ -12,6 +12,7 @@ NAMEDPARAM_INI_FIXTURE="$ROOT_DIR/tests/fixtures/ini/namedparams.ini"
|
||||
"$ROOT_DIR/tools/verify_upstream_baseline.sh"
|
||||
"$ROOT_DIR/tools/verify_vendor_sync.sh"
|
||||
"$ROOT_DIR/tools/verify_no_standalone_cnc_semantics.sh"
|
||||
"$ROOT_DIR/tools/verify_native_linuxcnc_fixture_baseline.sh"
|
||||
"$ROOT_DIR/tools/build_native_probes.sh"
|
||||
|
||||
check_source_probe_coverage() {
|
||||
@@ -152,6 +153,10 @@ check_exitcode linuxcnc_interp_minimal_harness
|
||||
check_exitcode linuxcnc_interp_minimal_harness.run
|
||||
check_exitcode linuxcnc_parameter_file_harness
|
||||
check_exitcode linuxcnc_parameter_file_harness.run
|
||||
check_exitcode linuxcnc_interp_init_harness
|
||||
check_exitcode linuxcnc_interp_init_harness.run
|
||||
check_exitcode linuxcnc_indexer_harness
|
||||
check_exitcode linuxcnc_indexer_harness.run
|
||||
check_exitcode linuxcnc_rs274_compile_probe
|
||||
check_exitcode linuxcnc_kins_util_source_probe
|
||||
check_exitcode linuxcnc_cubic_source_probe
|
||||
@@ -238,6 +243,31 @@ grep -Fq "saved_has_5399=1" "$PARAMETER_FILE_STDOUT"
|
||||
grep -Fq "saved_has_named_param=0" "$PARAMETER_FILE_STDOUT"
|
||||
grep -Fq "backup_has_original_5161=1" "$PARAMETER_FILE_STDOUT"
|
||||
|
||||
INIT_HARNESS_STDOUT="$BUILD_DIR/linuxcnc_interp_init_harness.run.stdout.log"
|
||||
grep -Fq "init=0" "$INIT_HARNESS_STDOUT"
|
||||
grep -Fq "setup.length_units=2" "$INIT_HARNESS_STDOUT"
|
||||
grep -Fq "setup.origin_index=1" "$INIT_HARNESS_STDOUT"
|
||||
grep -Fq "setup.distance_mode=0" "$INIT_HARNESS_STDOUT"
|
||||
grep -Fq "setup.feed_mode=0" "$INIT_HARNESS_STDOUT"
|
||||
grep -Fq "setup.motion_mode=800" "$INIT_HARNESS_STDOUT"
|
||||
grep -Fq "canon_event=INIT_CANON" "$INIT_HARNESS_STDOUT"
|
||||
grep -Fq "canon_event=USE_LENGTH_UNITS units=2" "$INIT_HARNESS_STDOUT"
|
||||
grep -Fq "canon_event=SET_G5X_OFFSET index=1" "$INIT_HARNESS_STDOUT"
|
||||
grep -Fq "canon_event=SET_G92_OFFSET x=0 y=0 z=0" "$INIT_HARNESS_STDOUT"
|
||||
grep -Fq "canon_event=SET_XY_ROTATION rotation=0" "$INIT_HARNESS_STDOUT"
|
||||
grep -Fq "canon_event=SET_FEED_REFERENCE reference=2" "$INIT_HARNESS_STDOUT"
|
||||
|
||||
INDEXER_HARNESS_STDOUT="$BUILD_DIR/linuxcnc_indexer_harness.run.stdout.log"
|
||||
grep -Fq "execute=0" "$INDEXER_HARNESS_STDOUT"
|
||||
grep -Fq "post_a=90" "$INDEXER_HARNESS_STDOUT"
|
||||
grep -Fq "canon_event=SET_MOTION_CONTROL_MODE mode=2 tolerance=0" "$INDEXER_HARNESS_STDOUT"
|
||||
grep -Fq "canon_event=UNLOCK_ROTARY line=1 joint=0" "$INDEXER_HARNESS_STDOUT"
|
||||
grep -Fq "canon_event=STRAIGHT_TRAVERSE line=1 x=0 y=0 z=0 a=90 b=0 c=0 u=0 v=0 w=0" "$INDEXER_HARNESS_STDOUT"
|
||||
grep -Fq "canon_event=LOCK_ROTARY line=1 joint=0" "$INDEXER_HARNESS_STDOUT"
|
||||
grep -Fq "canon_event=SET_MOTION_CONTROL_MODE mode=1 tolerance=0" "$INDEXER_HARNESS_STDOUT"
|
||||
grep -Fq "canon_event=SET_NAIVECAM_TOLERANCE tolerance=0" "$INDEXER_HARNESS_STDOUT"
|
||||
grep -Fq "canon_event=UPDATE_TAG line=1" "$INDEXER_HARNESS_STDOUT"
|
||||
|
||||
TP_API_STDOUT="$BUILD_DIR/linuxcnc_tp_api_probe.run.stdout.log"
|
||||
grep -Fq "tp_default_queue_size=32" "$TP_API_STDOUT"
|
||||
grep -Fq "tp_err_ok=0" "$TP_API_STDOUT"
|
||||
@@ -438,10 +468,10 @@ check_fixture_output() {
|
||||
local stdout_file="$3"
|
||||
local require_mdi="${4:-1}"
|
||||
|
||||
grep -Fq "read=0" "$stdout_file"
|
||||
grep -Fq "parse_line=0" "$stdout_file"
|
||||
|
||||
if [[ "$require_mdi" == "1" ]]; then
|
||||
grep -Fq "read=0" "$stdout_file"
|
||||
grep -Fq "parse_line=0" "$stdout_file"
|
||||
|
||||
local line_count
|
||||
line_count="$(grep -cv '^[[:space:]]*$' "$fixture")"
|
||||
local line_number
|
||||
@@ -484,7 +514,7 @@ for fixture in "$GCODE_FIXTURE_DIR"/*.ngc; do
|
||||
>"$stdout_file" \
|
||||
2>"$stderr_file"
|
||||
require_mdi=1
|
||||
if [[ "$name" == "oword_subroutine" ]]; then
|
||||
if [[ "$name" == "oword_subroutine" || "$name" == "percent_file_finish" ]]; then
|
||||
require_mdi=0
|
||||
fi
|
||||
check_fixture_output "$fixture" "$expected" "$stdout_file" "$require_mdi"
|
||||
|
||||
@@ -629,6 +629,16 @@ PARAMETER_FILE_SOURCES=(
|
||||
"$WRAP_DIR/linuxcnc_parameter_file_harness.cpp"
|
||||
)
|
||||
|
||||
INIT_HARNESS_SOURCES=(
|
||||
"${INTERP_CORE_SOURCES[@]}"
|
||||
"$WRAP_DIR/linuxcnc_interp_init_harness.cpp"
|
||||
)
|
||||
|
||||
INDEXER_HARNESS_SOURCES=(
|
||||
"${INTERP_CORE_SOURCES[@]}"
|
||||
"$WRAP_DIR/linuxcnc_indexer_harness.cpp"
|
||||
)
|
||||
|
||||
build_binary_target \
|
||||
linuxcnc_ini_probe \
|
||||
"$BUILD_DIR/linuxcnc_ini_probe" \
|
||||
@@ -1123,6 +1133,52 @@ else
|
||||
"$BUILD_DIR/linuxcnc_parameter_file_harness.run.stderr.log"
|
||||
fi
|
||||
|
||||
build_binary_target \
|
||||
linuxcnc_interp_init_harness \
|
||||
"$BUILD_DIR/linuxcnc_interp_init_harness" \
|
||||
MINIMAL_FLAGS \
|
||||
INIT_HARNESS_SOURCES \
|
||||
MINIMAL_LINK_FLAGS \
|
||||
-lfmt
|
||||
|
||||
if [[ "$(tr -d '[:space:]' < "$BUILD_DIR/linuxcnc_interp_init_harness.exitcode")" == "0" ]]; then
|
||||
set +e
|
||||
"$BUILD_DIR/linuxcnc_interp_init_harness" \
|
||||
>"$BUILD_DIR/linuxcnc_interp_init_harness.run.stdout.log" \
|
||||
2>"$BUILD_DIR/linuxcnc_interp_init_harness.run.stderr.log"
|
||||
INTERP_INIT_RUN_RC=$?
|
||||
set -e
|
||||
echo "$INTERP_INIT_RUN_RC" > "$BUILD_DIR/linuxcnc_interp_init_harness.run.exitcode"
|
||||
else
|
||||
rm -f \
|
||||
"$BUILD_DIR/linuxcnc_interp_init_harness.run.exitcode" \
|
||||
"$BUILD_DIR/linuxcnc_interp_init_harness.run.stdout.log" \
|
||||
"$BUILD_DIR/linuxcnc_interp_init_harness.run.stderr.log"
|
||||
fi
|
||||
|
||||
build_binary_target \
|
||||
linuxcnc_indexer_harness \
|
||||
"$BUILD_DIR/linuxcnc_indexer_harness" \
|
||||
MINIMAL_FLAGS \
|
||||
INDEXER_HARNESS_SOURCES \
|
||||
MINIMAL_LINK_FLAGS \
|
||||
-lfmt
|
||||
|
||||
if [[ "$(tr -d '[:space:]' < "$BUILD_DIR/linuxcnc_indexer_harness.exitcode")" == "0" ]]; then
|
||||
set +e
|
||||
"$BUILD_DIR/linuxcnc_indexer_harness" \
|
||||
>"$BUILD_DIR/linuxcnc_indexer_harness.run.stdout.log" \
|
||||
2>"$BUILD_DIR/linuxcnc_indexer_harness.run.stderr.log"
|
||||
INDEXER_RUN_RC=$?
|
||||
set -e
|
||||
echo "$INDEXER_RUN_RC" > "$BUILD_DIR/linuxcnc_indexer_harness.run.exitcode"
|
||||
else
|
||||
rm -f \
|
||||
"$BUILD_DIR/linuxcnc_indexer_harness.run.exitcode" \
|
||||
"$BUILD_DIR/linuxcnc_indexer_harness.run.stdout.log" \
|
||||
"$BUILD_DIR/linuxcnc_indexer_harness.run.stderr.log"
|
||||
fi
|
||||
|
||||
build_object_target \
|
||||
linuxcnc_rs274_compile_probe \
|
||||
"$BUILD_DIR/linuxcnc_rs274_compile_probe.o" \
|
||||
|
||||
186
wasm-port/tools/verify_native_linuxcnc_fixture_baseline.sh
Executable file
186
wasm-port/tools/verify_native_linuxcnc_fixture_baseline.sh
Executable file
@@ -0,0 +1,186 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ROOT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
|
||||
UPSTREAM_RS274="$ROOT_DIR/../linuxcnc/bin/rs274"
|
||||
GCODE_FIXTURE_DIR="$ROOT_DIR/tests/fixtures/gcode"
|
||||
CANON_FIXTURE_DIR="$ROOT_DIR/tests/fixtures/canon"
|
||||
|
||||
FIXTURES=(
|
||||
minimal_linear
|
||||
length_units
|
||||
plane_selection
|
||||
modal_incremental
|
||||
)
|
||||
|
||||
if [[ ! -x "$UPSTREAM_RS274" ]]; then
|
||||
echo "missing upstream rs274 executable: $UPSTREAM_RS274" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
TMP_DIR="$(mktemp -d)"
|
||||
trap 'rm -rf "$TMP_DIR"' EXIT
|
||||
|
||||
normalize_standalone_events() {
|
||||
awk '
|
||||
function norm(value) {
|
||||
return sprintf("%.12g", value + 0)
|
||||
}
|
||||
|
||||
/^canon_event=/ {
|
||||
line = $0
|
||||
sub(/^canon_event=/, "", line)
|
||||
|
||||
if (line ~ /^SELECT_PLANE plane=/) {
|
||||
value = line
|
||||
sub(/^SELECT_PLANE plane=/, "", value)
|
||||
if (value == "1") {
|
||||
print "SELECT_PLANE|XY"
|
||||
} else if (value == "2") {
|
||||
print "SELECT_PLANE|YZ"
|
||||
} else if (value == "3") {
|
||||
print "SELECT_PLANE|XZ"
|
||||
}
|
||||
next
|
||||
}
|
||||
|
||||
if (line ~ /^USE_LENGTH_UNITS units=/) {
|
||||
value = line
|
||||
sub(/^USE_LENGTH_UNITS units=/, "", value)
|
||||
if (value == "1") {
|
||||
print "USE_LENGTH_UNITS|INCHES"
|
||||
} else if (value == "2") {
|
||||
print "USE_LENGTH_UNITS|MM"
|
||||
}
|
||||
next
|
||||
}
|
||||
|
||||
if (line ~ /^SET_FEED_RATE rate=/) {
|
||||
value = line
|
||||
sub(/^SET_FEED_RATE rate=/, "", value)
|
||||
print "SET_FEED_RATE|" norm(value)
|
||||
next
|
||||
}
|
||||
|
||||
if (line ~ /^STRAIGHT_(TRAVERSE|FEED) /) {
|
||||
split(line, fields, /[[:space:]]+/)
|
||||
for (i in fields) {
|
||||
split(fields[i], pair, "=")
|
||||
values[pair[1]] = pair[2]
|
||||
}
|
||||
print fields[1] "|" norm(values["x"]) "|" norm(values["y"]) "|" \
|
||||
norm(values["z"]) "|" norm(values["a"]) "|" norm(values["b"]) "|" \
|
||||
norm(values["c"])
|
||||
delete values
|
||||
next
|
||||
}
|
||||
}
|
||||
'
|
||||
}
|
||||
|
||||
normalize_upstream_rs274_output() {
|
||||
awk '
|
||||
function norm(value) {
|
||||
return sprintf("%.12g", value + 0)
|
||||
}
|
||||
|
||||
function args_of(call, args) {
|
||||
args = call
|
||||
sub(/^[^(]+\(/, "", args)
|
||||
sub(/\).*$/, "", args)
|
||||
gsub(/[[:space:]]/, "", args)
|
||||
return args
|
||||
}
|
||||
|
||||
/^[[:space:]]*[0-9]+[[:space:]]+N\.\.\.\.\./ {
|
||||
line = $0
|
||||
sub(/^[[:space:]]*[0-9]+[[:space:]]+N\.\.\.\.\.[[:space:]]+/, "", line)
|
||||
|
||||
if (line == "ON_RESET()") {
|
||||
seen_reset = 1
|
||||
next
|
||||
}
|
||||
|
||||
if (!seen_reset) {
|
||||
next
|
||||
}
|
||||
|
||||
if (line ~ /^SELECT_PLANE\(CANON_PLANE_/) {
|
||||
value = line
|
||||
sub(/^SELECT_PLANE\(CANON_PLANE_/, "", value)
|
||||
sub(/\)$/, "", value)
|
||||
print "SELECT_PLANE|" value
|
||||
next
|
||||
}
|
||||
|
||||
if (line ~ /^USE_LENGTH_UNITS\(CANON_UNITS_/) {
|
||||
value = line
|
||||
sub(/^USE_LENGTH_UNITS\(CANON_UNITS_/, "", value)
|
||||
sub(/\)$/, "", value)
|
||||
print "USE_LENGTH_UNITS|" value
|
||||
next
|
||||
}
|
||||
|
||||
if (line ~ /^SET_FEED_RATE\(/) {
|
||||
args = args_of(line)
|
||||
print "SET_FEED_RATE|" norm(args)
|
||||
next
|
||||
}
|
||||
|
||||
if (line ~ /^STRAIGHT_(TRAVERSE|FEED)\(/) {
|
||||
op = line
|
||||
sub(/\(.*/, "", op)
|
||||
args = args_of(line)
|
||||
split(args, values, ",")
|
||||
print op "|" norm(values[1]) "|" norm(values[2]) "|" norm(values[3]) "|" \
|
||||
norm(values[4]) "|" norm(values[5]) "|" norm(values[6])
|
||||
next
|
||||
}
|
||||
}
|
||||
'
|
||||
}
|
||||
|
||||
for name in "${FIXTURES[@]}"; do
|
||||
gcode_file="$GCODE_FIXTURE_DIR/$name.ngc"
|
||||
expected_file="$CANON_FIXTURE_DIR/$name.events"
|
||||
native_raw="$TMP_DIR/$name.rs274.raw"
|
||||
native_norm="$TMP_DIR/$name.rs274.normalized"
|
||||
expected_norm="$TMP_DIR/$name.expected.normalized"
|
||||
|
||||
if [[ ! -f "$gcode_file" ]]; then
|
||||
echo "missing G-code fixture: $gcode_file" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ ! -f "$expected_file" ]]; then
|
||||
echo "missing canonical fixture: $expected_file" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
set +e
|
||||
"$UPSTREAM_RS274" -g "$gcode_file" > "$native_raw" 2>&1
|
||||
rs274_rc=$?
|
||||
set -e
|
||||
|
||||
if [[ "$rs274_rc" != "0" ]] && ! grep -Fq "File ended with no percent sign (%) or program end (M2)" "$native_raw"; then
|
||||
echo "upstream rs274 failed for fixture: $name" >&2
|
||||
sed -n '1,160p' "$native_raw" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
normalize_upstream_rs274_output < "$native_raw" > "$native_norm"
|
||||
normalize_standalone_events < "$expected_file" > "$expected_norm"
|
||||
|
||||
if [[ ! -s "$native_norm" ]]; then
|
||||
echo "no normalized upstream rs274 events for fixture: $name" >&2
|
||||
sed -n '1,160p' "$native_raw" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! diff -u "$expected_norm" "$native_norm"; then
|
||||
echo "native LinuxCNC rs274 baseline mismatch for fixture: $name" >&2
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
echo "native LinuxCNC fixture baseline validation complete"
|
||||
Reference in New Issue
Block a user