对齐 LinuxCNC 解析器覆盖

This commit is contained in:
wangdequan
2026-05-23 17:28:41 +08:00
parent 7fe7ea6038
commit ed4e674d1e
40 changed files with 8881 additions and 313 deletions

View File

@@ -30,6 +30,27 @@ bool near(double lhs, double rhs) {
return std::fabs(lhs - rhs) < 0.000001;
}
bool saw_comment_state(const std::vector<CncSimEvent> &events,
int line,
int reserved,
int tool,
double feed,
int arc_turns = 0,
double dwell_seconds = 0.0) {
for (const auto &event : events) {
if (event.type == CNC_SIM_EVENT_COMMENT &&
event.line == line &&
event.reserved == reserved &&
event.tool == tool &&
near(event.feed, feed) &&
event.arc_turns == arc_turns &&
near(event.dwell_seconds, dwell_seconds)) {
return true;
}
}
return false;
}
} // namespace
int main() {
@@ -73,14 +94,30 @@ int main() {
bool saw_g5x_offset = false;
bool saw_xy_rotation = false;
bool saw_g92_clear = false;
bool saw_g92_suspend = false;
bool saw_g92_restore = false;
bool saw_g92_restore_after_clear = false;
bool saw_g52_initial = false;
bool saw_g52_sticky_axis = false;
bool saw_g52_suspend = false;
bool saw_g52_restore = false;
bool saw_g52_end_line = false;
bool saw_coordinate_end_line = false;
bool saw_l20_g55_offset = false;
bool saw_l20_end_line = false;
bool saw_g10_p0_g55 = false;
bool saw_g10_p0_end_line = false;
bool saw_probe = false;
bool saw_probe_error_variant = false;
bool saw_probe_no_error_variant = false;
bool saw_probe_clear_error_variant = false;
bool saw_probe_clear_no_error_variant = false;
bool saw_probe_as_feed = false;
bool saw_spindle_cw = false;
bool saw_spindle_ccw = false;
bool saw_spindle_stop = false;
bool saw_spindle_orient = false;
bool saw_spindle_orient_wait = false;
bool saw_comment_line = false;
bool saw_tool_number_line = false;
bool saw_program_stop = false;
@@ -96,9 +133,33 @@ int main() {
bool saw_g95_mode = false;
bool saw_g94_feed_mode = false;
bool saw_g95_feed_mode = false;
bool saw_g96_mode = false;
bool saw_g97_mode = false;
bool saw_g33_sync_start = false;
bool saw_g33_sync_stop = false;
bool saw_g33_thread_line = false;
bool saw_g331_sync_start = false;
bool saw_g331_sync_stop = false;
bool saw_g331_rigid_tap_line = false;
bool saw_g61_mode = false;
bool saw_g611_mode = false;
bool saw_g64_mode = false;
bool saw_g18_arc = false;
bool saw_g19_arc = false;
bool saw_g911_arc = false;
bool saw_g901_arc = false;
bool saw_g911_restored_arc = false;
bool saw_g28_waypoint = false;
bool saw_g28_home_axis = false;
bool saw_g30_waypoint = false;
bool saw_g30_home_all_axes = false;
bool saw_g53_rapid = false;
bool saw_g53_modal_rapid = false;
bool saw_g53_feed = false;
bool saw_g431_tool_length = false;
bool saw_g432_tool_length = false;
bool saw_g432_h_tool_length = false;
bool saw_g49_dynamic_tool_length_clear = false;
bool saw_tool_length = false;
bool saw_tool_length_clear = false;
bool saw_cutter_left_first = false;
@@ -159,6 +220,229 @@ int main() {
ok &= expect(saw_g49, "expected LinuxCNC G49 RTCP off state");
ok &= expect(saw_g434, "expected LinuxCNC G43.4 RTCP on state with H code");
const char arc_planes_program[] =
"G21 G90 G17\n"
"G0 X0 Y0 Z0\n"
"F100\n"
"G18\n"
"G2 X10 Z0 I5 K0\n"
"G0 X0 Y0 Z0\n"
"G19\n"
"G3 Y10 Z0 J5 K0\n"
"M30\n";
events.clear();
ok &= expect(cnc_sim_parse_program(sim, arc_planes_program, sizeof(arc_planes_program) - 1) == 0,
cnc_sim_last_error(sim));
for (const auto &event : events) {
saw_g18_arc = saw_g18_arc ||
(event.type == CNC_SIM_EVENT_ARC_FEED &&
event.line == 5 &&
event.plane == 18 &&
event.start.x == 0.0 &&
event.start.z == 0.0 &&
event.end.x == 10.0 &&
event.end.z == 0.0 &&
event.center.x == 5.0 &&
event.center.z == 0.0 &&
event.arc_turns == -1);
saw_g19_arc = saw_g19_arc ||
(event.type == CNC_SIM_EVENT_ARC_FEED &&
event.line == 8 &&
event.plane == 19 &&
event.start.y == 0.0 &&
event.start.z == 0.0 &&
event.end.y == 10.0 &&
event.end.z == 0.0 &&
event.center.y == 5.0 &&
event.center.z == 0.0 &&
event.arc_turns == 1);
}
ok &= expect(saw_g18_arc, "expected LinuxCNC G18 XZ arc center mapping");
ok &= expect(saw_g19_arc, "expected LinuxCNC G19 YZ arc center mapping");
const char arc_distance_program[] =
"G21 G90 G17\n"
"G0 X0 Y0 Z0\n"
"F100\n"
"G91.1\n"
"G3 X10 Y0 I5 J0\n"
"G90.1\n"
"G3 X20 Y0 I15 J0\n"
"G91.1\n"
"G3 X30 Y0 I5 J0\n"
"M30\n";
events.clear();
ok &= expect(cnc_sim_parse_program(sim, arc_distance_program, sizeof(arc_distance_program) - 1) == 0,
cnc_sim_last_error(sim));
for (const auto &event : events) {
saw_g911_arc = saw_g911_arc ||
(event.type == CNC_SIM_EVENT_ARC_FEED &&
event.line == 5 &&
event.center.x == 5.0 &&
event.center.y == 0.0);
saw_g901_arc = saw_g901_arc ||
(event.type == CNC_SIM_EVENT_ARC_FEED &&
event.line == 7 &&
event.center.x == 15.0 &&
event.center.y == 0.0);
saw_g911_restored_arc = saw_g911_restored_arc ||
(event.type == CNC_SIM_EVENT_ARC_FEED &&
event.line == 9 &&
event.center.x == 25.0 &&
event.center.y == 0.0);
}
ok &= expect(saw_g911_arc, "expected LinuxCNC G91.1 incremental IJK arc center");
ok &= expect(saw_g901_arc, "expected LinuxCNC G90.1 absolute IJK arc center");
ok &= expect(saw_g911_restored_arc, "expected LinuxCNC G91.1 restored incremental IJK arc center");
const char predefined_position_program[] =
"G21 G90 G17\n"
"G0 X1 Y2 Z3\n"
"G28.1\n"
"G0 X10 Y20 Z30\n"
"G28 Z5\n"
"G0 X4 Y5 Z6\n"
"G30.1\n"
"G0 X40 Y50 Z60\n"
"G30\n"
"M30\n";
events.clear();
ok &= expect(cnc_sim_parse_program(sim,
predefined_position_program,
sizeof(predefined_position_program) - 1) == 0,
cnc_sim_last_error(sim));
for (const auto &event : events) {
saw_g28_waypoint = saw_g28_waypoint ||
(event.type == CNC_SIM_EVENT_RAPID &&
event.line == 5 &&
event.start.x == 10.0 &&
event.start.y == 20.0 &&
event.start.z == 30.0 &&
event.end.x == 10.0 &&
event.end.y == 20.0 &&
event.end.z == 5.0);
saw_g28_home_axis = saw_g28_home_axis ||
(event.type == CNC_SIM_EVENT_RAPID &&
event.line == 5 &&
event.start.x == 10.0 &&
event.start.y == 20.0 &&
event.start.z == 5.0 &&
event.end.x == 10.0 &&
event.end.y == 20.0 &&
event.end.z == 3.0);
saw_g30_home_all_axes = saw_g30_home_all_axes ||
(event.type == CNC_SIM_EVENT_RAPID &&
event.line == 9 &&
event.start.x == 40.0 &&
event.start.y == 50.0 &&
event.start.z == 60.0 &&
event.end.x == 4.0 &&
event.end.y == 5.0 &&
event.end.z == 6.0);
saw_g30_waypoint = saw_g30_waypoint ||
(event.type == CNC_SIM_EVENT_RAPID &&
event.line == 9 &&
event.start.x == 40.0 &&
event.start.y == 50.0 &&
event.start.z == 60.0 &&
event.end.x == 40.0 &&
event.end.y == 50.0 &&
event.end.z == 60.0);
}
ok &= expect(saw_g28_waypoint, "expected LinuxCNC G28 waypoint rapid");
ok &= expect(saw_g28_home_axis, "expected LinuxCNC G28 selected-axis home rapid");
ok &= expect(saw_g30_waypoint, "expected LinuxCNC G30 waypoint rapid");
ok &= expect(saw_g30_home_all_axes, "expected LinuxCNC G30 all-axis home rapid");
const char machine_coordinate_program[] =
"G21 G90 G17\n"
"G0 X5 Y6 Z7\n"
"G53 G0 X0 Z1\n"
"G53 X2\n"
"G1 F100\n"
"G53 G1 Y3\n"
"M30\n";
events.clear();
ok &= expect(cnc_sim_parse_program(sim,
machine_coordinate_program,
sizeof(machine_coordinate_program) - 1) == 0,
cnc_sim_last_error(sim));
for (const auto &event : events) {
saw_g53_rapid = saw_g53_rapid ||
(event.type == CNC_SIM_EVENT_RAPID &&
event.line == 3 &&
event.start.x == 5.0 &&
event.start.y == 6.0 &&
event.start.z == 7.0 &&
event.end.x == 0.0 &&
event.end.y == 6.0 &&
event.end.z == 1.0);
saw_g53_modal_rapid = saw_g53_modal_rapid ||
(event.type == CNC_SIM_EVENT_RAPID &&
event.line == 4 &&
event.start.x == 0.0 &&
event.start.y == 6.0 &&
event.start.z == 1.0 &&
event.end.x == 2.0 &&
event.end.y == 6.0 &&
event.end.z == 1.0);
saw_g53_feed = saw_g53_feed ||
(event.type == CNC_SIM_EVENT_LINEAR_FEED &&
event.line == 6 &&
event.start.x == 2.0 &&
event.start.y == 6.0 &&
event.start.z == 1.0 &&
event.end.x == 2.0 &&
event.end.y == 3.0 &&
event.end.z == 1.0);
}
ok &= expect(saw_g53_rapid, "expected LinuxCNC G53 explicit rapid move");
ok &= expect(saw_g53_modal_rapid, "expected LinuxCNC G53 modal rapid move");
ok &= expect(saw_g53_feed, "expected LinuxCNC G53 feed move");
const char dynamic_tool_length_program[] =
"G21 G90 G17\n"
"G43.1 X1 Z2\n"
"G43.2 X0.25 Z0.5\n"
"G43.2 H1\n"
"G49\n"
"M30\n";
events.clear();
ok &= expect(cnc_sim_parse_program(sim,
dynamic_tool_length_program,
sizeof(dynamic_tool_length_program) - 1) == 0,
cnc_sim_last_error(sim));
for (const auto &event : events) {
saw_g431_tool_length = saw_g431_tool_length ||
(event.type == CNC_SIM_EVENT_COMMENT &&
event.line == 2 &&
event.reserved == 430 &&
event.start.x == 1.0 &&
event.start.z == 2.0);
saw_g432_tool_length = saw_g432_tool_length ||
(event.type == CNC_SIM_EVENT_COMMENT &&
event.line == 3 &&
event.reserved == 430 &&
event.start.x == 1.25 &&
event.start.z == 2.5);
saw_g49_dynamic_tool_length_clear = saw_g49_dynamic_tool_length_clear ||
(event.type == CNC_SIM_EVENT_COMMENT &&
event.line == 5 &&
event.reserved == 430 &&
event.start.x == 0.0 &&
event.start.z == 0.0);
saw_g432_h_tool_length = saw_g432_h_tool_length ||
(event.type == CNC_SIM_EVENT_COMMENT &&
event.line == 4 &&
event.reserved == 430 &&
event.start.x == 1.25 &&
event.start.z == 15.0);
}
ok &= expect(saw_g431_tool_length, "expected LinuxCNC G43.1 dynamic tool length event");
ok &= expect(saw_g432_tool_length, "expected LinuxCNC G43.2 additive tool length event");
ok &= expect(saw_g432_h_tool_length, "expected LinuxCNC G43.2 H tool-table additive event");
ok &= expect(saw_g49_dynamic_tool_length_clear, "expected LinuxCNC G49 dynamic tool length clear event");
const char spindle_program[] =
"G21 G90 G17\n"
"S1200 M3\n"
@@ -189,6 +473,249 @@ int main() {
ok &= expect(saw_spindle_ccw, "expected LinuxCNC M4 counterclockwise spindle state");
ok &= expect(saw_spindle_stop, "expected LinuxCNC M5 stopped spindle state");
const char spindle_mode_program[] =
"G21 G90 G17\n"
"G97 S1000\n"
"G96 S120 D2500\n"
"G97 S900\n"
"M30\n";
events.clear();
ok &= expect(cnc_sim_parse_program(sim, spindle_mode_program, sizeof(spindle_mode_program) - 1) == 0,
cnc_sim_last_error(sim));
for (const auto &event : events) {
saw_g97_mode = saw_g97_mode ||
(event.type == CNC_SIM_EVENT_COMMENT &&
event.line == 2 &&
event.reserved == 970 &&
event.feed == 0.0);
saw_g96_mode = saw_g96_mode ||
(event.type == CNC_SIM_EVENT_COMMENT &&
event.line == 3 &&
event.reserved == 960 &&
event.feed == 2500.0);
}
ok &= expect(saw_g97_mode, "expected LinuxCNC G97 constant-RPM spindle mode state");
ok &= expect(saw_g96_mode, "expected LinuxCNC G96 CSS spindle mode state");
const char spindle_orient_program[] =
"G21 G90 G17\n"
"M19 R45 P1 Q2\n"
"M30\n";
events.clear();
ok &= expect(cnc_sim_parse_program(sim, spindle_orient_program, sizeof(spindle_orient_program) - 1) == 0,
cnc_sim_last_error(sim));
for (const auto &event : events) {
saw_spindle_orient = saw_spindle_orient ||
(event.type == CNC_SIM_EVENT_COMMENT &&
event.line == 2 &&
event.reserved == 1901 &&
event.tool == 0 &&
event.feed == 45.0 &&
event.arc_turns == 1);
saw_spindle_orient_wait = saw_spindle_orient_wait ||
(event.type == CNC_SIM_EVENT_COMMENT &&
event.line == 2 &&
event.reserved == 1902 &&
event.tool == 0 &&
event.dwell_seconds == 2.0);
}
ok &= expect(saw_spindle_orient, "expected LinuxCNC M19 spindle orient state");
ok &= expect(saw_spindle_orient_wait, "expected LinuxCNC M19 spindle orient wait state");
const char io_controls_program[] =
"G21 G90 G17\n"
"M62 P1\n"
"M63 P1\n"
"M64 P2\n"
"M65 P2\n"
"M66 P0 L3 Q5\n"
"M66 E1 L0\n"
"M67 E0 Q1.25\n"
"M68 E1 Q2.5\n"
"M30\n";
events.clear();
ok &= expect(cnc_sim_parse_program(sim, io_controls_program, sizeof(io_controls_program) - 1) == 0,
cnc_sim_last_error(sim));
bool saw_m62 = false;
bool saw_m63 = false;
bool saw_m64 = false;
bool saw_m65 = false;
bool saw_m66_digital = false;
bool saw_m66_analog = false;
bool saw_m67 = false;
bool saw_m68 = false;
for (const auto &event : events) {
saw_m62 = saw_m62 || (event.type == CNC_SIM_EVENT_COMMENT &&
event.line == 2 &&
event.reserved == 62 &&
event.tool == 1 &&
event.feed == 1.0);
saw_m63 = saw_m63 || (event.type == CNC_SIM_EVENT_COMMENT &&
event.line == 3 &&
event.reserved == 63 &&
event.tool == 1 &&
event.feed == 0.0);
saw_m64 = saw_m64 || (event.type == CNC_SIM_EVENT_COMMENT &&
event.line == 4 &&
event.reserved == 64 &&
event.tool == 2 &&
event.feed == 1.0);
saw_m65 = saw_m65 || (event.type == CNC_SIM_EVENT_COMMENT &&
event.line == 5 &&
event.reserved == 65 &&
event.tool == 2 &&
event.feed == 0.0);
saw_m66_digital = saw_m66_digital || (event.type == CNC_SIM_EVENT_COMMENT &&
event.line == 6 &&
event.reserved == 66 &&
event.tool == 0 &&
event.arc_turns == 1 &&
event.feed == 3.0 &&
event.dwell_seconds == 5.0);
saw_m66_analog = saw_m66_analog || (event.type == CNC_SIM_EVENT_COMMENT &&
event.line == 7 &&
event.reserved == 66 &&
event.tool == 1 &&
event.arc_turns == 0 &&
event.feed == 0.0 &&
event.dwell_seconds == 0.0);
saw_m67 = saw_m67 || (event.type == CNC_SIM_EVENT_COMMENT &&
event.line == 8 &&
event.reserved == 67 &&
event.tool == 0 &&
event.feed == 1.25);
saw_m68 = saw_m68 || (event.type == CNC_SIM_EVENT_COMMENT &&
event.line == 9 &&
event.reserved == 68 &&
event.tool == 1 &&
event.feed == 2.5);
}
ok &= expect(saw_m62, "expected LinuxCNC M62 motion digital output on state");
ok &= expect(saw_m63, "expected LinuxCNC M63 motion digital output off state");
ok &= expect(saw_m64, "expected LinuxCNC M64 auxiliary digital output on state");
ok &= expect(saw_m65, "expected LinuxCNC M65 auxiliary digital output off state");
ok &= expect(saw_m66_digital, "expected LinuxCNC M66 digital input wait state");
ok &= expect(saw_m66_analog, "expected LinuxCNC M66 analog input wait state");
ok &= expect(saw_m67, "expected LinuxCNC M67 motion analog output state");
ok &= expect(saw_m68, "expected LinuxCNC M68 auxiliary analog output state");
const char override_controls_program[] =
"G21 G90 G17\n"
"M48\n"
"M49\n"
"M50 P1\n"
"M50 P0\n"
"M51 P1\n"
"M51 P0\n"
"M52 P1\n"
"M52 P0\n"
"M53 P1\n"
"M53 P0\n"
"M30\n";
events.clear();
ok &= expect(cnc_sim_parse_program(sim, override_controls_program, sizeof(override_controls_program) - 1) == 0,
cnc_sim_last_error(sim));
ok &= expect(saw_comment_state(events, 2, 50, 0, 1.0), "expected LinuxCNC M48 feed override enable state");
ok &= expect(saw_comment_state(events, 2, 51, 0, 1.0), "expected LinuxCNC M48 speed override enable state");
ok &= expect(saw_comment_state(events, 3, 50, 0, 0.0), "expected LinuxCNC M49 feed override disable state");
ok &= expect(saw_comment_state(events, 3, 51, 0, 0.0), "expected LinuxCNC M49 speed override disable state");
ok &= expect(saw_comment_state(events, 4, 50, 0, 1.0), "expected LinuxCNC M50 feed override enable state");
ok &= expect(saw_comment_state(events, 5, 50, 0, 0.0), "expected LinuxCNC M50 feed override disable state");
ok &= expect(saw_comment_state(events, 6, 51, 0, 1.0), "expected LinuxCNC M51 speed override enable state");
ok &= expect(saw_comment_state(events, 7, 51, 0, 0.0), "expected LinuxCNC M51 speed override disable state");
ok &= expect(saw_comment_state(events, 8, 52, 0, 1.0), "expected LinuxCNC M52 adaptive feed enable state");
ok &= expect(saw_comment_state(events, 9, 52, 0, 0.0), "expected LinuxCNC M52 adaptive feed disable state");
ok &= expect(saw_comment_state(events, 10, 53, 0, 1.0), "expected LinuxCNC M53 feed hold enable state");
ok &= expect(saw_comment_state(events, 11, 53, 0, 0.0), "expected LinuxCNC M53 feed hold disable state");
const char modal_state_program[] =
"G21 G90 G17\n"
"G0 X0 Y0 Z0\n"
"M70\n"
"G91 G18 G20\n"
"G0 X1 Z1\n"
"M72\n"
"G0 X2 Y0 Z2\n"
"F100 G2 X4 Y0 I1 J0\n"
"M30\n";
events.clear();
ok &= expect(cnc_sim_parse_program(sim, modal_state_program, sizeof(modal_state_program) - 1) == 0,
cnc_sim_last_error(sim));
bool saw_modal_restored_absolute_mm = false;
bool saw_modal_restored_xy_arc = false;
for (const auto &event : events) {
saw_modal_restored_absolute_mm = saw_modal_restored_absolute_mm ||
(event.type == CNC_SIM_EVENT_RAPID &&
event.line == 7 &&
near(event.end.x, 2.0) &&
near(event.end.y, 0.0) &&
near(event.end.z, 2.0));
saw_modal_restored_xy_arc = saw_modal_restored_xy_arc ||
(event.type == CNC_SIM_EVENT_ARC_FEED &&
event.line == 8 &&
event.plane == 17 &&
near(event.end.x, 4.0) &&
near(event.end.y, 0.0));
}
ok &= expect(saw_modal_restored_absolute_mm, "expected LinuxCNC M72 restored absolute millimeter move");
ok &= expect(saw_modal_restored_xy_arc, "expected LinuxCNC M72 restored XY plane arc");
const char modal_invalidate_program[] =
"G21 G90 G17\n"
"M70\n"
"M71\n"
"M72\n"
"M30\n";
events.clear();
ok &= expect(cnc_sim_parse_program(sim, modal_invalidate_program, sizeof(modal_invalidate_program) - 1) != 0,
"expected LinuxCNC M71 invalidated modal state to reject M72 restore");
const char threading_sync_program[] =
"G21 G90 G17\n"
"S500 M3\n"
"G0 Z5\n"
"G33 Z0 K1\n"
"G0 Z5\n"
"G33.1 Z0 K1\n"
"M30\n";
events.clear();
ok &= expect(cnc_sim_parse_program(sim, threading_sync_program, sizeof(threading_sync_program) - 1) == 0,
cnc_sim_last_error(sim));
for (const auto &event : events) {
saw_g33_sync_start = saw_g33_sync_start ||
(event.type == CNC_SIM_EVENT_COMMENT &&
event.line == 4 &&
event.reserved == 3301 &&
event.feed == 1.0);
saw_g33_sync_stop = saw_g33_sync_stop ||
(event.type == CNC_SIM_EVENT_COMMENT &&
event.line == 4 &&
event.reserved == 3300);
saw_g33_thread_line = saw_g33_thread_line ||
(event.type == CNC_SIM_EVENT_LINEAR_FEED &&
event.line == 4 &&
event.end.z == 0.0);
saw_g331_sync_start = saw_g331_sync_start ||
(event.type == CNC_SIM_EVENT_COMMENT &&
event.line == 6 &&
event.reserved == 3301 &&
event.feed == 1.0);
saw_g331_sync_stop = saw_g331_sync_stop ||
(event.type == CNC_SIM_EVENT_COMMENT &&
event.line == 6 &&
event.reserved == 3300);
saw_g331_rigid_tap_line = saw_g331_rigid_tap_line ||
(event.type == CNC_SIM_EVENT_LINEAR_FEED &&
event.line == 6 &&
event.end.z == 0.0);
}
ok &= expect(saw_g33_sync_start, "expected LinuxCNC G33 speed-feed sync start");
ok &= expect(saw_g33_sync_stop, "expected LinuxCNC G33 speed-feed sync stop");
ok &= expect(saw_g33_thread_line, "expected LinuxCNC G33 threading feed line");
ok &= expect(saw_g331_sync_start, "expected LinuxCNC G33.1 speed-feed sync start");
ok &= expect(saw_g331_sync_stop, "expected LinuxCNC G33.1 speed-feed sync stop");
ok &= expect(saw_g331_rigid_tap_line, "expected LinuxCNC G33.1 rigid tap line number");
const char tool_number_program[] =
"G21 G90 G17\n"
"M61 Q1\n"
@@ -297,7 +824,7 @@ int main() {
saw_g95_feed_mode = saw_g95_feed_mode ||
(event.type == CNC_SIM_EVENT_SET_FEED &&
event.line == 4 &&
event.reserved == 0);
event.reserved == 1);
}
ok &= expect(saw_g93_mode, "expected LinuxCNC G93 feed mode state");
ok &= expect(saw_g94_mode, "expected LinuxCNC G94 feed mode state");
@@ -464,7 +991,13 @@ int main() {
"G21 G90 G17\n"
"G0 X0 Y0 Z5\n"
"F100\n"
"G38.3 Z0\n"
"G38.2 Z4\n"
"G0 Z5\n"
"G38.3 Z3\n"
"G0 Z5\n"
"G38.4 Z2\n"
"G0 Z5\n"
"G38.5 Z1\n"
"M30\n";
events.clear();
ok &= expect(cnc_sim_parse_program(sim, probe_program, sizeof(probe_program) - 1) == 0,
@@ -472,16 +1005,47 @@ int main() {
for (const auto &event : events) {
saw_probe = saw_probe ||
(event.type == CNC_SIM_EVENT_PROBE &&
event.line == 4 &&
event.line == 6 &&
event.feed == 100.0 &&
event.start.z == 5.0 &&
event.end.z == 0.0);
event.end.z == 3.0);
saw_probe_error_variant = saw_probe_error_variant ||
(event.type == CNC_SIM_EVENT_PROBE &&
event.line == 4 &&
event.reserved == 0 &&
event.start.z == 5.0 &&
event.end.z == 4.0);
saw_probe_no_error_variant = saw_probe_no_error_variant ||
(event.type == CNC_SIM_EVENT_PROBE &&
event.line == 6 &&
event.reserved == 1 &&
event.start.z == 5.0 &&
event.end.z == 3.0);
saw_probe_clear_error_variant = saw_probe_clear_error_variant ||
(event.type == CNC_SIM_EVENT_PROBE &&
event.line == 8 &&
event.reserved == 2 &&
event.start.z == 5.0 &&
event.end.z == 2.0);
saw_probe_clear_no_error_variant = saw_probe_clear_no_error_variant ||
(event.type == CNC_SIM_EVENT_PROBE &&
event.line == 10 &&
event.reserved == 3 &&
event.start.z == 5.0 &&
event.end.z == 1.0);
saw_probe_as_feed = saw_probe_as_feed ||
(event.type == CNC_SIM_EVENT_LINEAR_FEED &&
event.line == 4);
(event.line == 4 ||
event.line == 6 ||
event.line == 8 ||
event.line == 10));
}
ok &= expect(saw_probe, "expected LinuxCNC G38.3 probe event");
ok &= expect(!saw_probe_as_feed, "expected LinuxCNC G38.3 to avoid linear-feed event");
ok &= expect(saw_probe_error_variant, "expected LinuxCNC G38.2 probe event");
ok &= expect(saw_probe_no_error_variant, "expected LinuxCNC G38.3 probe event with probe type");
ok &= expect(saw_probe_clear_error_variant, "expected LinuxCNC G38.4 probe-clear event");
ok &= expect(saw_probe_clear_no_error_variant, "expected LinuxCNC G38.5 probe-clear no-error event");
ok &= expect(!saw_probe_as_feed, "expected LinuxCNC G38 probe moves to avoid linear-feed events");
const char l20_program[] =
"G21 G90 G17\n"
@@ -507,11 +1071,37 @@ int main() {
ok &= expect(saw_l20_g55_offset, "expected LinuxCNC G10 L20 P2 offset after G55 selection");
ok &= expect(saw_l20_end_line, "expected LinuxCNC G10 L20 program end line number");
const char p0_coordinate_program[] =
"G21 G90 G17\n"
"G55\n"
"G10 L2 P0 X7 Y8 Z9\n"
"M30\n";
events.clear();
ok &= expect(cnc_sim_parse_program(sim, p0_coordinate_program, sizeof(p0_coordinate_program) - 1) == 0,
cnc_sim_last_error(sim));
for (const auto &event : events) {
saw_g10_p0_g55 = saw_g10_p0_g55 ||
(event.type == CNC_SIM_EVENT_SET_G5X_OFFSET &&
event.line == 3 &&
event.tool == 2 &&
event.start.x == 7.0 &&
event.start.y == 8.0 &&
event.start.z == 9.0);
saw_g10_p0_end_line = saw_g10_p0_end_line ||
(event.type == CNC_SIM_EVENT_PROGRAM_END &&
event.line == 4);
}
ok &= expect(saw_g10_p0_g55, "expected LinuxCNC G10 L2 P0 to target active G55");
ok &= expect(saw_g10_p0_end_line, "expected LinuxCNC G10 P0 program end line number");
const char coordinate_program[] =
"G21 G90 G17\n"
"G10 L2 P1 X12.5 Y-3 Z4 R30\n"
"G92 X1 Y2 Z3\n"
"G92.2\n"
"G92.3\n"
"G92.1\n"
"G92.3\n"
"M30\n";
events.clear();
ok &= expect(cnc_sim_parse_program(sim, coordinate_program, sizeof(coordinate_program) - 1) == 0,
@@ -530,19 +1120,86 @@ int main() {
event.feed == 30.0);
saw_g92_clear = saw_g92_clear ||
(event.type == CNC_SIM_EVENT_SET_G92_OFFSET &&
event.line == 4 &&
event.line == 6 &&
event.start.x == 0.0 &&
event.start.y == 0.0 &&
event.start.z == 0.0);
saw_g92_suspend = saw_g92_suspend ||
(event.type == CNC_SIM_EVENT_SET_G92_OFFSET &&
event.line == 4 &&
event.start.x == 0.0 &&
event.start.y == 0.0 &&
event.start.z == 0.0);
saw_g92_restore = saw_g92_restore ||
(event.type == CNC_SIM_EVENT_SET_G92_OFFSET &&
event.line == 5 &&
near(event.start.x, -10.325317547305483) &&
near(event.start.y, 6.848076211353316) &&
event.start.z == -7.0);
saw_g92_restore_after_clear = saw_g92_restore_after_clear ||
(event.type == CNC_SIM_EVENT_SET_G92_OFFSET &&
event.line == 7 &&
event.start.x == 0.0 &&
event.start.y == 0.0 &&
event.start.z == 0.0);
saw_coordinate_end_line = saw_coordinate_end_line ||
(event.type == CNC_SIM_EVENT_PROGRAM_END &&
event.line == 5);
event.line == 8);
}
ok &= expect(saw_g5x_offset, "expected LinuxCNC G10 L2 G5X offset event");
ok &= expect(saw_xy_rotation, "expected LinuxCNC G10 L2 XY rotation event");
ok &= expect(saw_g92_suspend, "expected LinuxCNC G92.2 suspend offset event");
ok &= expect(saw_g92_restore, "expected LinuxCNC G92.3 restore suspended rotated-offset event");
ok &= expect(saw_g92_clear, "expected LinuxCNC G92.1 clear offset event");
ok &= expect(saw_g92_restore_after_clear, "expected LinuxCNC G92.3 to restore zero after G92.1");
ok &= expect(saw_coordinate_end_line, "expected LinuxCNC coordinate program end line number");
const char g52_program[] =
"G21 G90 G17\n"
"G52 X1 Y2\n"
"G52 Y3\n"
"G92.2\n"
"G92.3\n"
"G92.1\n"
"M30\n";
events.clear();
ok &= expect(cnc_sim_parse_program(sim, g52_program, sizeof(g52_program) - 1) == 0,
cnc_sim_last_error(sim));
for (const auto &event : events) {
saw_g52_initial = saw_g52_initial ||
(event.type == CNC_SIM_EVENT_SET_G92_OFFSET &&
event.line == 2 &&
event.start.x == 1.0 &&
event.start.y == 2.0 &&
event.start.z == 0.0);
saw_g52_sticky_axis = saw_g52_sticky_axis ||
(event.type == CNC_SIM_EVENT_SET_G92_OFFSET &&
event.line == 3 &&
event.start.x == 1.0 &&
event.start.y == 3.0 &&
event.start.z == 0.0);
saw_g52_suspend = saw_g52_suspend ||
(event.type == CNC_SIM_EVENT_SET_G92_OFFSET &&
event.line == 4 &&
event.start.x == 0.0 &&
event.start.y == 0.0 &&
event.start.z == 0.0);
saw_g52_restore = saw_g52_restore ||
(event.type == CNC_SIM_EVENT_SET_G92_OFFSET &&
event.line == 5 &&
event.start.x == 1.0 &&
event.start.y == 3.0 &&
event.start.z == 0.0);
saw_g52_end_line = saw_g52_end_line ||
(event.type == CNC_SIM_EVENT_PROGRAM_END &&
event.line == 7);
}
ok &= expect(saw_g52_initial, "expected LinuxCNC G52 initial local offset event");
ok &= expect(saw_g52_sticky_axis, "expected LinuxCNC G52 to retain omitted axes");
ok &= expect(saw_g52_suspend, "expected LinuxCNC G52/G92 shared offset to suspend with G92.2");
ok &= expect(saw_g52_restore, "expected LinuxCNC G52/G92 shared offset to restore with G92.3");
ok &= expect(saw_g52_end_line, "expected LinuxCNC G52 program end line number");
cnc_sim_destroy(sim);
int abort_count = 0;

File diff suppressed because it is too large Load Diff

View File

@@ -33,11 +33,61 @@ int main() {
INIT_CANON();
USE_LENGTH_UNITS(CANON_UNITS_MM);
SELECT_PLANE(CANON_PLANE::XY);
SET_TRAVERSE_RATE(9000.0);
const bool external_traverse_rate = GET_EXTERNAL_TRAVERSE_RATE() == 9000.0;
SET_FEED_RATE(500.0);
SET_FEED_MODE(2, 1);
SET_SPINDLE_SPEED(0, 1200.0);
START_SPINDLE_CLOCKWISE(0, 0);
START_SPINDLE_COUNTERCLOCKWISE(0, 0);
STOP_SPINDLE_TURNING(0);
SET_SPINDLE_MODE(0, 2500.0);
cnc_sim_linuxcnc_set_current_line(27);
ORIENT_SPINDLE(0, 45.0, 1);
WAIT_SPINDLE_ORIENT_COMPLETE(0, 2.5);
cnc_sim_linuxcnc_set_current_line(28);
SET_MOTION_OUTPUT_BIT(1);
CLEAR_MOTION_OUTPUT_BIT(1);
SET_AUX_OUTPUT_BIT(2);
CLEAR_AUX_OUTPUT_BIT(2);
WAIT(0, DIGITAL_INPUT, WAIT_MODE_HIGH, 5.0);
WAIT(1, ANALOG_INPUT, WAIT_MODE_IMMEDIATE, 0.0);
SET_MOTION_OUTPUT_VALUE(0, 1.25);
SET_AUX_OUTPUT_VALUE(1, 2.5);
cnc_sim_linuxcnc_set_current_line(29);
ENABLE_FEED_OVERRIDE();
const bool external_feed_override_on = GET_EXTERNAL_FEED_OVERRIDE_ENABLE() == 1;
DISABLE_FEED_OVERRIDE();
const bool external_feed_override_off = GET_EXTERNAL_FEED_OVERRIDE_ENABLE() == 0;
ENABLE_SPEED_OVERRIDE(0);
const bool external_speed_override_on = GET_EXTERNAL_SPINDLE_OVERRIDE_ENABLE(0) == 1;
DISABLE_SPEED_OVERRIDE(0);
const bool external_speed_override_off = GET_EXTERNAL_SPINDLE_OVERRIDE_ENABLE(0) == 0;
ENABLE_ADAPTIVE_FEED();
const bool external_adaptive_feed_on = GET_EXTERNAL_ADAPTIVE_FEED_ENABLE() == 1;
DISABLE_ADAPTIVE_FEED();
const bool external_adaptive_feed_off = GET_EXTERNAL_ADAPTIVE_FEED_ENABLE() == 0;
ENABLE_FEED_HOLD();
const bool external_feed_hold_on = GET_EXTERNAL_FEED_HOLD_ENABLE() == 1;
DISABLE_FEED_HOLD();
const bool external_feed_hold_off = GET_EXTERNAL_FEED_HOLD_ENABLE() == 0;
cnc_sim_linuxcnc_set_current_line(30);
SET_MOTION_CONTROL_MODE(CANON_CONTINUOUS, 0.125);
SET_NAIVECAM_TOLERANCE(0.025);
const bool external_motion_mode = GET_EXTERNAL_MOTION_CONTROL_MODE() == CANON_CONTINUOUS;
const bool external_motion_tolerance = GET_EXTERNAL_MOTION_CONTROL_TOLERANCE() == 0.125;
const bool external_naivecam_tolerance = GET_EXTERNAL_MOTION_CONTROL_NAIVECAM_TOLERANCE() == 0.025;
SET_BLOCK_DELETE(true);
const bool external_block_delete_on = GET_BLOCK_DELETE();
SET_BLOCK_DELETE(false);
const bool external_block_delete_off = !GET_BLOCK_DELETE();
SET_OPTIONAL_PROGRAM_STOP(true);
const bool external_optional_stop_on = GET_OPTIONAL_PROGRAM_STOP();
SET_OPTIONAL_PROGRAM_STOP(false);
const bool external_optional_stop_off = !GET_OPTIONAL_PROGRAM_STOP();
cnc_sim_linuxcnc_set_current_line(0);
START_SPEED_FEED_SYNCH(0, 1.25, false);
STOP_SPEED_FEED_SYNCH();
SELECT_TOOL(7);
CHANGE_TOOL();
cnc_sim_linuxcnc_set_current_line(8);
@@ -45,7 +95,10 @@ int main() {
STRAIGHT_TRAVERSE(10, 0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
STRAIGHT_FEED(11, 10.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
ARC_FEED(12, 10.0, 10.0, 10.0, 5.0, 1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
STRAIGHT_PROBE(13, 10.0, 10.0, -1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0);
STRAIGHT_PROBE(13, 10.0, 10.0, -1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 3);
STRAIGHT_PROBE(14, 10.0, 10.0, -2.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1);
const bool external_probe_position = GET_EXTERNAL_PROBE_POSITION_Z() == -2.0;
const bool external_probe_tripped = GET_EXTERNAL_PROBE_TRIPPED_VALUE() == 1;
SET_G5X_OFFSET(1, 10.0, 20.0, 30.0, 1.0, 2.0, 3.0, 0.0, 0.0, 0.0);
SET_G92_OFFSET(1.0, 2.0, 3.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
SET_XY_ROTATION(15.0);
@@ -53,6 +106,7 @@ int main() {
tool_offset.tran.z = 12.5;
cnc_sim_linuxcnc_set_current_line(19);
USE_TOOL_LENGTH_OFFSET(tool_offset);
const bool external_tool_length_z = GET_EXTERNAL_TOOL_LENGTH_ZOFFSET() == 12.5;
cnc_sim_linuxcnc_set_current_line(20);
COMMENT("bridge comment");
cnc_sim_linuxcnc_set_current_line(24);
@@ -74,6 +128,7 @@ int main() {
ok &= expect(events.size() >= 8, "expected bridge events");
ok &= expect(events[0].type == CNC_SIM_EVENT_SET_UNITS, "expected units event");
ok &= expect(events[1].type == CNC_SIM_EVENT_SET_PLANE, "expected plane event");
ok &= expect(external_traverse_rate, "expected external traverse rate query to reflect SET_TRAVERSE_RATE");
bool saw_tool = false;
bool saw_tool_number = false;
@@ -82,6 +137,28 @@ int main() {
bool saw_spindle_cw = false;
bool saw_spindle_ccw = false;
bool saw_spindle_stop = false;
bool saw_spindle_mode = false;
bool saw_feed_mode = false;
bool saw_spindle_orient = false;
bool saw_spindle_orient_wait = false;
bool saw_motion_digital_on = false;
bool saw_motion_digital_off = false;
bool saw_aux_digital_on = false;
bool saw_aux_digital_off = false;
bool saw_wait_digital = false;
bool saw_wait_analog = false;
bool saw_motion_analog = false;
bool saw_aux_analog = false;
bool saw_feed_override_on = false;
bool saw_feed_override_off = false;
bool saw_speed_override_on = false;
bool saw_speed_override_off = false;
bool saw_adaptive_feed_on = false;
bool saw_adaptive_feed_off = false;
bool saw_feed_hold_on = false;
bool saw_feed_hold_off = false;
bool saw_speed_feed_sync_start = false;
bool saw_speed_feed_sync_stop = false;
bool saw_arc = false;
bool saw_probe = false;
bool saw_g5x = false;
@@ -111,6 +188,110 @@ int main() {
saw_spindle_stop = saw_spindle_stop || (event.type == CNC_SIM_EVENT_SET_SPINDLE &&
event.spindle == 0.0 &&
event.reserved == 0);
saw_spindle_mode = saw_spindle_mode || (event.type == CNC_SIM_EVENT_COMMENT &&
event.reserved == 960 &&
event.feed == 2500.0 &&
event.tool == 0);
saw_feed_mode = saw_feed_mode || (event.type == CNC_SIM_EVENT_SET_FEED &&
event.reserved == 1 &&
event.tool == 2);
saw_spindle_orient = saw_spindle_orient || (event.type == CNC_SIM_EVENT_COMMENT &&
event.line == 27 &&
event.reserved == 1901 &&
event.tool == 0 &&
event.feed == 45.0 &&
event.arc_turns == 1);
saw_spindle_orient_wait = saw_spindle_orient_wait || (event.type == CNC_SIM_EVENT_COMMENT &&
event.line == 27 &&
event.reserved == 1902 &&
event.tool == 0 &&
event.dwell_seconds == 2.5);
saw_motion_digital_on = saw_motion_digital_on || (event.type == CNC_SIM_EVENT_COMMENT &&
event.line == 28 &&
event.reserved == 62 &&
event.tool == 1 &&
event.feed == 1.0);
saw_motion_digital_off = saw_motion_digital_off || (event.type == CNC_SIM_EVENT_COMMENT &&
event.line == 28 &&
event.reserved == 63 &&
event.tool == 1 &&
event.feed == 0.0);
saw_aux_digital_on = saw_aux_digital_on || (event.type == CNC_SIM_EVENT_COMMENT &&
event.line == 28 &&
event.reserved == 64 &&
event.tool == 2 &&
event.feed == 1.0);
saw_aux_digital_off = saw_aux_digital_off || (event.type == CNC_SIM_EVENT_COMMENT &&
event.line == 28 &&
event.reserved == 65 &&
event.tool == 2 &&
event.feed == 0.0);
saw_wait_digital = saw_wait_digital || (event.type == CNC_SIM_EVENT_COMMENT &&
event.line == 28 &&
event.reserved == 66 &&
event.tool == 0 &&
event.arc_turns == DIGITAL_INPUT &&
event.feed == WAIT_MODE_HIGH &&
event.dwell_seconds == 5.0);
saw_wait_analog = saw_wait_analog || (event.type == CNC_SIM_EVENT_COMMENT &&
event.line == 28 &&
event.reserved == 66 &&
event.tool == 1 &&
event.arc_turns == ANALOG_INPUT &&
event.feed == WAIT_MODE_IMMEDIATE &&
event.dwell_seconds == 0.0);
saw_motion_analog = saw_motion_analog || (event.type == CNC_SIM_EVENT_COMMENT &&
event.line == 28 &&
event.reserved == 67 &&
event.tool == 0 &&
event.feed == 1.25);
saw_aux_analog = saw_aux_analog || (event.type == CNC_SIM_EVENT_COMMENT &&
event.line == 28 &&
event.reserved == 68 &&
event.tool == 1 &&
event.feed == 2.5);
saw_feed_override_on = saw_feed_override_on || (event.type == CNC_SIM_EVENT_COMMENT &&
event.line == 29 &&
event.reserved == 50 &&
event.feed == 1.0);
saw_feed_override_off = saw_feed_override_off || (event.type == CNC_SIM_EVENT_COMMENT &&
event.line == 29 &&
event.reserved == 50 &&
event.feed == 0.0);
saw_speed_override_on = saw_speed_override_on || (event.type == CNC_SIM_EVENT_COMMENT &&
event.line == 29 &&
event.reserved == 51 &&
event.tool == 0 &&
event.feed == 1.0);
saw_speed_override_off = saw_speed_override_off || (event.type == CNC_SIM_EVENT_COMMENT &&
event.line == 29 &&
event.reserved == 51 &&
event.tool == 0 &&
event.feed == 0.0);
saw_adaptive_feed_on = saw_adaptive_feed_on || (event.type == CNC_SIM_EVENT_COMMENT &&
event.line == 29 &&
event.reserved == 52 &&
event.feed == 1.0);
saw_adaptive_feed_off = saw_adaptive_feed_off || (event.type == CNC_SIM_EVENT_COMMENT &&
event.line == 29 &&
event.reserved == 52 &&
event.feed == 0.0);
saw_feed_hold_on = saw_feed_hold_on || (event.type == CNC_SIM_EVENT_COMMENT &&
event.line == 29 &&
event.reserved == 53 &&
event.feed == 1.0);
saw_feed_hold_off = saw_feed_hold_off || (event.type == CNC_SIM_EVENT_COMMENT &&
event.line == 29 &&
event.reserved == 53 &&
event.feed == 0.0);
saw_speed_feed_sync_start = saw_speed_feed_sync_start || (event.type == CNC_SIM_EVENT_COMMENT &&
event.reserved == 3301 &&
event.feed == 1.25 &&
event.tool == 0);
saw_speed_feed_sync_stop = saw_speed_feed_sync_stop || (event.type == CNC_SIM_EVENT_COMMENT &&
event.reserved == 3300 &&
event.feed == 0.0 &&
event.tool == 0);
saw_rapid = saw_rapid || (event.type == CNC_SIM_EVENT_RAPID && event.end.z == 5.0);
saw_feed = saw_feed || (event.type == CNC_SIM_EVENT_LINEAR_FEED && event.end.x == 10.0);
saw_arc = saw_arc || (event.type == CNC_SIM_EVENT_ARC_FEED &&
@@ -119,6 +300,7 @@ int main() {
event.center.y == 5.0);
saw_probe = saw_probe || (event.type == CNC_SIM_EVENT_PROBE &&
event.line == 13 &&
event.reserved == 3 &&
event.start.x == 10.0 &&
event.start.y == 10.0 &&
event.end.z == -1.0);
@@ -171,14 +353,54 @@ int main() {
ok &= expect(saw_spindle_cw, "expected clockwise spindle state");
ok &= expect(saw_spindle_ccw, "expected counterclockwise spindle state");
ok &= expect(saw_spindle_stop, "expected stopped spindle state");
ok &= expect(saw_spindle_mode, "expected spindle mode state");
ok &= expect(saw_feed_mode, "expected feed mode state to preserve spindle and mode arguments");
ok &= expect(saw_spindle_orient, "expected spindle orient state");
ok &= expect(saw_spindle_orient_wait, "expected spindle orient wait state");
ok &= expect(saw_motion_digital_on, "expected motion digital output on state");
ok &= expect(saw_motion_digital_off, "expected motion digital output off state");
ok &= expect(saw_aux_digital_on, "expected auxiliary digital output on state");
ok &= expect(saw_aux_digital_off, "expected auxiliary digital output off state");
ok &= expect(saw_wait_digital, "expected digital input wait state");
ok &= expect(saw_wait_analog, "expected analog input wait state");
ok &= expect(saw_motion_analog, "expected motion analog output state");
ok &= expect(saw_aux_analog, "expected auxiliary analog output state");
ok &= expect(saw_feed_override_on, "expected feed override enable state");
ok &= expect(saw_feed_override_off, "expected feed override disable state");
ok &= expect(saw_speed_override_on, "expected speed override enable state");
ok &= expect(saw_speed_override_off, "expected speed override disable state");
ok &= expect(saw_adaptive_feed_on, "expected adaptive feed enable state");
ok &= expect(saw_adaptive_feed_off, "expected adaptive feed disable state");
ok &= expect(saw_feed_hold_on, "expected feed hold enable state");
ok &= expect(saw_feed_hold_off, "expected feed hold disable state");
ok &= expect(external_feed_override_on, "expected external feed override query to reflect enable");
ok &= expect(external_feed_override_off, "expected external feed override query to reflect disable");
ok &= expect(external_speed_override_on, "expected external speed override query to reflect enable");
ok &= expect(external_speed_override_off, "expected external speed override query to reflect disable");
ok &= expect(external_adaptive_feed_on, "expected external adaptive feed query to reflect enable");
ok &= expect(external_adaptive_feed_off, "expected external adaptive feed query to reflect disable");
ok &= expect(external_feed_hold_on, "expected external feed hold query to reflect enable");
ok &= expect(external_feed_hold_off, "expected external feed hold query to reflect disable");
ok &= expect(external_motion_mode, "expected external motion-control mode query to reflect SET_MOTION_CONTROL_MODE");
ok &= expect(external_motion_tolerance, "expected external motion-control tolerance query to reflect SET_MOTION_CONTROL_MODE");
ok &= expect(external_naivecam_tolerance, "expected external naivecam tolerance query to reflect SET_NAIVECAM_TOLERANCE");
ok &= expect(external_block_delete_on, "expected block-delete query to reflect enable");
ok &= expect(external_block_delete_off, "expected block-delete query to reflect disable");
ok &= expect(external_optional_stop_on, "expected optional-stop query to reflect enable");
ok &= expect(external_optional_stop_off, "expected optional-stop query to reflect disable");
ok &= expect(saw_speed_feed_sync_start, "expected speed-feed sync start state");
ok &= expect(saw_speed_feed_sync_stop, "expected speed-feed sync stop state");
ok &= expect(saw_rapid, "expected rapid move");
ok &= expect(saw_feed, "expected linear feed");
ok &= expect(saw_arc, "expected arc feed");
ok &= expect(saw_probe, "expected probe event");
ok &= expect(external_probe_position, "expected external probe position query to reflect last STRAIGHT_PROBE");
ok &= expect(external_probe_tripped, "expected external probe tripped query to reflect trip-seeking STRAIGHT_PROBE");
ok &= expect(saw_g5x, "expected G5X offset event");
ok &= expect(saw_g92, "expected G92 offset event");
ok &= expect(saw_rotation, "expected XY rotation event");
ok &= expect(saw_tool_length, "expected tool length offset event");
ok &= expect(external_tool_length_z, "expected external tool length Z query to reflect USE_TOOL_LENGTH_OFFSET");
ok &= expect(saw_comment, "expected comment event line");
ok &= expect(saw_mist_on, "expected mist on state");
ok &= expect(saw_flood_on, "expected flood on state");