按规划持续工作

结论:已纳入 LinuxCNC 五轴 switchkins M428/M429/M430 来源资产,补齐 remap source probe 与 native 验证闭环,未新增自写 CNC 语义。
This commit is contained in:
2026-06-08 15:33:05 +08:00
parent 19687c3268
commit 5df62ad60a
61 changed files with 12160 additions and 4 deletions

View File

@@ -0,0 +1,235 @@
#include <fstream>
#include <iostream>
#include <iterator>
#include <string>
#include <vector>
#include "emc/ini/inifile.hh"
#ifndef LINUXCNC_VENDOR_DIR
#error "LINUXCNC_VENDOR_DIR must point at wasm-port/vendor/linuxcnc"
#endif
namespace {
struct MachineCase {
const char *label;
const char *ini_rel;
const char *machine;
const char *kinematics;
const char *coordinates;
const char *joints;
const char *parameter_file;
const char *tool_table;
bool expects_m430;
};
std::string vendor_path(const std::string &rel)
{
return std::string(LINUXCNC_VENDOR_DIR) + "/" + rel;
}
std::string read_text(const std::string &path)
{
std::ifstream input(path);
return std::string(
std::istreambuf_iterator<char>(input),
std::istreambuf_iterator<char>());
}
bool contains(const std::string &text, const std::string &needle)
{
return text.find(needle) != std::string::npos;
}
void print_bool(const std::string &name, bool value)
{
std::cout << name << "=" << (value ? 1 : 0) << "\n";
}
bool check_string(
const linuxcnc::IniFile &ini,
const std::string &label,
const std::string &section,
const std::string &tag,
const std::string &expected)
{
const auto actual = ini.findString(tag, section);
std::cout << label << "_" << section << "." << tag << "="
<< (actual ? *actual : "<missing>") << "\n";
const bool ok = actual && *actual == expected;
print_bool(label + "_" + section + "." + tag + "_ok", ok);
return ok;
}
bool check_remap_entry(
const std::vector<std::string> &remaps,
const std::string &label,
const std::string &mcode,
const std::string &ngc)
{
const std::string mcode_needle = "REMAP = " + mcode;
const std::string ngc_needle = "ngc=" + ngc;
bool ok = false;
for (const auto &remap : remaps) {
if (contains(remap, mcode) && contains(remap, ngc_needle)) {
ok = true;
}
}
print_bool(label + "_remap_" + mcode + "_" + ngc, ok);
(void)mcode_needle;
return ok;
}
bool check_remap_file(
const std::string &label,
const std::string &dir_rel,
const std::string &mcode,
const std::string &expected_kinstype)
{
const std::string path = vendor_path(dir_rel + "/remap_subs/" + mcode.substr(1) + "remap.ngc");
const std::string text = read_text(path);
const bool ok =
contains(text, "o<" + mcode.substr(1) + "remap>sub") &&
contains(text, "#<kinstype> = " + expected_kinstype) &&
contains(text, "#<SWITCHKINS_PIN> = 3") &&
contains(text, "#<_hal[motion.switchkins-type]>") &&
contains(text, "M68") &&
contains(text, "M66") &&
contains(text, "o<" + mcode.substr(1) + "remap>endsub");
print_bool(label + "_" + mcode + "_remap_file_from_linuxcnc", ok);
return ok;
}
bool check_text_mcodes(
const std::string &label,
const std::string &rel,
bool expects_m428,
bool expects_m429)
{
const std::string text = read_text(vendor_path(rel));
const bool ok =
(!expects_m428 || contains(text, "M428")) &&
(!expects_m429 || contains(text, "M429"));
print_bool(label + "_switch_mcodes_from_linuxcnc", ok);
return ok;
}
bool check_machine(const MachineCase &machine)
{
bool ok = true;
const std::string ini_path = vendor_path(machine.ini_rel);
linuxcnc::IniFile ini(ini_path);
const bool opened = static_cast<bool>(ini);
print_bool(std::string(machine.label) + "_ini_open", opened);
if (!opened) {
return false;
}
ok &= check_string(ini, machine.label, "EMC", "MACHINE", machine.machine);
ok &= check_string(ini, machine.label, "KINS", "KINEMATICS", machine.kinematics);
ok &= check_string(ini, machine.label, "TRAJ", "COORDINATES", machine.coordinates);
ok &= check_string(ini, machine.label, "KINS", "JOINTS", machine.joints);
ok &= check_string(ini, machine.label, "RS274NGC", "SUBROUTINE_PATH", "./remap_subs");
ok &= check_string(ini, machine.label, "RS274NGC", "PARAMETER_FILE", machine.parameter_file);
ok &= check_string(ini, machine.label, "EMCIO", "TOOL_TABLE", machine.tool_table);
const auto remaps = ini.findStringAll("REMAP", "RS274NGC");
std::cout << machine.label << "_remap_count=" << remaps.size() << "\n";
ok &= check_remap_entry(remaps, machine.label, "M428", "428remap");
ok &= check_remap_entry(remaps, machine.label, "M429", "429remap");
if (machine.expects_m430) {
ok &= check_remap_entry(remaps, machine.label, "M430", "430remap");
}
const std::string ini_text = read_text(ini_path);
const bool has_switchkins_halcmd =
contains(ini_text, "motion.analog-out-03 => motion.switchkins-type");
ok &= has_switchkins_halcmd;
print_bool(std::string(machine.label) + "_halcmd_switchkins_from_linuxcnc", has_switchkins_halcmd);
const std::string dir_rel = std::string(machine.ini_rel).substr(
0,
std::string(machine.ini_rel).find_last_of('/'));
return ok && check_remap_file(machine.label, dir_rel, "M428",
std::string(machine.label) == "bridgemill" ? "0" : "1") &&
check_remap_file(machine.label, dir_rel, "M429",
std::string(machine.label) == "bridgemill" ? "1" : "0") &&
(!machine.expects_m430 || check_remap_file(machine.label, dir_rel, "M430", "2"));
}
} // namespace
int main()
{
const MachineCase cases[] = {
{
"bridgemill",
"configs/sim/axis/vismach/5axis/bridgemill/5axis.ini",
"Sim-5Axis Bridge Mill (xyzbcw)",
"5axiskins coordinates=xyzbcwy",
"XYZBCWY",
"7",
"5axis.var",
"5axis.tbl",
true,
},
{
"xyzab_tdr",
"configs/sim/axis/vismach/5axis/table-dual-rotary/xyzab-tdr.ini",
"sim-xyzab-tdr-kins (switchkins)",
"xyzab_tdr_kins",
"XYZAB",
"5",
"xyzab-tdr.var",
"xyzab-tdr.tbl",
false,
},
{
"xyzac_trt",
"configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzac-trt.ini",
"sim-xyzac-trt-kins (switchkins)",
"xyzac-trt-kins sparm=identityfirst",
"XYZAC",
"5",
"xyzac.var",
"xyzac-trt.tbl",
true,
},
{
"xyzbc_trt",
"configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzbc-trt.ini",
"sim-xyzbc-trt-kins (switchkins)",
"xyzbc-trt-kins sparm=identityfirst",
"XYZBC",
"5",
"xyzbc.var",
"xyzbc-trt.tbl",
true,
},
};
bool ok = true;
for (const auto &machine : cases) {
ok &= check_machine(machine);
}
ok &= check_text_mcodes(
"xyzab_tdr",
"configs/sim/axis/vismach/5axis/table-dual-rotary/README",
true,
true);
ok &= check_text_mcodes(
"xyzac_trt",
"configs/sim/axis/vismach/5axis/table-rotary-tilting/demos/xyzac_switchkins_test_1.ngc",
true,
true);
ok &= check_text_mcodes(
"xyzbc_trt",
"configs/sim/axis/vismach/5axis/table-rotary-tilting/demos/boat-xyzbc.ngc",
true,
true);
print_bool("fiveaxis_remap_assets_from_linuxcnc", ok);
return ok ? 0 : 1;
}

View File

@@ -14,6 +14,7 @@ typedef _object PyObject;
inline int PyCallable_Check(PyObject *) { return 0; }
inline int PyErr_ExceptionMatches(PyObject *) { return 0; }
inline void PyErr_Clear() {}
inline void PyErr_Print() {}
inline int PyUnicode_Check(PyObject *) { return 0; }
inline int PyLong_Check(PyObject *) { return 0; }
inline int PyFloat_Check(PyObject *) { return 0; }
@@ -36,6 +37,9 @@ public:
template <typename T>
explicit object(const T &) {}
template <typename T>
object &operator=(const T &) { return *this; }
object attr(const char *) const { return object(); }
object operator[](const char *) const { return object(); }
object operator[](const std::string &) const { return object(); }

View File

@@ -0,0 +1,7 @@
#pragma once
#include <cwctype>
#ifndef towlower
#define towlower std::towlower
#endif

View File

@@ -19,7 +19,7 @@ import {
} from "../../opfs/linuxcnc-machine-session-bridge.js";
const SAMPLE_PATH =
"../../../linuxcnc/configs/sim/axis/vismach/5axis/table-dual-rotary/xyzab-tdr.ini";
"../../../vendor/linuxcnc/configs/sim/axis/vismach/5axis/table-dual-rotary/xyzab-tdr.ini";
const MACHINE_ID = "xyzab-tdr";
const MACHINE_PATHS = machineFilePaths(MACHINE_ID);
const OPFS_FILE = MACHINE_PATHS.ini;