按建议继续完成后续工作
结论:upstream rs274 side-by-side 基线已从简单 parser/conversion fixture 扩展到 motion、offset、feed-control、comment/logging、numbered parameter、spindle orient、file finish 和 tool reload 等稳定 canonical 事件;完整 native 验证已通过。
This commit is contained in:
@@ -25,7 +25,7 @@ The native validation script runs these checks in order:
|
|||||||
3. `tools/verify_no_standalone_cnc_semantics.sh`
|
3. `tools/verify_no_standalone_cnc_semantics.sh`
|
||||||
Confirms standalone code has not reintroduced `Interp::convert_g()`.
|
Confirms standalone code has not reintroduced `Interp::convert_g()`.
|
||||||
4. `tools/verify_native_linuxcnc_fixture_baseline.sh`
|
4. `tools/verify_native_linuxcnc_fixture_baseline.sh`
|
||||||
Runs a narrow side-by-side fixture baseline through upstream
|
Runs a side-by-side fixture baseline through upstream
|
||||||
`../linuxcnc/bin/rs274` and compares normalized canonical events for
|
`../linuxcnc/bin/rs274` and compares normalized canonical events for
|
||||||
fixtures that do not require standalone-only runtime adapters.
|
fixtures that do not require standalone-only runtime adapters.
|
||||||
5. `tools/build_native_probes.sh`
|
5. `tools/build_native_probes.sh`
|
||||||
@@ -108,8 +108,9 @@ Current validation is native-only. WASM, browser, SDK, OPFS, and full
|
|||||||
machine-session validation remain future work.
|
machine-session validation remain future work.
|
||||||
|
|
||||||
The current fixture expectations validate standalone behavior against both the
|
The current fixture expectations validate standalone behavior against both the
|
||||||
vendored LinuxCNC source path and a first upstream `rs274` side-by-side
|
vendored LinuxCNC source path and an upstream `rs274` side-by-side baseline for
|
||||||
baseline for simple parser/conversion fixtures. Fixtures that depend on
|
parser/conversion, offsets, feed-control, comment/logging, numbered-parameter,
|
||||||
|
spindle-orient, file-finish, and tool-reload fixtures. Fixtures that depend on
|
||||||
standalone-only runtime adapters, HAL/INI/tool table setup, or richer machine
|
standalone-only runtime adapters, HAL/INI/tool table setup, or richer machine
|
||||||
session state still need dedicated native LinuxCNC baselines.
|
session state still need dedicated native LinuxCNC baselines.
|
||||||
|
|
||||||
|
|||||||
@@ -66,9 +66,10 @@ semantic rewrites:
|
|||||||
now have standalone interpreter fixture coverage through vendored LinuxCNC
|
now have standalone interpreter fixture coverage through vendored LinuxCNC
|
||||||
source.
|
source.
|
||||||
- Fixture expectations are checked against the standalone vendored source
|
- Fixture expectations are checked against the standalone vendored source
|
||||||
path. A first upstream `rs274` side-by-side baseline now covers simple
|
path. The upstream `rs274` side-by-side baseline now covers simple motion,
|
||||||
parser/conversion fixtures; adapter-heavy fixtures still need dedicated
|
offsets, feed-control, comment/logging, numbered-parameter, spindle-orient,
|
||||||
native LinuxCNC baselines.
|
file-finish, and tool-reload fixtures; adapter-heavy fixtures still need
|
||||||
|
dedicated native LinuxCNC baselines.
|
||||||
|
|
||||||
## Current Drift Conclusion
|
## Current Drift Conclusion
|
||||||
|
|
||||||
|
|||||||
@@ -502,12 +502,13 @@ Current verified progress:
|
|||||||
and `LOGCLOSE`. `tests/fixtures/gcode/comment_logging.ngc` and
|
and `LOGCLOSE`. `tests/fixtures/gcode/comment_logging.ngc` and
|
||||||
`tests/fixtures/canon/comment_logging.events` pin LinuxCNC comment logging
|
`tests/fixtures/canon/comment_logging.events` pin LinuxCNC comment logging
|
||||||
dispatch without adding standalone comment semantics.
|
dispatch without adding standalone comment semantics.
|
||||||
- `tools/verify_native_linuxcnc_fixture_baseline.sh` now runs a first
|
- `tools/verify_native_linuxcnc_fixture_baseline.sh` now runs an expanded
|
||||||
side-by-side baseline against upstream `../linuxcnc/bin/rs274`. It normalizes
|
side-by-side baseline against upstream `../linuxcnc/bin/rs274`. It normalizes
|
||||||
native LinuxCNC canonical output for simple parser/conversion fixtures
|
native LinuxCNC canonical output for simple motion, offsets, feed-control,
|
||||||
(`minimal_linear`, `length_units`, `plane_selection`, and
|
comment/logging, numbered-parameter, spindle-orient, file-finish, and
|
||||||
`modal_incremental`) and compares it with the standalone fixture events,
|
tool-reload fixtures, filters native output to the event classes each
|
||||||
without introducing a project-authored CNC semantics oracle.
|
standalone fixture explicitly expects, and compares the result without
|
||||||
|
introducing a project-authored CNC semantics oracle.
|
||||||
- `tests/fixtures/gcode_errors/g1_zero_feed.ngc` and
|
- `tests/fixtures/gcode_errors/g1_zero_feed.ngc` and
|
||||||
`tests/fixtures/canon_errors/g1_zero_feed.expected` pin the negative
|
`tests/fixtures/canon_errors/g1_zero_feed.expected` pin the negative
|
||||||
`G1` zero-feed case. The source basis is LinuxCNC
|
`G1` zero-feed case. The source basis is LinuxCNC
|
||||||
|
|||||||
@@ -8,9 +8,19 @@ CANON_FIXTURE_DIR="$ROOT_DIR/tests/fixtures/canon"
|
|||||||
|
|
||||||
FIXTURES=(
|
FIXTURES=(
|
||||||
minimal_linear
|
minimal_linear
|
||||||
|
comment_logging
|
||||||
|
coordinate_offsets
|
||||||
|
cutter_comp_motion
|
||||||
|
feed_control_modes
|
||||||
|
g53_machine_coordinates
|
||||||
length_units
|
length_units
|
||||||
plane_selection
|
plane_selection
|
||||||
modal_incremental
|
modal_incremental
|
||||||
|
numbered_params
|
||||||
|
percent_file_finish
|
||||||
|
position_params
|
||||||
|
spindle_orient
|
||||||
|
tool_reload
|
||||||
)
|
)
|
||||||
|
|
||||||
if [[ ! -x "$UPSTREAM_RS274" ]]; then
|
if [[ ! -x "$UPSTREAM_RS274" ]]; then
|
||||||
@@ -31,6 +41,31 @@ normalize_standalone_events() {
|
|||||||
line = $0
|
line = $0
|
||||||
sub(/^canon_event=/, "", line)
|
sub(/^canon_event=/, "", line)
|
||||||
|
|
||||||
|
if (line ~ /^COMMENT: /) {
|
||||||
|
sub(/^COMMENT: /, "", line)
|
||||||
|
print "COMMENT|" line
|
||||||
|
next
|
||||||
|
}
|
||||||
|
|
||||||
|
if (line ~ /^MESSAGE: /) {
|
||||||
|
sub(/^MESSAGE: /, "", line)
|
||||||
|
print "MESSAGE|" line
|
||||||
|
next
|
||||||
|
}
|
||||||
|
|
||||||
|
if (line ~ /^LOG(OPEN|APPEND)?: /) {
|
||||||
|
op = line
|
||||||
|
sub(/:.*/, "", op)
|
||||||
|
sub(/^[^:]+: /, "", line)
|
||||||
|
print op "|" line
|
||||||
|
next
|
||||||
|
}
|
||||||
|
|
||||||
|
if (line == "LOGCLOSE" || line == "FINISH" || line == "RELOAD_TOOLDATA") {
|
||||||
|
print line
|
||||||
|
next
|
||||||
|
}
|
||||||
|
|
||||||
if (line ~ /^SELECT_PLANE plane=/) {
|
if (line ~ /^SELECT_PLANE plane=/) {
|
||||||
value = line
|
value = line
|
||||||
sub(/^SELECT_PLANE plane=/, "", value)
|
sub(/^SELECT_PLANE plane=/, "", value)
|
||||||
@@ -55,6 +90,39 @@ normalize_standalone_events() {
|
|||||||
next
|
next
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (line ~ /^SET_G5X_OFFSET index=/) {
|
||||||
|
split(line, fields, /[[:space:]]+/)
|
||||||
|
for (i in fields) {
|
||||||
|
split(fields[i], pair, "=")
|
||||||
|
values[pair[1]] = pair[2]
|
||||||
|
}
|
||||||
|
print "SET_G5X_OFFSET|" values["index"] "|" norm(values["x"]) "|" \
|
||||||
|
norm(values["y"]) "|" norm(values["z"]) "|" norm(values["a"]) "|" \
|
||||||
|
norm(values["b"]) "|" norm(values["c"])
|
||||||
|
delete values
|
||||||
|
next
|
||||||
|
}
|
||||||
|
|
||||||
|
if (line ~ /^SET_G92_OFFSET /) {
|
||||||
|
split(line, fields, /[[:space:]]+/)
|
||||||
|
for (i in fields) {
|
||||||
|
split(fields[i], pair, "=")
|
||||||
|
values[pair[1]] = pair[2]
|
||||||
|
}
|
||||||
|
print "SET_G92_OFFSET|" norm(values["x"]) "|" norm(values["y"]) "|" \
|
||||||
|
norm(values["z"]) "|" norm(values["a"]) "|" norm(values["b"]) "|" \
|
||||||
|
norm(values["c"])
|
||||||
|
delete values
|
||||||
|
next
|
||||||
|
}
|
||||||
|
|
||||||
|
if (line ~ /^SET_XY_ROTATION rotation=/) {
|
||||||
|
value = line
|
||||||
|
sub(/^SET_XY_ROTATION rotation=/, "", value)
|
||||||
|
print "SET_XY_ROTATION|" norm(value)
|
||||||
|
next
|
||||||
|
}
|
||||||
|
|
||||||
if (line ~ /^SET_FEED_RATE rate=/) {
|
if (line ~ /^SET_FEED_RATE rate=/) {
|
||||||
value = line
|
value = line
|
||||||
sub(/^SET_FEED_RATE rate=/, "", value)
|
sub(/^SET_FEED_RATE rate=/, "", value)
|
||||||
@@ -62,6 +130,64 @@ normalize_standalone_events() {
|
|||||||
next
|
next
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (line ~ /^SET_FEED_MODE /) {
|
||||||
|
split(line, fields, /[[:space:]]+/)
|
||||||
|
for (i in fields) {
|
||||||
|
split(fields[i], pair, "=")
|
||||||
|
values[pair[1]] = pair[2]
|
||||||
|
}
|
||||||
|
print "SET_FEED_MODE|" values["spindle"] "|" values["mode"]
|
||||||
|
delete values
|
||||||
|
next
|
||||||
|
}
|
||||||
|
|
||||||
|
if (line ~ /^SET_MOTION_CONTROL_MODE /) {
|
||||||
|
split(line, fields, /[[:space:]]+/)
|
||||||
|
for (i in fields) {
|
||||||
|
split(fields[i], pair, "=")
|
||||||
|
values[pair[1]] = pair[2]
|
||||||
|
}
|
||||||
|
print "SET_MOTION_CONTROL_MODE|" values["mode"] "|" norm(values["tolerance"])
|
||||||
|
delete values
|
||||||
|
next
|
||||||
|
}
|
||||||
|
|
||||||
|
if (line ~ /^SET_NAIVECAM_TOLERANCE tolerance=/) {
|
||||||
|
value = line
|
||||||
|
sub(/^SET_NAIVECAM_TOLERANCE tolerance=/, "", value)
|
||||||
|
print "SET_NAIVECAM_TOLERANCE|" norm(value)
|
||||||
|
next
|
||||||
|
}
|
||||||
|
|
||||||
|
if (line ~ /^DWELL seconds=/) {
|
||||||
|
value = line
|
||||||
|
sub(/^DWELL seconds=/, "", value)
|
||||||
|
print "DWELL|" norm(value)
|
||||||
|
next
|
||||||
|
}
|
||||||
|
|
||||||
|
if (line ~ /^ORIENT_SPINDLE /) {
|
||||||
|
split(line, fields, /[[:space:]]+/)
|
||||||
|
for (i in fields) {
|
||||||
|
split(fields[i], pair, "=")
|
||||||
|
values[pair[1]] = pair[2]
|
||||||
|
}
|
||||||
|
print "ORIENT_SPINDLE|" values["spindle"] "|" norm(values["orientation"]) "|" values["mode"]
|
||||||
|
delete values
|
||||||
|
next
|
||||||
|
}
|
||||||
|
|
||||||
|
if (line ~ /^WAIT_SPINDLE_ORIENT_COMPLETE /) {
|
||||||
|
split(line, fields, /[[:space:]]+/)
|
||||||
|
for (i in fields) {
|
||||||
|
split(fields[i], pair, "=")
|
||||||
|
values[pair[1]] = pair[2]
|
||||||
|
}
|
||||||
|
print "WAIT_SPINDLE_ORIENT_COMPLETE|" values["spindle"] "|" norm(values["timeout"])
|
||||||
|
delete values
|
||||||
|
next
|
||||||
|
}
|
||||||
|
|
||||||
if (line ~ /^STRAIGHT_(TRAVERSE|FEED) /) {
|
if (line ~ /^STRAIGHT_(TRAVERSE|FEED) /) {
|
||||||
split(line, fields, /[[:space:]]+/)
|
split(line, fields, /[[:space:]]+/)
|
||||||
for (i in fields) {
|
for (i in fields) {
|
||||||
@@ -84,11 +210,16 @@ normalize_upstream_rs274_output() {
|
|||||||
return sprintf("%.12g", value + 0)
|
return sprintf("%.12g", value + 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function trim(value) {
|
||||||
|
sub(/^[[:space:]]+/, "", value)
|
||||||
|
sub(/[[:space:]]+$/, "", value)
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
function args_of(call, args) {
|
function args_of(call, args) {
|
||||||
args = call
|
args = call
|
||||||
sub(/^[^(]+\(/, "", args)
|
sub(/^[^(]+\(/, "", args)
|
||||||
sub(/\).*$/, "", args)
|
sub(/\).*$/, "", args)
|
||||||
gsub(/[[:space:]]/, "", args)
|
|
||||||
return args
|
return args
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -105,6 +236,39 @@ normalize_upstream_rs274_output() {
|
|||||||
next
|
next
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (line ~ /^COMMENT\("/) {
|
||||||
|
value = args_of(line)
|
||||||
|
sub(/^"/, "", value)
|
||||||
|
sub(/"$/, "", value)
|
||||||
|
print "COMMENT|" value
|
||||||
|
next
|
||||||
|
}
|
||||||
|
|
||||||
|
if (line ~ /^MESSAGE\("/) {
|
||||||
|
value = args_of(line)
|
||||||
|
sub(/^"/, "", value)
|
||||||
|
sub(/"$/, "", value)
|
||||||
|
print "MESSAGE|" value
|
||||||
|
next
|
||||||
|
}
|
||||||
|
|
||||||
|
if (line ~ /^LOG(OPEN|APPEND)?\("/) {
|
||||||
|
op = line
|
||||||
|
sub(/\(.*/, "", op)
|
||||||
|
value = args_of(line)
|
||||||
|
sub(/^"/, "", value)
|
||||||
|
sub(/"$/, "", value)
|
||||||
|
print op "|" value
|
||||||
|
next
|
||||||
|
}
|
||||||
|
|
||||||
|
if (line == "LOGCLOSE()" || line == "FINISH()" || line == "RELOAD_TOOLDATA()") {
|
||||||
|
value = line
|
||||||
|
sub(/\(\)$/, "", value)
|
||||||
|
print value
|
||||||
|
next
|
||||||
|
}
|
||||||
|
|
||||||
if (line ~ /^SELECT_PLANE\(CANON_PLANE_/) {
|
if (line ~ /^SELECT_PLANE\(CANON_PLANE_/) {
|
||||||
value = line
|
value = line
|
||||||
sub(/^SELECT_PLANE\(CANON_PLANE_/, "", value)
|
sub(/^SELECT_PLANE\(CANON_PLANE_/, "", value)
|
||||||
@@ -121,12 +285,86 @@ normalize_upstream_rs274_output() {
|
|||||||
next
|
next
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (line ~ /^SET_G5X_OFFSET\(/) {
|
||||||
|
args = args_of(line)
|
||||||
|
split(args, values, ",")
|
||||||
|
print "SET_G5X_OFFSET|" trim(values[1]) "|" norm(values[2]) "|" norm(values[3]) "|" \
|
||||||
|
norm(values[4]) "|" norm(values[5]) "|" norm(values[6]) "|" norm(values[7])
|
||||||
|
next
|
||||||
|
}
|
||||||
|
|
||||||
|
if (line ~ /^SET_G92_OFFSET\(/) {
|
||||||
|
args = args_of(line)
|
||||||
|
split(args, values, ",")
|
||||||
|
print "SET_G92_OFFSET|" norm(values[1]) "|" norm(values[2]) "|" norm(values[3]) "|" \
|
||||||
|
norm(values[4]) "|" norm(values[5]) "|" norm(values[6])
|
||||||
|
next
|
||||||
|
}
|
||||||
|
|
||||||
|
if (line ~ /^SET_XY_ROTATION\(/) {
|
||||||
|
args = args_of(line)
|
||||||
|
print "SET_XY_ROTATION|" norm(args)
|
||||||
|
next
|
||||||
|
}
|
||||||
|
|
||||||
if (line ~ /^SET_FEED_RATE\(/) {
|
if (line ~ /^SET_FEED_RATE\(/) {
|
||||||
args = args_of(line)
|
args = args_of(line)
|
||||||
print "SET_FEED_RATE|" norm(args)
|
print "SET_FEED_RATE|" norm(args)
|
||||||
next
|
next
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (line ~ /^SET_FEED_MODE\(/) {
|
||||||
|
args = args_of(line)
|
||||||
|
split(args, values, ",")
|
||||||
|
print "SET_FEED_MODE|" trim(values[1]) "|" trim(values[2])
|
||||||
|
next
|
||||||
|
}
|
||||||
|
|
||||||
|
if (line ~ /^SET_MOTION_CONTROL_MODE\(/) {
|
||||||
|
args = args_of(line)
|
||||||
|
split(args, values, ",")
|
||||||
|
mode_name = trim(values[1])
|
||||||
|
if (mode_name == "CANON_EXACT_STOP") {
|
||||||
|
mode = 1
|
||||||
|
} else if (mode_name == "CANON_EXACT_PATH") {
|
||||||
|
mode = 2
|
||||||
|
} else if (mode_name == "CANON_CONTINUOUS") {
|
||||||
|
mode = 3
|
||||||
|
} else {
|
||||||
|
next
|
||||||
|
}
|
||||||
|
print "SET_MOTION_CONTROL_MODE|" mode "|" norm(values[2])
|
||||||
|
next
|
||||||
|
}
|
||||||
|
|
||||||
|
if (line ~ /^SET_NAIVECAM_TOLERANCE\(/) {
|
||||||
|
args = args_of(line)
|
||||||
|
print "SET_NAIVECAM_TOLERANCE|" norm(args)
|
||||||
|
next
|
||||||
|
}
|
||||||
|
|
||||||
|
if (line ~ /^DWELL\(/) {
|
||||||
|
args = args_of(line)
|
||||||
|
print "DWELL|" norm(args)
|
||||||
|
next
|
||||||
|
}
|
||||||
|
|
||||||
|
if (line ~ /^ORIENT_SPINDLE\(/) {
|
||||||
|
args = args_of(line)
|
||||||
|
split(args, values, ",")
|
||||||
|
print "ORIENT_SPINDLE|" trim(values[1]) "|" norm(values[2]) "|" trim(values[3])
|
||||||
|
next
|
||||||
|
}
|
||||||
|
|
||||||
|
if (line ~ /^SPINDLE\.[0-9]+\.WAIT_ORIENT_COMPLETE\(/) {
|
||||||
|
spindle = line
|
||||||
|
sub(/^SPINDLE\./, "", spindle)
|
||||||
|
sub(/\.WAIT_ORIENT_COMPLETE.*/, "", spindle)
|
||||||
|
args = args_of(line)
|
||||||
|
print "WAIT_SPINDLE_ORIENT_COMPLETE|" spindle "|" norm(args)
|
||||||
|
next
|
||||||
|
}
|
||||||
|
|
||||||
if (line ~ /^STRAIGHT_(TRAVERSE|FEED)\(/) {
|
if (line ~ /^STRAIGHT_(TRAVERSE|FEED)\(/) {
|
||||||
op = line
|
op = line
|
||||||
sub(/\(.*/, "", op)
|
sub(/\(.*/, "", op)
|
||||||
@@ -140,11 +378,33 @@ normalize_upstream_rs274_output() {
|
|||||||
'
|
'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
filter_to_expected_event_keys() {
|
||||||
|
local expected_norm="$1"
|
||||||
|
|
||||||
|
awk '
|
||||||
|
NR == FNR {
|
||||||
|
key = $0
|
||||||
|
sub(/\|.*/, "", key)
|
||||||
|
keys[key] = 1
|
||||||
|
next
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
key = $0
|
||||||
|
sub(/\|.*/, "", key)
|
||||||
|
if (key in keys) {
|
||||||
|
print
|
||||||
|
}
|
||||||
|
}
|
||||||
|
' "$expected_norm" -
|
||||||
|
}
|
||||||
|
|
||||||
for name in "${FIXTURES[@]}"; do
|
for name in "${FIXTURES[@]}"; do
|
||||||
gcode_file="$GCODE_FIXTURE_DIR/$name.ngc"
|
gcode_file="$GCODE_FIXTURE_DIR/$name.ngc"
|
||||||
expected_file="$CANON_FIXTURE_DIR/$name.events"
|
expected_file="$CANON_FIXTURE_DIR/$name.events"
|
||||||
native_raw="$TMP_DIR/$name.rs274.raw"
|
native_raw="$TMP_DIR/$name.rs274.raw"
|
||||||
native_norm="$TMP_DIR/$name.rs274.normalized"
|
native_norm="$TMP_DIR/$name.rs274.normalized"
|
||||||
|
native_filtered="$TMP_DIR/$name.rs274.filtered"
|
||||||
expected_norm="$TMP_DIR/$name.expected.normalized"
|
expected_norm="$TMP_DIR/$name.expected.normalized"
|
||||||
|
|
||||||
if [[ ! -f "$gcode_file" ]]; then
|
if [[ ! -f "$gcode_file" ]]; then
|
||||||
@@ -170,14 +430,15 @@ for name in "${FIXTURES[@]}"; do
|
|||||||
|
|
||||||
normalize_upstream_rs274_output < "$native_raw" > "$native_norm"
|
normalize_upstream_rs274_output < "$native_raw" > "$native_norm"
|
||||||
normalize_standalone_events < "$expected_file" > "$expected_norm"
|
normalize_standalone_events < "$expected_file" > "$expected_norm"
|
||||||
|
filter_to_expected_event_keys "$expected_norm" < "$native_norm" > "$native_filtered"
|
||||||
|
|
||||||
if [[ ! -s "$native_norm" ]]; then
|
if [[ ! -s "$native_filtered" ]]; then
|
||||||
echo "no normalized upstream rs274 events for fixture: $name" >&2
|
echo "no normalized upstream rs274 events for fixture: $name" >&2
|
||||||
sed -n '1,160p' "$native_raw" >&2
|
sed -n '1,160p' "$native_raw" >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if ! diff -u "$expected_norm" "$native_norm"; then
|
if ! diff -u "$expected_norm" "$native_filtered"; then
|
||||||
echo "native LinuxCNC rs274 baseline mismatch for fixture: $name" >&2
|
echo "native LinuxCNC rs274 baseline mismatch for fixture: $name" >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|||||||
Reference in New Issue
Block a user