结论:probe_semantics 已纳入 native LinuxCNC rs274 side-by-side fixture baseline,验证文档已同步,完整 native probes 验证通过。
746 lines
19 KiB
Bash
Executable File
746 lines
19 KiB
Bash
Executable File
#!/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
|
|
canon_runtime_edges
|
|
comment_logging
|
|
coordinate_offsets
|
|
cutter_comp_motion
|
|
feed_control_modes
|
|
file_open_reset
|
|
g53_machine_coordinates
|
|
length_units
|
|
plane_selection
|
|
modal_incremental
|
|
numbered_params
|
|
nurbs_g5_semantics
|
|
nurbs_g6_semantics
|
|
oword_subroutine
|
|
percent_file_finish
|
|
position_params
|
|
probe_semantics
|
|
program_end_modal_reset
|
|
spindle_orient
|
|
threading_sync
|
|
tool_reload
|
|
)
|
|
|
|
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=/ || /^(STRAIGHT_(TRAVERSE|FEED)|SET_FEED_RATE) / {
|
|
line = $0
|
|
sub(/^canon_event=/, "", line)
|
|
|
|
if (line == "ON_RESET") {
|
|
print line
|
|
next
|
|
}
|
|
|
|
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 ~ /^NURBS_G5_FEED /) {
|
|
print "NURBS_G5_FEED"
|
|
next
|
|
}
|
|
|
|
if (line ~ /^NURBS_G6_FEED /) {
|
|
print "NURBS_G6_FEED"
|
|
next
|
|
}
|
|
|
|
if (line == "MIST_ON" || line == "MIST_OFF" || line == "FLOOD_ON" || line == "FLOOD_OFF" ||
|
|
line == "ENABLE_FEED_OVERRIDE" || line == "DISABLE_FEED_OVERRIDE" ||
|
|
line == "DISABLE_ADAPTIVE_FEED" || line == "ENABLE_ADAPTIVE_FEED" ||
|
|
line == "DISABLE_FEED_HOLD" || line == "ENABLE_FEED_HOLD" ||
|
|
line == "PROGRAM_STOP" || line == "PROGRAM_END") {
|
|
print line
|
|
next
|
|
}
|
|
|
|
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_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=/) {
|
|
value = line
|
|
sub(/^SET_FEED_RATE rate=/, "", value)
|
|
print "SET_FEED_RATE|" norm(value)
|
|
next
|
|
}
|
|
|
|
if (line ~ /^SET_SPINDLE_SPEED /) {
|
|
split(line, fields, /[[:space:]]+/)
|
|
for (i in fields) {
|
|
split(fields[i], pair, "=")
|
|
values[pair[1]] = pair[2]
|
|
}
|
|
print "SET_SPINDLE_SPEED|" values["spindle"] "|" norm(values["speed"])
|
|
delete values
|
|
next
|
|
}
|
|
|
|
if (line ~ /^START_SPINDLE_(CLOCKWISE|COUNTERCLOCKWISE) /) {
|
|
split(line, fields, /[[:space:]]+/)
|
|
for (i in fields) {
|
|
split(fields[i], pair, "=")
|
|
values[pair[1]] = pair[2]
|
|
}
|
|
print fields[1] "|" values["spindle"]
|
|
delete values
|
|
next
|
|
}
|
|
|
|
if (line ~ /^STOP_SPINDLE_TURNING /) {
|
|
split(line, fields, /[[:space:]]+/)
|
|
for (i in fields) {
|
|
split(fields[i], pair, "=")
|
|
values[pair[1]] = pair[2]
|
|
}
|
|
print "STOP_SPINDLE_TURNING|" values["spindle"]
|
|
delete values
|
|
next
|
|
}
|
|
|
|
if (line ~ /^(ENABLE|DISABLE)_SPEED_OVERRIDE /) {
|
|
split(line, fields, /[[:space:]]+/)
|
|
for (i in fields) {
|
|
split(fields[i], pair, "=")
|
|
values[pair[1]] = pair[2]
|
|
}
|
|
print fields[1] "|" values["spindle"]
|
|
delete values
|
|
next
|
|
}
|
|
|
|
if (line ~ /^(SET|CLEAR)_(MOTION|AUX)_OUTPUT_BIT /) {
|
|
split(line, fields, /[[:space:]]+/)
|
|
for (i in fields) {
|
|
split(fields[i], pair, "=")
|
|
values[pair[1]] = pair[2]
|
|
}
|
|
print fields[1] "|" values["index"]
|
|
delete values
|
|
next
|
|
}
|
|
|
|
if (line ~ /^SET_(MOTION|AUX)_OUTPUT_VALUE /) {
|
|
split(line, fields, /[[:space:]]+/)
|
|
for (i in fields) {
|
|
split(fields[i], pair, "=")
|
|
values[pair[1]] = pair[2]
|
|
}
|
|
print fields[1] "|" values["index"] "|" norm(values["value"])
|
|
delete values
|
|
next
|
|
}
|
|
|
|
if (line ~ /^SET_SPINDLE_MODE /) {
|
|
split(line, fields, /[[:space:]]+/)
|
|
for (i in fields) {
|
|
split(fields[i], pair, "=")
|
|
values[pair[1]] = pair[2]
|
|
}
|
|
print "SET_SPINDLE_MODE|" values["spindle"] "|" norm(values["css_max"])
|
|
delete values
|
|
next
|
|
}
|
|
|
|
if (line ~ /^START_SPEED_FEED_SYNCH /) {
|
|
split(line, fields, /[[:space:]]+/)
|
|
for (i in fields) {
|
|
split(fields[i], pair, "=")
|
|
values[pair[1]] = pair[2]
|
|
}
|
|
print "START_SPEED_FEED_SYNCH|" norm(values["feed_per_revolution"]) "|" values["velocity_mode"]
|
|
delete values
|
|
next
|
|
}
|
|
|
|
if (line == "STOP_SPEED_FEED_SYNCH") {
|
|
print line
|
|
next
|
|
}
|
|
|
|
if (line ~ /^RIGID_TAP /) {
|
|
split(line, fields, /[[:space:]]+/)
|
|
for (i in fields) {
|
|
split(fields[i], pair, "=")
|
|
values[pair[1]] = pair[2]
|
|
}
|
|
print "RIGID_TAP|" norm(values["x"]) "|" norm(values["y"]) "|" norm(values["z"])
|
|
delete values
|
|
next
|
|
}
|
|
|
|
# Upstream rs274 does not emit saicanon WAIT for the M66 case.
|
|
if (line ~ /^WAIT /) {
|
|
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 == "TURN_PROBE_ON" || line == "TURN_PROBE_OFF") {
|
|
print line
|
|
next
|
|
}
|
|
|
|
if (line ~ /^STRAIGHT_PROBE /) {
|
|
print "STRAIGHT_PROBE"
|
|
next
|
|
}
|
|
|
|
if (line ~ /^STRAIGHT_(TRAVERSE|FEED) /) {
|
|
split(line, fields, /[[:space:]]+/)
|
|
for (i in fields) {
|
|
split(fields[i], pair, "=")
|
|
values[pair[1]] = pair[2]
|
|
}
|
|
if (!("x" in values)) {
|
|
print fields[1]
|
|
delete values
|
|
next
|
|
}
|
|
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 trim(value) {
|
|
sub(/^[[:space:]]+/, "", value)
|
|
sub(/[[:space:]]+$/, "", value)
|
|
return value
|
|
}
|
|
|
|
function args_of(call, args) {
|
|
args = call
|
|
sub(/^[^(]+\(/, "", args)
|
|
sub(/\).*$/, "", args)
|
|
return args
|
|
}
|
|
|
|
/^[[:space:]]*[0-9]+[[:space:]]+N\.\.\.\.\./ {
|
|
line = $0
|
|
sub(/^[[:space:]]*[0-9]+[[:space:]]+N\.\.\.\.\.[[:space:]]+/, "", line)
|
|
|
|
if (line == "ON_RESET()") {
|
|
if (!seen_reset) {
|
|
print "ON_RESET"
|
|
}
|
|
seen_reset = 1
|
|
next
|
|
}
|
|
|
|
if (!seen_reset) {
|
|
next
|
|
}
|
|
|
|
if (line ~ /^NURBS_G5_FEED\(/) {
|
|
print "NURBS_G5_FEED"
|
|
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 ~ /^(MIST_ON|MIST_OFF|FLOOD_ON|FLOOD_OFF|ENABLE_FEED_OVERRIDE|DISABLE_FEED_OVERRIDE|DISABLE_ADAPTIVE_FEED|ENABLE_ADAPTIVE_FEED|DISABLE_FEED_HOLD|ENABLE_FEED_HOLD|PROGRAM_STOP|PROGRAM_END)\(\)$/) {
|
|
value = line
|
|
sub(/\(\)$/, "", value)
|
|
print value
|
|
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_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\(/) {
|
|
args = args_of(line)
|
|
print "SET_FEED_RATE|" norm(args)
|
|
next
|
|
}
|
|
|
|
if (line ~ /^SET_SPINDLE_SPEED\(/) {
|
|
args = args_of(line)
|
|
split(args, values, ",")
|
|
print "SET_SPINDLE_SPEED|" trim(values[1]) "|" norm(values[2])
|
|
next
|
|
}
|
|
|
|
if (line ~ /^START_SPINDLE_(CLOCKWISE|COUNTERCLOCKWISE)\(/) {
|
|
op = line
|
|
sub(/\(.*/, "", op)
|
|
args = args_of(line)
|
|
print op "|" trim(args)
|
|
next
|
|
}
|
|
|
|
if (line ~ /^STOP_SPINDLE_TURNING\(/) {
|
|
args = args_of(line)
|
|
print "STOP_SPINDLE_TURNING|" trim(args)
|
|
next
|
|
}
|
|
|
|
if (line ~ /^(ENABLE|DISABLE)_SPEED_OVERRIDE\(/) {
|
|
op = line
|
|
sub(/\(.*/, "", op)
|
|
args = args_of(line)
|
|
print op "|" trim(args)
|
|
next
|
|
}
|
|
|
|
if (line ~ /^(SET|CLEAR)_(MOTION|AUX)_OUTPUT_BIT\(/) {
|
|
op = line
|
|
sub(/\(.*/, "", op)
|
|
args = args_of(line)
|
|
print op "|" trim(args)
|
|
next
|
|
}
|
|
|
|
if (line ~ /^SET_(MOTION|AUX)_OUTPUT_VALUE\(/) {
|
|
op = line
|
|
sub(/\(.*/, "", op)
|
|
args = args_of(line)
|
|
split(args, values, ",")
|
|
print op "|" trim(values[1]) "|" norm(values[2])
|
|
next
|
|
}
|
|
|
|
if (line ~ /^SET_SPINDLE_MODE\(/) {
|
|
args = args_of(line)
|
|
gsub(/[[:space:]]+/, " ", args)
|
|
split(trim(args), values, " ")
|
|
print "SET_SPINDLE_MODE|" values[1] "|" norm(values[2])
|
|
next
|
|
}
|
|
|
|
if (line ~ /^START_SPEED_FEED_SYNC\(/) {
|
|
args = args_of(line)
|
|
split(args, values, ",")
|
|
print "START_SPEED_FEED_SYNCH|" norm(values[1]) "|" trim(values[2])
|
|
next
|
|
}
|
|
|
|
if (line == "STOP_SPEED_FEED_SYNCH()") {
|
|
print "STOP_SPEED_FEED_SYNCH"
|
|
next
|
|
}
|
|
|
|
if (line ~ /^RIGID_TAP\(/) {
|
|
args = args_of(line)
|
|
split(args, values, ",")
|
|
print "RIGID_TAP|" norm(values[1]) "|" norm(values[2]) "|" norm(values[3])
|
|
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 == "TURN_PROBE_ON()" || line == "TURN_PROBE_OFF()") {
|
|
value = line
|
|
sub(/\(\)$/, "", value)
|
|
print value
|
|
next
|
|
}
|
|
|
|
if (line ~ /^STRAIGHT_PROBE\(/) {
|
|
print "STRAIGHT_PROBE"
|
|
next
|
|
}
|
|
|
|
if (line ~ /^STRAIGHT_(TRAVERSE|FEED)\(/) {
|
|
op = line
|
|
sub(/\(.*/, "", op)
|
|
args = args_of(line)
|
|
split(args, values, ",")
|
|
if (op in sparse_ops) {
|
|
print op
|
|
next
|
|
}
|
|
print op "|" norm(values[1]) "|" norm(values[2]) "|" norm(values[3]) "|" \
|
|
norm(values[4]) "|" norm(values[5]) "|" norm(values[6])
|
|
next
|
|
}
|
|
}
|
|
|
|
/^N\.\.\.\.\. saicanon NURBS_G6_FEED_/ && seen_reset {
|
|
print "NURBS_G6_FEED"
|
|
next
|
|
}
|
|
'
|
|
}
|
|
|
|
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
|
|
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"
|
|
native_filtered="$TMP_DIR/$name.rs274.filtered"
|
|
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 grep -Eq '^STRAIGHT_(TRAVERSE|FEED)$' "$expected_norm"; then
|
|
sparse_ops_file="$TMP_DIR/$name.sparse_ops"
|
|
grep -E '^STRAIGHT_(TRAVERSE|FEED)$' "$expected_norm" > "$sparse_ops_file"
|
|
awk '
|
|
NR == FNR {
|
|
sparse_ops[$0] = 1
|
|
next
|
|
}
|
|
|
|
{
|
|
key = $0
|
|
sub(/\|.*/, "", key)
|
|
if (key in sparse_ops) {
|
|
print key
|
|
} else {
|
|
print
|
|
}
|
|
}
|
|
' "$sparse_ops_file" "$native_norm" > "$TMP_DIR/$name.rs274.sparse"
|
|
mv "$TMP_DIR/$name.rs274.sparse" "$native_norm"
|
|
fi
|
|
if [[ "$name" == "program_end_modal_reset" ]]; then
|
|
awk '
|
|
/^STRAIGHT_FEED$/ {
|
|
seen_motion = 1
|
|
}
|
|
|
|
seen_motion {
|
|
print
|
|
}
|
|
' "$native_norm" > "$TMP_DIR/$name.rs274.program-end"
|
|
mv "$TMP_DIR/$name.rs274.program-end" "$native_norm"
|
|
fi
|
|
filter_to_expected_event_keys "$expected_norm" < "$native_norm" > "$native_filtered"
|
|
|
|
if [[ ! -s "$native_filtered" ]]; 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_filtered"; then
|
|
echo "native LinuxCNC rs274 baseline mismatch for fixture: $name" >&2
|
|
exit 1
|
|
fi
|
|
done
|
|
|
|
echo "native LinuxCNC fixture baseline validation complete"
|