From bf7192cc07514221d355ff33cc03e85ac20e24c0 Mon Sep 17 00:00:00 2001 From: CNC Local Date: Fri, 22 May 2026 04:48:37 +0800 Subject: [PATCH] Propagate LinuxCNC canon event line numbers --- README.zh-CN.md | 2 + core/src/linuxcnc_canon_bridge.cpp | 38 ++++++++++++------- core/src/linuxcnc_canon_bridge.h | 2 +- core/src/linuxcnc_rs274_backend.cpp | 2 + .../cnc_sim_api_linuxcnc_rs274_smoke.cpp | 8 ++++ core/tools/linuxcnc_rs274_dump.cpp | 1 + test-linuxcnc-rs274-native.sh | 4 ++ 7 files changed, 42 insertions(+), 15 deletions(-) diff --git a/README.zh-CN.md b/README.zh-CN.md index c7aa65b..a94da87 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -58,6 +58,7 @@ The first useful target is: - 已有 LinuxCNC RS274 源码级链接 smoke:本项目直接编译 23 个解释器 core 源文件,不再通过 `librs274` 取得解释器主体。 - 已有五轴 RTCP 第一版几何内核,可根据编程刀尖点、A/B/C 姿态和刀长计算枢轴/主轴点补偿位置。 - 已有坐标系事件回归语料,覆盖 `G10 L2` 的 G5X/XY 旋转事件和 `G92.1` 清零事件。 +- LinuxCNC Canon bridge 会把当前解释行号补到没有自带 `lineno` 的回调事件上,方便 Web 端诊断和源码高亮。 - 下一步是继续替换源码级链接中残留的 Python、INI/HAL、文件系统和动态加载依赖,并把 RTCP 内核接入 canon 事件流和机型配置。 ## 本地测试 @@ -145,6 +146,7 @@ Canon bridge 已不再丢弃坐标系相关回调,会输出: 这些事件先保证 LinuxCNC Canon 层信息完整进入 Web/core。具体 G-code(如 `G10`、`G92`、坐标旋转)是否触发这些回调,还要继续按 LinuxCNC 解释器参数路径逐项补回归语料。 目前已有第一组回归语料 `tests/gcode/linuxcnc_coordinate_offsets.ngc`,覆盖 `G10 L2 P1 X... Y... Z... R...` 触发 `set-g5x-offset` / `set-xy-rotation`,以及 `G92.1` 触发 `set-g92-offset` 清零。后续继续扩展到 `G10 L20`、多坐标系 P 号、持久参数文件和旋转叠加运动路径。 +LinuxCNC 中部分 Canon 函数不携带行号参数,bridge 会在调用解释器 `read/execute` 前记录当前输入行,并用它填充这类事件的 `line` 字段。 ## CMake native LinuxCNC 后端 diff --git a/core/src/linuxcnc_canon_bridge.cpp b/core/src/linuxcnc_canon_bridge.cpp index f5369c3..9cc0fbb 100644 --- a/core/src/linuxcnc_canon_bridge.cpp +++ b/core/src/linuxcnc_canon_bridge.cpp @@ -14,6 +14,7 @@ namespace { CanonEventSink *active_sink = nullptr; +int active_line = 0; std::string parameter_file_name = "rs274ngc.var"; CncSimPose make_pose(double x, double y, double z, @@ -81,17 +82,26 @@ void trace_call(const char *name) { } } +int event_line(int lineno = 0) { + return lineno > 0 ? lineno : active_line; +} + } // namespace void cnc_sim_linuxcnc_set_canon_sink(CanonEventSink *sink) { trace_call("cnc_sim_linuxcnc_set_canon_sink"); active_sink = sink; + active_line = 0; } CanonEventSink *cnc_sim_linuxcnc_get_canon_sink() { return active_sink; } +void cnc_sim_linuxcnc_set_current_line(int line) { + active_line = line > 0 ? line : 0; +} + void INIT_CANON() { trace_call("INIT_CANON"); if (active_sink) { @@ -102,28 +112,28 @@ void INIT_CANON() { void USE_LENGTH_UNITS(CANON_UNITS units) { trace_call("USE_LENGTH_UNITS"); if (active_sink) { - active_sink->use_length_units(units_to_scale(units), 0); + active_sink->use_length_units(units_to_scale(units), event_line()); } } void SELECT_PLANE(CANON_PLANE plane) { trace_call("SELECT_PLANE"); if (active_sink) { - active_sink->select_plane(plane_to_g_code(plane), 0); + active_sink->select_plane(plane_to_g_code(plane), event_line()); } } void SET_FEED_RATE(double rate) { trace_call("SET_FEED_RATE"); if (active_sink) { - active_sink->set_feed_rate(rate, 0); + active_sink->set_feed_rate(rate, event_line()); } } void SET_SPINDLE_SPEED(int, double speed) { trace_call("SET_SPINDLE_SPEED"); if (active_sink) { - active_sink->set_spindle_speed(speed, 0); + active_sink->set_spindle_speed(speed, event_line()); } } @@ -137,7 +147,7 @@ void SELECT_TOOL(int tool) { void CHANGE_TOOL() { trace_call("CHANGE_TOOL"); if (active_sink) { - active_sink->change_tool(0); + active_sink->change_tool(event_line()); } } @@ -147,7 +157,7 @@ void STRAIGHT_TRAVERSE(int lineno, double u, double v, double w) { trace_call("STRAIGHT_TRAVERSE"); if (active_sink) { - active_sink->straight_traverse(lineno, make_pose(x, y, z, a, b, c, u, v, w)); + active_sink->straight_traverse(event_line(lineno), make_pose(x, y, z, a, b, c, u, v, w)); } } @@ -157,7 +167,7 @@ void STRAIGHT_FEED(int lineno, double u, double v, double w) { trace_call("STRAIGHT_FEED"); if (active_sink) { - active_sink->straight_feed(lineno, make_pose(x, y, z, a, b, c, u, v, w)); + active_sink->straight_feed(event_line(lineno), make_pose(x, y, z, a, b, c, u, v, w)); } } @@ -205,20 +215,20 @@ void ARC_FEED(int lineno, end.u = u; end.v = v; end.w = w; - active_sink->arc_feed(lineno, end, center, rotation); + active_sink->arc_feed(event_line(lineno), end, center, rotation); } void DWELL(double seconds) { trace_call("DWELL"); if (active_sink) { - active_sink->dwell(seconds, 0); + active_sink->dwell(seconds, event_line()); } } void PROGRAM_END() { trace_call("PROGRAM_END"); if (active_sink) { - active_sink->program_end(0); + active_sink->program_end(event_line()); } } @@ -232,7 +242,7 @@ void SET_G5X_OFFSET(int index, double u, double v, double w) { trace_call("SET_G5X_OFFSET"); if (active_sink) { - active_sink->set_g5x_offset(index, make_pose(x, y, z, a, b, c, u, v, w), 0); + active_sink->set_g5x_offset(index, make_pose(x, y, z, a, b, c, u, v, w), event_line()); } } @@ -241,14 +251,14 @@ void SET_G92_OFFSET(double x, double y, double z, double u, double v, double w) { trace_call("SET_G92_OFFSET"); if (active_sink) { - active_sink->set_g92_offset(make_pose(x, y, z, a, b, c, u, v, w), 0); + active_sink->set_g92_offset(make_pose(x, y, z, a, b, c, u, v, w), event_line()); } } void SET_XY_ROTATION(double angle) { trace_call("SET_XY_ROTATION"); if (active_sink) { - active_sink->set_xy_rotation(angle, 0); + active_sink->set_xy_rotation(angle, event_line()); } } @@ -257,7 +267,7 @@ void CANON_UPDATE_END_POINT(double x, double y, double z, double u, double v, double w) { trace_call("CANON_UPDATE_END_POINT"); if (active_sink) { - active_sink->straight_traverse(0, make_pose(x, y, z, a, b, c, u, v, w)); + active_sink->straight_traverse(event_line(), make_pose(x, y, z, a, b, c, u, v, w)); } } diff --git a/core/src/linuxcnc_canon_bridge.h b/core/src/linuxcnc_canon_bridge.h index d02ca63..88573bf 100644 --- a/core/src/linuxcnc_canon_bridge.h +++ b/core/src/linuxcnc_canon_bridge.h @@ -4,4 +4,4 @@ class CanonEventSink; void cnc_sim_linuxcnc_set_canon_sink(CanonEventSink *sink); CanonEventSink *cnc_sim_linuxcnc_get_canon_sink(); - +void cnc_sim_linuxcnc_set_current_line(int line); diff --git a/core/src/linuxcnc_rs274_backend.cpp b/core/src/linuxcnc_rs274_backend.cpp index da1ac27..bf443f4 100644 --- a/core/src/linuxcnc_rs274_backend.cpp +++ b/core/src/linuxcnc_rs274_backend.cpp @@ -126,6 +126,7 @@ int parse_linuxcnc_rs274_backend(CanonEventSink &sink, int line_number = 0; while (!program_done && std::getline(input, line)) { ++line_number; + cnc_sim_linuxcnc_set_current_line(line_number); std::vector control_actions; if (parse_simulator_gcode_control_line(line, &control_actions)) { for (const auto &action : control_actions) { @@ -172,6 +173,7 @@ int parse_linuxcnc_rs274_backend(CanonEventSink &sink, } } + cnc_sim_linuxcnc_set_current_line(0); interp->exit(); delete interp; cnc_sim_linuxcnc_set_canon_sink(nullptr); diff --git a/core/tests/cnc_sim_api_linuxcnc_rs274_smoke.cpp b/core/tests/cnc_sim_api_linuxcnc_rs274_smoke.cpp index c0136cc..56f5ce8 100644 --- a/core/tests/cnc_sim_api_linuxcnc_rs274_smoke.cpp +++ b/core/tests/cnc_sim_api_linuxcnc_rs274_smoke.cpp @@ -68,6 +68,7 @@ int main() { bool saw_g5x_offset = false; bool saw_xy_rotation = false; bool saw_g92_clear = false; + bool saw_coordinate_end_line = false; for (const auto &event : events) { saw_tool = saw_tool || event.type == CNC_SIM_EVENT_TOOL_CHANGE; saw_rapid = saw_rapid || event.type == CNC_SIM_EVENT_RAPID; @@ -128,22 +129,29 @@ int main() { for (const auto &event : events) { saw_g5x_offset = saw_g5x_offset || (event.type == CNC_SIM_EVENT_SET_G5X_OFFSET && + event.line == 2 && event.tool == 1 && event.start.x == 12.5 && event.start.y == -3.0 && event.start.z == 4.0); saw_xy_rotation = saw_xy_rotation || (event.type == CNC_SIM_EVENT_SET_XY_ROTATION && + event.line == 2 && event.feed == 30.0); saw_g92_clear = saw_g92_clear || (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_coordinate_end_line = saw_coordinate_end_line || + (event.type == CNC_SIM_EVENT_PROGRAM_END && + event.line == 5); } 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_clear, "expected LinuxCNC G92.1 clear offset event"); + ok &= expect(saw_coordinate_end_line, "expected LinuxCNC coordinate program end line number"); cnc_sim_destroy(sim); diff --git a/core/tools/linuxcnc_rs274_dump.cpp b/core/tools/linuxcnc_rs274_dump.cpp index 0fd20b6..7fb1ae7 100644 --- a/core/tools/linuxcnc_rs274_dump.cpp +++ b/core/tools/linuxcnc_rs274_dump.cpp @@ -133,6 +133,7 @@ bool execute_line(InterpBase *interp, const std::string &line, int line_number, bool *program_done) { + cnc_sim_linuxcnc_set_current_line(line_number); std::vector control_actions; if (parse_simulator_gcode_control_line(line, &control_actions)) { for (const auto &action : control_actions) { diff --git a/test-linuxcnc-rs274-native.sh b/test-linuxcnc-rs274-native.sh index c61f448..f1eb8ff 100755 --- a/test-linuxcnc-rs274-native.sh +++ b/test-linuxcnc-rs274-native.sh @@ -82,6 +82,7 @@ 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 @@ -92,12 +93,15 @@ if not any( 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") PY echo "linuxcnc rs274 native smoke passed"