按提示词结论接入 INI 参数文件桥

This commit is contained in:
cnc
2026-06-02 13:26:09 +08:00
parent cee1bf3a3f
commit 0e1e22a864
7 changed files with 197 additions and 4 deletions

View File

@@ -11,6 +11,7 @@
struct CncSimHandle {
CncSimDialect dialect = CNC_SIM_DIALECT_LINUXCNC;
GcodeBackendKind backend = GcodeBackendKind::LinuxCncRs274;
GcodeBackendOptions backend_options;
std::string last_error;
CanonEventSink sink;
};
@@ -96,6 +97,72 @@ bool contains_string_value(const std::string &compact, const char *key, const ch
return false;
}
bool find_json_string_value(const std::string &json, const char *key, std::string *value) {
const std::string needle = std::string("\"") + key + "\"";
size_t pos = 0;
while ((pos = json.find(needle, pos)) != std::string::npos) {
pos += needle.size();
while (pos < json.size() && std::isspace(static_cast<unsigned char>(json[pos]))) {
++pos;
}
if (pos >= json.size() || json[pos] != ':') {
continue;
}
++pos;
while (pos < json.size() && std::isspace(static_cast<unsigned char>(json[pos]))) {
++pos;
}
if (pos >= json.size() || json[pos] != '"') {
continue;
}
++pos;
std::string parsed;
bool escaped = false;
for (; pos < json.size(); ++pos) {
const char ch = json[pos];
if (escaped) {
switch (ch) {
case '"':
case '\\':
case '/':
parsed.push_back(ch);
break;
case 'n':
parsed.push_back('\n');
break;
case 'r':
parsed.push_back('\r');
break;
case 't':
parsed.push_back('\t');
break;
default:
parsed.push_back(ch);
break;
}
escaped = false;
} else if (ch == '\\') {
escaped = true;
} else if (ch == '"') {
*value = parsed;
return true;
} else {
parsed.push_back(ch);
}
}
}
return false;
}
bool find_json_string_any(const std::string &json, std::string *value, const char *first) {
return find_json_string_value(json, first, value);
}
template <typename... Keys>
bool find_json_string_any(const std::string &json, std::string *value, const char *first, Keys... rest) {
return find_json_string_value(json, first, value) || find_json_string_any(json, value, rest...);
}
bool contains_switchkins_config_alias(const std::string &compact, const char *alias) {
return contains_string_value(compact, "switchkins", alias) ||
contains_string_value(compact, "remap", alias) ||
@@ -300,6 +367,20 @@ int apply_config(CncSimHandle *handle, const std::string &json) {
return -1;
}
std::string ini_file_name;
if (find_json_string_any(json,
&ini_file_name,
"ini",
"iniFile",
"inifile",
"iniFileName",
"inifilename",
"ini_file",
"ini_file_name",
"INI_FILE_NAME")) {
handle->backend_options.ini_file_name = ini_file_name;
}
bool rtcp_enabled = false;
double tool_length = 0.0;
const bool has_rtcp_enabled = contains_bool_value(compact, "rtcp", &rtcp_enabled) ||
@@ -383,7 +464,12 @@ int cnc_sim_parse_program(CncSimHandle *handle, const char *program, size_t prog
}
handle->last_error.clear();
const int rc = parse_gcode_with_backend(handle->backend, handle->sink, program, program_len, &handle->last_error);
const int rc = parse_gcode_with_backend(handle->backend,
handle->sink,
program,
program_len,
handle->backend_options,
&handle->last_error);
if (rc != 0 && handle->last_error.empty()) {
handle->last_error = "program parse failed";
}

View File

@@ -22,6 +22,7 @@ int parse_gcode_with_backend(GcodeBackendKind backend,
CanonEventSink &sink,
const char *program,
size_t program_len,
const GcodeBackendOptions &options,
std::string *error) {
switch (backend) {
case GcodeBackendKind::Smoke: {
@@ -37,7 +38,7 @@ int parse_gcode_with_backend(GcodeBackendKind backend,
}
case GcodeBackendKind::LinuxCncRs274:
#ifdef CNC_SIM_ENABLE_LINUXCNC_RS274_BACKEND
return parse_linuxcnc_rs274_backend(sink, program, program_len, error);
return parse_linuxcnc_rs274_backend(sink, program, program_len, options, error);
#else
if (error) {
*error = "linuxcnc-rs274 backend is not compiled into this build";

View File

@@ -10,11 +10,15 @@ enum class GcodeBackendKind {
LinuxCncRs274,
};
struct GcodeBackendOptions {
std::string ini_file_name;
};
const char *gcode_backend_name(GcodeBackendKind backend);
int parse_gcode_with_backend(GcodeBackendKind backend,
CanonEventSink &sink,
const char *program,
size_t program_len,
const GcodeBackendOptions &options,
std::string *error);

View File

@@ -175,6 +175,7 @@ int execute_file_mode(InterpBase *interp,
int parse_linuxcnc_rs274_backend(CanonEventSink &sink,
const char *program,
size_t program_len,
const GcodeBackendOptions &options,
std::string *error) {
if (!program && program_len != 0) {
if (error) {
@@ -197,6 +198,22 @@ int parse_linuxcnc_rs274_backend(CanonEventSink &sink,
cnc_sim_linuxcnc_set_canon_sink(&sink);
InterpBase *interp = makeInterp();
if (!options.ini_file_name.empty()) {
// LinuxCNC source basis: emctask.cc calls Interp::ini_load() before
// Interp::init(), and rs274ngc_pre.cc ini_load() maps
// [RS274NGC] PARAMETER_FILE through SET_PARAMETER_FILE_NAME().
if (interp->ini_load(options.ini_file_name.c_str()) != INTERP_OK) {
if (error) {
*error = "ini_load failed: " + options.ini_file_name;
}
delete interp;
cnc_sim_linuxcnc_set_canon_sink(nullptr);
return -1;
}
if (const char *parameter_file = std::getenv("CNC_SIM_RS274_VAR")) {
SET_PARAMETER_FILE_NAME(parameter_file);
}
}
int status = interp->init();
if (status != INTERP_OK) {
if (error) {

View File

@@ -1,6 +1,7 @@
#pragma once
#include "canon_event_sink.h"
#include "gcode_backend.h"
#include <cstddef>
#include <string>
@@ -8,5 +9,5 @@
int parse_linuxcnc_rs274_backend(CanonEventSink &sink,
const char *program,
size_t program_len,
const GcodeBackendOptions &options,
std::string *error);