按规划持续工作

结论:接通 LinuxCNC M68/M66 到 standalone HAL adapter 的同步边界,新增 native remap/HAL 验证,确认 5axis switchkins remap 所需的 _hal[motion.switchkins-type] 读回路径可用。
This commit is contained in:
2026-06-08 17:05:24 +08:00
parent 3a58f1e495
commit 42da16214d
7 changed files with 207 additions and 0 deletions

View File

@@ -3,6 +3,7 @@
#include <cstdarg>
#include <cstdio>
#include <new>
#include <sstream>
#include <string>
#include <unordered_map>
#include <vector>
@@ -52,6 +53,12 @@ std::unordered_map<std::string, HalEntry> &values_for(standalone::HalValueKind k
return pins();
}
std::unordered_map<std::string, std::vector<std::string>> &pin_aliases()
{
static std::unordered_map<std::string, std::vector<std::string>> values;
return values;
}
int lookup_hal_value(const char *name, std::unordered_map<std::string, HalEntry> &values,
hal_type_t *type, hal_data_u **ptr, bool *connected)
{
@@ -81,6 +88,7 @@ void reset_hal_adapter()
pins().clear();
signals().clear();
params().clear();
pin_aliases().clear();
}
void set_hal_value(HalValueKind kind, const char *name, hal_type_t type, hal_data_u value,
@@ -89,6 +97,39 @@ void set_hal_value(HalValueKind kind, const char *name, hal_type_t type, hal_dat
values_for(kind)[name] = HalEntry{type, value, connected};
}
void link_hal_pin_alias(const char *source, const char *alias)
{
if (!source || !alias) {
return;
}
pin_aliases()[source].push_back(alias);
}
void sync_motion_analog_output(int index, double value)
{
hal_data_u analog{};
analog.f = value;
std::ostringstream out_name;
out_name << "motion.analog-out-" << index;
set_hal_value(HalValueKind::Pin, out_name.str().c_str(), HAL_FLOAT, analog);
std::ostringstream padded_out_name;
padded_out_name << "motion.analog-out-0" << index;
set_hal_value(HalValueKind::Pin, padded_out_name.str().c_str(), HAL_FLOAT, analog);
const std::string names[] = {out_name.str(), padded_out_name.str()};
for (const auto &name : names) {
auto aliases = pin_aliases().find(name);
if (aliases == pin_aliases().end()) {
continue;
}
for (const auto &alias : aliases->second) {
set_hal_value(HalValueKind::Pin, alias.c_str(), HAL_FLOAT, analog);
}
}
}
} // namespace standalone
int hal_init(const char *)

View File

@@ -13,5 +13,7 @@ enum class HalValueKind {
void reset_hal_adapter();
void set_hal_value(HalValueKind kind, const char *name, hal_type_t type, hal_data_u value,
bool connected = true);
void link_hal_pin_alias(const char *source, const char *alias);
void sync_motion_analog_output(int index, double value);
} // namespace standalone

View File

@@ -12,6 +12,7 @@
#include "emc/rs274ngc/rs274ngc_return.hh"
#include "canon_event_sink.hh"
#include "linuxcnc_hal_adapter.hh"
#include "linuxcnc_tool_adapter.hh"
#include "nml_intf/emc.hh"
@@ -381,6 +382,7 @@ void SET_AUX_OUTPUT_VALUE(int index, double value)
std::ostringstream oss;
oss << "SET_AUX_OUTPUT_VALUE index=" << index << " value=" << value;
standalone::push_canon_event(oss.str());
standalone::sync_motion_analog_output(index, value);
}
int WAIT(int index, int input_type, int wait_type, double timeout)
{

View File

@@ -0,0 +1,117 @@
#define private public
#include "emc/rs274ngc/rs274ngc_interp.hh"
#undef private
#include <cmath>
#include <cstring>
#include <iostream>
#include <string>
#include "canon_event_sink.hh"
#include "linuxcnc_hal_adapter.hh"
#include "linuxcnc_tool_adapter.hh"
namespace {
void print_bool(const std::string &name, bool value)
{
std::cout << name << "=" << (value ? 1 : 0) << "\n";
}
void seed_switchkins_hal()
{
standalone::reset_hal_adapter();
hal_data_u switchkins{};
switchkins.f = 0.0;
standalone::set_hal_value(standalone::HalValueKind::Pin, "motion.switchkins-type",
HAL_FLOAT, switchkins);
standalone::set_hal_value(standalone::HalValueKind::Pin, "motion.analog-out-03",
HAL_FLOAT, switchkins);
standalone::link_hal_pin_alias("motion.analog-out-03", "motion.switchkins-type");
}
void initialize_interp(Interp &interp)
{
seed_switchkins_hal();
standalone::reset_tool_adapter();
standalone::reset_canon_events();
interp._setup.length_units = CANON_UNITS_MM;
interp._setup.distance_mode = DISTANCE_MODE::ABSOLUTE;
interp._setup.ijk_distance_mode = DISTANCE_MODE::ABSOLUTE;
interp._setup.feed_mode = FEED_MODE::UNITS_PER_MINUTE;
interp._setup.plane = CANON_PLANE::XY;
interp._setup.motion_mode = G_0;
interp._setup.percent_flag = false;
interp._setup.sequence_number = 0;
interp._setup.parameter_occurrence = 0;
interp._setup.num_spindles = 1;
interp._setup.feature_set = FEATURE_INI_VARS | FEATURE_HAL_PIN_VARS;
interp._setup.parameter_g73_peck_clearance = 1.0;
interp._setup.parameter_g83_peck_clearance = 1.0;
interp._setup.parameters[5599] = 1.0;
std::memcpy(interp._readers, Interp::default_readers, sizeof(Interp::default_readers));
interp.init_named_parameters();
}
bool read_hal_named(Interp &interp, const char *name, double expected)
{
int status = 0;
double value = 0.0;
const int rc = interp.find_named_param(name, &status, &value);
std::cout << name << ": rc=" << rc << " found=" << status << " value=" << value << "\n";
return rc == INTERP_OK && status == 1 && std::fabs(value - expected) < 0.000001;
}
bool has_event(const std::string &needle)
{
for (const auto &event : standalone::canon_events()) {
if (event.find(needle) != std::string::npos) {
return true;
}
}
return false;
}
} // namespace
int main()
{
Interp interp;
initialize_interp(interp);
bool ok = true;
ok &= read_hal_named(interp, "_hal[motion.switchkins-type]", 0.0);
const int m68_to_tcp_rc = interp.execute("M68 E3 Q1\n");
std::cout << "m68_to_tcp=" << m68_to_tcp_rc << "\n";
ok &= m68_to_tcp_rc == INTERP_OK;
ok &= read_hal_named(interp, "_hal[motion.switchkins-type]", 1.0);
ok &= read_hal_named(interp, "_hal[motion.analog-out-03]", 1.0);
const int m66_sync_rc = interp.execute("M66 E0 L0\n");
std::cout << "m66_sync=" << m66_sync_rc << "\n";
std::cout << "m66_input_flag=" << interp._setup.input_flag << "\n";
std::cout << "m66_input_index=" << interp._setup.input_index << "\n";
std::cout << "m66_input_digital=" << interp._setup.input_digital << "\n";
ok &= m66_sync_rc == INTERP_EXECUTE_FINISH;
ok &= interp._setup.input_flag;
ok &= interp._setup.input_index == 0;
ok &= !interp._setup.input_digital;
const int m68_to_identity_rc = interp.execute("M68 E3 Q0\n");
std::cout << "m68_to_identity=" << m68_to_identity_rc << "\n";
ok &= m68_to_identity_rc == INTERP_OK;
ok &= read_hal_named(interp, "_hal[motion.switchkins-type]", 0.0);
print_bool("canon_has_m68_tcp", has_event("SET_AUX_OUTPUT_VALUE index=3 value=1"));
print_bool("canon_has_m66_sync", has_event("WAIT index=0 input_type=0 wait_type=0"));
print_bool("canon_has_m68_identity", has_event("SET_AUX_OUTPUT_VALUE index=3 value=0"));
ok &= has_event("SET_AUX_OUTPUT_VALUE index=3 value=1");
ok &= has_event("WAIT index=0 input_type=0 wait_type=0");
ok &= has_event("SET_AUX_OUTPUT_VALUE index=3 value=0");
print_bool("fiveaxis_remap_hal_sync_boundary", ok);
return ok ? 0 : 1;
}