Files
wasm-simulator/test-linuxcnc-rs274-native.sh
2026-05-22 05:39:59 +08:00

236 lines
10 KiB
Bash
Executable File

#!/usr/bin/env bash
set -euo pipefail
cd "$(dirname "$0")"
linuxcnc_root=${LINUXCNC_ROOT:-../linuxcnc}
cxx=${CXX:-g++}
build_dir=${TMPDIR:-/tmp}/cnc_sim_native
mkdir -p "$build_dir"
var_file="$build_dir/rs274ngc.var"
base_var_file="$build_dir/rs274ngc-base.var"
cp "$linuxcnc_root/tests/halui/jogging/sim.var" "$base_var_file"
cp "$base_var_file" "$var_file"
"$cxx" -std=c++17 \
$(python3.13-config --includes 2>/dev/null || python3-config --includes) \
-I core/include \
-I core/src \
-I "$linuxcnc_root/src" \
-I "$linuxcnc_root/src/emc" \
-I "$linuxcnc_root/src/emc/nml_intf" \
-I "$linuxcnc_root/src/emc/rs274ngc" \
-I "$linuxcnc_root/src/emc/motion" \
-I "$linuxcnc_root/include" \
core/src/canon_event_sink.cpp \
core/src/linuxcnc_canon_bridge.cpp \
core/src/rtcp_kinematics.cpp \
core/src/simulator_gcode_controls.cpp \
core/tools/linuxcnc_rs274_dump.cpp \
-L "$linuxcnc_root/lib" \
-Wl,-rpath,"$linuxcnc_root/lib" \
-lrs274 \
-ltooldata \
-lpython3.13 \
-o "$build_dir/linuxcnc_rs274_dump"
CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_basic_motion.ngc >/tmp/cnc_sim_linuxcnc_basic_motion.json
CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/basic_mill.ngc >/tmp/cnc_sim_linuxcnc_basic_mill.json
CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_rtcp_controls.ngc >/tmp/cnc_sim_linuxcnc_rtcp_controls.json
CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_spindle_direction.ngc >/tmp/cnc_sim_linuxcnc_spindle_direction.json
CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_tool_number.ngc >/tmp/cnc_sim_linuxcnc_tool_number.json
CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_program_stops.ngc >/tmp/cnc_sim_linuxcnc_program_stops.json
CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_coolant.ngc >/tmp/cnc_sim_linuxcnc_coolant.json
CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_feed_modes.ngc >/tmp/cnc_sim_linuxcnc_feed_modes.json
CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_motion_modes.ngc >/tmp/cnc_sim_linuxcnc_motion_modes.json
CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_canned_cycle.ngc >/tmp/cnc_sim_linuxcnc_canned_cycle.json
CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_comments.ngc >/tmp/cnc_sim_linuxcnc_comments.json
CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_probe_no_error.ngc >/tmp/cnc_sim_linuxcnc_probe_no_error.json
cp "$base_var_file" "$var_file"
CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_coordinate_offsets.ngc >/tmp/cnc_sim_linuxcnc_coordinate_offsets.json
cp "$base_var_file" "$var_file"
CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_coordinate_l20.ngc >/tmp/cnc_sim_linuxcnc_coordinate_l20.json
python3 - <<'PY'
import json
from pathlib import Path
def check(path, required):
events = json.loads(Path(path).read_text())
types = [event["type"] for event in events]
missing = sorted(required - set(types))
if missing:
raise SystemExit(f"{path}: missing events: {', '.join(missing)}")
final_motion = [event for event in events if event["type"] in {"rapid", "linear-feed", "arc-feed"}][-1]
if final_motion["end"]["x"] != 0 or final_motion["end"]["y"] != 0:
raise SystemExit(f"{path}: unexpected final XY position")
return events
required_motion = {"set-units", "set-plane", "set-spindle", "rapid", "set-feed", "linear-feed", "arc-feed", "dwell", "program-end"}
check("/tmp/cnc_sim_linuxcnc_basic_motion.json", required_motion)
check("/tmp/cnc_sim_linuxcnc_basic_mill.json", required_motion | {"tool-change"})
controls = json.loads(Path("/tmp/cnc_sim_linuxcnc_rtcp_controls.json").read_text())
kin = [event for event in controls if event["type"] == "kinematics-switch"]
if [(event["reserved"], event["feed"]) for event in kin] != [(1, 1), (0, 0), (2, 1)]:
raise SystemExit("unexpected kinematics switch sequence")
rtcp = [event for event in controls if event["type"] == "rtcp-state"]
if [(event["line"], event["tool"], event["feed"]) for event in rtcp] != [(3, 0, 0), (4, 7, 1)]:
raise SystemExit("unexpected RTCP state sequence")
spindle = json.loads(Path("/tmp/cnc_sim_linuxcnc_spindle_direction.json").read_text())
spindle_states = [
(event["line"], event["spindle"], event["reserved"])
for event in spindle
if event["type"] == "set-spindle"
]
if (2, 1200, 1) not in spindle_states:
raise SystemExit("missing M3 clockwise spindle state")
if (3, 1200, 2) not in spindle_states:
raise SystemExit("missing M4 counterclockwise spindle state")
if (4, 0, 0) not in spindle_states:
raise SystemExit("missing M5 stopped spindle state")
tool_number = json.loads(Path("/tmp/cnc_sim_linuxcnc_tool_number.json").read_text())
if not any(
event["type"] == "tool-change" and
event["line"] == 2 and
event["tool"] == 1
for event in tool_number
):
raise SystemExit("missing M61 Q1 tool-number event line")
stops = json.loads(Path("/tmp/cnc_sim_linuxcnc_program_stops.json").read_text())
stop_states = [
(event["line"], event["reserved"])
for event in stops
if event["type"] == "program-end"
]
for expected in [(2, 1), (3, 2), (4, 3), (4, 1), (5, 0)]:
if expected not in stop_states:
raise SystemExit(f"missing program stop state {expected!r}")
coolant = json.loads(Path("/tmp/cnc_sim_linuxcnc_coolant.json").read_text())
coolant_states = [
(event["line"], event["reserved"])
for event in coolant
if event["type"] == "comment"
]
for expected in [(2, 11), (3, 21), (4, 10), (4, 20)]:
if expected not in coolant_states:
raise SystemExit(f"missing coolant state {expected!r}")
feed_modes = json.loads(Path("/tmp/cnc_sim_linuxcnc_feed_modes.json").read_text())
feed_mode_comments = [
(event["line"], event["reserved"])
for event in feed_modes
if event["type"] == "comment"
]
for expected in [(2, 93), (3, 94), (4, 95)]:
if expected not in feed_mode_comments:
raise SystemExit(f"missing feed mode comment state {expected!r}")
feed_mode_events = [
(event["line"], event["reserved"])
for event in feed_modes
if event["type"] == "set-feed"
]
for expected in [(3, 0), (4, 0)]:
if expected not in feed_mode_events:
raise SystemExit(f"missing feed mode event {expected!r}")
motion_modes = json.loads(Path("/tmp/cnc_sim_linuxcnc_motion_modes.json").read_text())
motion_mode_states = [
(event["line"], event["reserved"], event["feed"])
for event in motion_modes
if event["type"] == "comment"
]
for expected in [(2, 611, 0), (3, 612, 0), (4, 640, 0.05)]:
if expected not in motion_mode_states:
raise SystemExit(f"missing motion mode state {expected!r}")
cycle = json.loads(Path("/tmp/cnc_sim_linuxcnc_canned_cycle.json").read_text())
motions = [event for event in cycle if event["type"] in {"rapid", "linear-feed"}]
expected_cycle = [
("rapid", 0, 0, 5),
("rapid", 20, 0, 5),
("rapid", 20, 0, 3),
("linear-feed", 20, 0, -2),
("rapid", 20, 0, 3),
]
actual_cycle = [(event["type"], event["end"]["x"], event["end"]["y"], event["end"]["z"]) for event in motions]
if actual_cycle != expected_cycle:
raise SystemExit(f"unexpected G81/G80 expansion: {actual_cycle!r}")
comments = json.loads(Path("/tmp/cnc_sim_linuxcnc_comments.json").read_text())
if not any(event["type"] == "comment" and event["line"] == 2 for event in comments):
raise SystemExit("missing LinuxCNC comment line event")
probe = json.loads(Path("/tmp/cnc_sim_linuxcnc_probe_no_error.json").read_text())
if not any(
event["type"] == "probe" and
event["line"] == 4 and
event["feed"] == 100 and
event["start"]["z"] == 5 and
event["end"]["z"] == 0
for event in probe
):
raise SystemExit("missing G38.3 probe event")
if any(event["type"] == "linear-feed" and event["line"] == 4 for event in probe):
raise SystemExit("G38.3 probe should not be emitted as linear-feed")
coords = json.loads(Path("/tmp/cnc_sim_linuxcnc_coordinate_offsets.json").read_text())
g5x = [event for event in coords if event["type"] == "set-g5x-offset"]
g92 = [event for event in coords if event["type"] == "set-g92-offset"]
rot = [event for event in coords if event["type"] == "set-xy-rotation"]
if not any(
event["line"] == 2 and
event["tool"] == 1 and
event["start"]["x"] == 12.5 and
event["start"]["y"] == -3 and
event["start"]["z"] == 4
for event in g5x
):
raise SystemExit("missing G10 L2 G5X offset event")
if not any(event["feed"] == 30 for event in rot):
raise SystemExit("missing G10 L2 XY rotation event")
if not any(
event["line"] == 4 and
event["start"]["x"] == 0 and
event["start"]["y"] == 0 and
event["start"]["z"] == 0
for event in g92
):
raise SystemExit("missing G92.1 clear offset event")
if not any(event["type"] == "program-end" and event["line"] == 5 for event in coords):
raise SystemExit("missing coordinate program end line number")
l20 = json.loads(Path("/tmp/cnc_sim_linuxcnc_coordinate_l20.json").read_text())
if not any(
event["type"] == "set-g5x-offset" and
event["line"] == 4 and
event["tool"] == 2 and
event["start"]["x"] == 4 and
event["start"]["y"] == 4 and
event["start"]["z"] == 4
for event in l20
):
raise SystemExit("missing G10 L20 P2 offset event after G55 selection")
if not any(event["type"] == "program-end" and event["line"] == 5 for event in l20):
raise SystemExit("missing G10 L20 program end line number")
PY
echo "linuxcnc rs274 native smoke passed"
echo "dumped /tmp/cnc_sim_linuxcnc_basic_motion.json"
echo "dumped /tmp/cnc_sim_linuxcnc_basic_mill.json"
echo "dumped /tmp/cnc_sim_linuxcnc_rtcp_controls.json"
echo "dumped /tmp/cnc_sim_linuxcnc_spindle_direction.json"
echo "dumped /tmp/cnc_sim_linuxcnc_tool_number.json"
echo "dumped /tmp/cnc_sim_linuxcnc_program_stops.json"
echo "dumped /tmp/cnc_sim_linuxcnc_coolant.json"
echo "dumped /tmp/cnc_sim_linuxcnc_feed_modes.json"
echo "dumped /tmp/cnc_sim_linuxcnc_motion_modes.json"
echo "dumped /tmp/cnc_sim_linuxcnc_canned_cycle.json"
echo "dumped /tmp/cnc_sim_linuxcnc_comments.json"
echo "dumped /tmp/cnc_sim_linuxcnc_probe_no_error.json"
echo "dumped /tmp/cnc_sim_linuxcnc_coordinate_offsets.json"
echo "dumped /tmp/cnc_sim_linuxcnc_coordinate_l20.json"