按规划持续工作
结论:接通 LinuxCNC M68/M66 到 standalone HAL adapter 的同步边界,新增 native remap/HAL 验证,确认 5axis switchkins remap 所需的 _hal[motion.switchkins-type] 读回路径可用。
This commit is contained in:
@@ -212,6 +212,7 @@ The validation fails if:
|
|||||||
| `linuxcnc_parameter_file_harness` | Validates LinuxCNC parameter file restore/save behavior and required/read-only parameter handling. |
|
| `linuxcnc_parameter_file_harness` | Validates LinuxCNC parameter file restore/save behavior and required/read-only parameter handling. |
|
||||||
| `linuxcnc_interp_init_harness` | Validates vendored LinuxCNC `Interp::init()` emits canonical initialization boundaries, reads metric/inch machine units, and synchronizes current/selected tool slots through standalone status adapters. |
|
| `linuxcnc_interp_init_harness` | Validates vendored LinuxCNC `Interp::init()` emits canonical initialization boundaries, reads metric/inch machine units, and synchronizes current/selected tool slots through standalone status adapters. |
|
||||||
| `linuxcnc_indexer_harness` | Validates vendored LinuxCNC single-axis rotary indexer dispatch emits lock/unlock and motion boundaries through the standalone event sink. |
|
| `linuxcnc_indexer_harness` | Validates vendored LinuxCNC single-axis rotary indexer dispatch emits lock/unlock and motion boundaries through the standalone event sink. |
|
||||||
|
| `linuxcnc_remap_hal_sync_harness` | Validates vendored LinuxCNC `M68`/`M66` execution can drive the standalone HAL adapter boundary used by 5-axis switchkins remap files, including `_hal[motion.switchkins-type]` readback. |
|
||||||
| `linuxcnc_tp_api_probe` | Validates vendored LinuxCNC trajectory planner calls for linear, arc, and queued motion paths. |
|
| `linuxcnc_tp_api_probe` | Validates vendored LinuxCNC trajectory planner calls for linear, arc, and queued motion paths. |
|
||||||
| `linuxcnc_kinematics_probe` | Validates vendored LinuxCNC `trivkins.c` plus `kins_util.c` initialize and perform identity forward/inverse mapping through the standalone HAL/RTAPI boundary. |
|
| `linuxcnc_kinematics_probe` | Validates vendored LinuxCNC `trivkins.c` plus `kins_util.c` initialize and perform identity forward/inverse mapping through the standalone HAL/RTAPI boundary. |
|
||||||
| `linuxcnc_5axis_kinematics_probe` | Validates vendored LinuxCNC `5axiskins.c` through `switchkins.c`, including 5-axis forward/inverse round-trip behavior and switching to identity kinematics. |
|
| `linuxcnc_5axis_kinematics_probe` | Validates vendored LinuxCNC `5axiskins.c` through `switchkins.c`, including 5-axis forward/inverse round-trip behavior and switching to identity kinematics. |
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
#include <cstdarg>
|
#include <cstdarg>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <new>
|
#include <new>
|
||||||
|
#include <sstream>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@@ -52,6 +53,12 @@ std::unordered_map<std::string, HalEntry> &values_for(standalone::HalValueKind k
|
|||||||
return pins();
|
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,
|
int lookup_hal_value(const char *name, std::unordered_map<std::string, HalEntry> &values,
|
||||||
hal_type_t *type, hal_data_u **ptr, bool *connected)
|
hal_type_t *type, hal_data_u **ptr, bool *connected)
|
||||||
{
|
{
|
||||||
@@ -81,6 +88,7 @@ void reset_hal_adapter()
|
|||||||
pins().clear();
|
pins().clear();
|
||||||
signals().clear();
|
signals().clear();
|
||||||
params().clear();
|
params().clear();
|
||||||
|
pin_aliases().clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_hal_value(HalValueKind kind, const char *name, hal_type_t type, hal_data_u value,
|
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};
|
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
|
} // namespace standalone
|
||||||
|
|
||||||
int hal_init(const char *)
|
int hal_init(const char *)
|
||||||
|
|||||||
@@ -13,5 +13,7 @@ enum class HalValueKind {
|
|||||||
void reset_hal_adapter();
|
void reset_hal_adapter();
|
||||||
void set_hal_value(HalValueKind kind, const char *name, hal_type_t type, hal_data_u value,
|
void set_hal_value(HalValueKind kind, const char *name, hal_type_t type, hal_data_u value,
|
||||||
bool connected = true);
|
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
|
} // namespace standalone
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
|
|
||||||
#include "emc/rs274ngc/rs274ngc_return.hh"
|
#include "emc/rs274ngc/rs274ngc_return.hh"
|
||||||
#include "canon_event_sink.hh"
|
#include "canon_event_sink.hh"
|
||||||
|
#include "linuxcnc_hal_adapter.hh"
|
||||||
#include "linuxcnc_tool_adapter.hh"
|
#include "linuxcnc_tool_adapter.hh"
|
||||||
#include "nml_intf/emc.hh"
|
#include "nml_intf/emc.hh"
|
||||||
|
|
||||||
@@ -381,6 +382,7 @@ void SET_AUX_OUTPUT_VALUE(int index, double value)
|
|||||||
std::ostringstream oss;
|
std::ostringstream oss;
|
||||||
oss << "SET_AUX_OUTPUT_VALUE index=" << index << " value=" << value;
|
oss << "SET_AUX_OUTPUT_VALUE index=" << index << " value=" << value;
|
||||||
standalone::push_canon_event(oss.str());
|
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)
|
int WAIT(int index, int input_type, int wait_type, double timeout)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -161,6 +161,8 @@ check_exitcode linuxcnc_interp_init_harness
|
|||||||
check_exitcode linuxcnc_interp_init_harness.run
|
check_exitcode linuxcnc_interp_init_harness.run
|
||||||
check_exitcode linuxcnc_remap_parse_harness
|
check_exitcode linuxcnc_remap_parse_harness
|
||||||
check_exitcode linuxcnc_remap_parse_harness.run
|
check_exitcode linuxcnc_remap_parse_harness.run
|
||||||
|
check_exitcode linuxcnc_remap_hal_sync_harness
|
||||||
|
check_exitcode linuxcnc_remap_hal_sync_harness.run
|
||||||
check_exitcode linuxcnc_indexer_harness
|
check_exitcode linuxcnc_indexer_harness
|
||||||
check_exitcode linuxcnc_indexer_harness.run
|
check_exitcode linuxcnc_indexer_harness.run
|
||||||
check_exitcode linuxcnc_rs274_compile_probe
|
check_exitcode linuxcnc_rs274_compile_probe
|
||||||
@@ -264,6 +266,21 @@ grep -Fq "xyzbc_trt_M430_ngc=1" "$REMAP_PARSE_STDOUT"
|
|||||||
grep -Fq "xyzbc_trt_linuxcnc_ngc_remaps_parsed=1" "$REMAP_PARSE_STDOUT"
|
grep -Fq "xyzbc_trt_linuxcnc_ngc_remaps_parsed=1" "$REMAP_PARSE_STDOUT"
|
||||||
grep -Fq "fiveaxis_linuxcnc_remap_parse_path=1" "$REMAP_PARSE_STDOUT"
|
grep -Fq "fiveaxis_linuxcnc_remap_parse_path=1" "$REMAP_PARSE_STDOUT"
|
||||||
|
|
||||||
|
REMAP_HAL_SYNC_STDOUT="$BUILD_DIR/linuxcnc_remap_hal_sync_harness.run.stdout.log"
|
||||||
|
grep -Fq "_hal[motion.switchkins-type]: rc=0 found=1 value=0" "$REMAP_HAL_SYNC_STDOUT"
|
||||||
|
grep -Fq "m68_to_tcp=0" "$REMAP_HAL_SYNC_STDOUT"
|
||||||
|
grep -Fq "_hal[motion.switchkins-type]: rc=0 found=1 value=1" "$REMAP_HAL_SYNC_STDOUT"
|
||||||
|
grep -Fq "_hal[motion.analog-out-03]: rc=0 found=1 value=1" "$REMAP_HAL_SYNC_STDOUT"
|
||||||
|
grep -Fq "m66_sync=2" "$REMAP_HAL_SYNC_STDOUT"
|
||||||
|
grep -Fq "m66_input_flag=1" "$REMAP_HAL_SYNC_STDOUT"
|
||||||
|
grep -Fq "m66_input_index=0" "$REMAP_HAL_SYNC_STDOUT"
|
||||||
|
grep -Fq "m66_input_digital=0" "$REMAP_HAL_SYNC_STDOUT"
|
||||||
|
grep -Fq "m68_to_identity=0" "$REMAP_HAL_SYNC_STDOUT"
|
||||||
|
grep -Fq "canon_has_m68_tcp=1" "$REMAP_HAL_SYNC_STDOUT"
|
||||||
|
grep -Fq "canon_has_m66_sync=1" "$REMAP_HAL_SYNC_STDOUT"
|
||||||
|
grep -Fq "canon_has_m68_identity=1" "$REMAP_HAL_SYNC_STDOUT"
|
||||||
|
grep -Fq "fiveaxis_remap_hal_sync_boundary=1" "$REMAP_HAL_SYNC_STDOUT"
|
||||||
|
|
||||||
NAMEDPARAM_STDOUT="$BUILD_DIR/linuxcnc_namedparam_harness.run.stdout.log"
|
NAMEDPARAM_STDOUT="$BUILD_DIR/linuxcnc_namedparam_harness.run.stdout.log"
|
||||||
grep -Fq "init_named_parameters=0" "$NAMEDPARAM_STDOUT"
|
grep -Fq "init_named_parameters=0" "$NAMEDPARAM_STDOUT"
|
||||||
grep -Fq "global_named_count=57" "$NAMEDPARAM_STDOUT"
|
grep -Fq "global_named_count=57" "$NAMEDPARAM_STDOUT"
|
||||||
|
|||||||
@@ -697,6 +697,11 @@ REMAP_PARSE_SOURCES=(
|
|||||||
"$WRAP_DIR/linuxcnc_remap_parse_harness.cpp"
|
"$WRAP_DIR/linuxcnc_remap_parse_harness.cpp"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
REMAP_HAL_SYNC_SOURCES=(
|
||||||
|
"${INTERP_CORE_SOURCES[@]}"
|
||||||
|
"$WRAP_DIR/linuxcnc_remap_hal_sync_harness.cpp"
|
||||||
|
)
|
||||||
|
|
||||||
build_binary_target \
|
build_binary_target \
|
||||||
linuxcnc_ini_probe \
|
linuxcnc_ini_probe \
|
||||||
"$BUILD_DIR/linuxcnc_ini_probe" \
|
"$BUILD_DIR/linuxcnc_ini_probe" \
|
||||||
@@ -1282,6 +1287,28 @@ else
|
|||||||
"$BUILD_DIR/linuxcnc_remap_parse_harness.run.stderr.log"
|
"$BUILD_DIR/linuxcnc_remap_parse_harness.run.stderr.log"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
build_binary_target \
|
||||||
|
linuxcnc_remap_hal_sync_harness \
|
||||||
|
"$BUILD_DIR/linuxcnc_remap_hal_sync_harness" \
|
||||||
|
REMAP_RUNTIME_FLAGS \
|
||||||
|
REMAP_HAL_SYNC_SOURCES \
|
||||||
|
MINIMAL_LINK_FLAGS
|
||||||
|
|
||||||
|
if [[ "$(tr -d '[:space:]' < "$BUILD_DIR/linuxcnc_remap_hal_sync_harness.exitcode")" == "0" ]]; then
|
||||||
|
set +e
|
||||||
|
"$BUILD_DIR/linuxcnc_remap_hal_sync_harness" \
|
||||||
|
>"$BUILD_DIR/linuxcnc_remap_hal_sync_harness.run.stdout.log" \
|
||||||
|
2>"$BUILD_DIR/linuxcnc_remap_hal_sync_harness.run.stderr.log"
|
||||||
|
REMAP_HAL_SYNC_RUN_RC=$?
|
||||||
|
set -e
|
||||||
|
echo "$REMAP_HAL_SYNC_RUN_RC" > "$BUILD_DIR/linuxcnc_remap_hal_sync_harness.run.exitcode"
|
||||||
|
else
|
||||||
|
rm -f \
|
||||||
|
"$BUILD_DIR/linuxcnc_remap_hal_sync_harness.run.exitcode" \
|
||||||
|
"$BUILD_DIR/linuxcnc_remap_hal_sync_harness.run.stdout.log" \
|
||||||
|
"$BUILD_DIR/linuxcnc_remap_hal_sync_harness.run.stderr.log"
|
||||||
|
fi
|
||||||
|
|
||||||
build_binary_target \
|
build_binary_target \
|
||||||
linuxcnc_indexer_harness \
|
linuxcnc_indexer_harness \
|
||||||
"$BUILD_DIR/linuxcnc_indexer_harness" \
|
"$BUILD_DIR/linuxcnc_indexer_harness" \
|
||||||
|
|||||||
Reference in New Issue
Block a user