接续上一轮:推进浏览器验证与M428配置收拢

结论:已完成浏览器侧真实加载验证,M428/M429/M430 的配置入口进一步从 LinuxCNC INI/HALFILE/REMAP 来源生成,native 与 source-link 验证通过。
This commit is contained in:
cnc
2026-05-30 10:03:21 +08:00
parent b40914747d
commit de273bf830
141 changed files with 11255 additions and 1259 deletions

View File

@@ -1,9 +1,10 @@
cmake_minimum_required(VERSION 3.20)
project(cnc_sim_wasm_core LANGUAGES CXX)
project(cnc_sim_wasm_core LANGUAGES C CXX)
option(CNC_SIM_ENABLE_LINUXCNC_BRIDGE "Build the experimental LinuxCNC canon bridge" OFF)
option(CNC_SIM_ENABLE_LINUXCNC_RS274_BACKEND "Build the native LinuxCNC librs274 backend" OFF)
option(CNC_SIM_ENABLE_LINUXCNC_WASM_SAFE_PROBE "Compile the browser-safe subset of LinuxCNC rs274 sources" OFF)
option(CNC_SIM_ENABLE_SMOKE_BACKEND "Build the legacy explicit smoke G-code backend test harness" OFF)
set(CNC_SIM_LINUXCNC_ROOT "" CACHE PATH "LinuxCNC source root for the experimental bridge")
set(CNC_SIM_LINUXCNC_WASM_SOURCE_MANIFEST
"${CMAKE_CURRENT_SOURCE_DIR}/../linuxcnc-rs274-wasm-source-files.txt"
@@ -15,23 +16,71 @@ set(cnc_sim_core_sources
src/canon_event_sink.cpp
src/cnc_sim_api.cpp
src/gcode_backend.cpp
src/linuxcnc_5axiskins_adapter.c
src/linuxcnc_5axiskins_adapter.cpp
src/linuxcnc_corexykins_adapter.c
src/linuxcnc_corexykins_adapter.cpp
src/linuxcnc_cubic_adapter.c
src/linuxcnc_cubic_adapter.cpp
src/linuxcnc_genserfuncs_adapter.c
src/linuxcnc_genserfuncs_adapter.cpp
src/linuxcnc_genhexkins_adapter.c
src/linuxcnc_genhexkins_adapter.cpp
src/linuxcnc_kins_util_adapter.c
src/linuxcnc_kins_util_adapter.cpp
src/linuxcnc_lineardeltakins_adapter.c
src/linuxcnc_lineardeltakins_adapter.cpp
src/linuxcnc_maxkins_adapter.c
src/linuxcnc_maxkins_adapter.cpp
src/linuxcnc_pentakins_adapter.c
src/linuxcnc_pentakins_adapter.cpp
src/linuxcnc_pumakins_adapter.c
src/linuxcnc_pumakins_adapter.cpp
src/linuxcnc_rotatekins_adapter.c
src/linuxcnc_rotatekins_adapter.cpp
src/linuxcnc_rosekins_adapter.c
src/linuxcnc_rosekins_adapter.cpp
src/linuxcnc_rotarydeltakins_adapter.c
src/linuxcnc_rotarydeltakins_adapter.cpp
src/linuxcnc_scarakins_adapter.c
src/linuxcnc_scarakins_adapter.cpp
src/linuxcnc_scorbot_kins_adapter.c
src/linuxcnc_scorbot_kins_adapter.cpp
src/linuxcnc_tripodkins_adapter.c
src/linuxcnc_tripodkins_adapter.cpp
src/linuxcnc_trtfuncs_adapter.c
src/linuxcnc_trtfuncs_adapter.cpp
src/linuxcnc_userkfuncs_adapter.c
src/linuxcnc_userkfuncs_adapter.cpp
src/linuxcnc_xyzab_tdr_kins_adapter.c
src/linuxcnc_xyzab_tdr_kins_adapter.cpp
src/rtcp_kinematics.cpp
src/simulator_gcode_controls.cpp
)
set(cnc_sim_smoke_backend_sources
src/smoke_gcode_parser.cpp
)
set(cnc_sim_linuxcnc_rs274_backend_sources
src/linuxcnc_canon_bridge.cpp
src/linuxcnc_rs274_backend.cpp
src/linuxcnc_tooldata_fixture.cpp
)
if(CNC_SIM_ENABLE_LINUXCNC_RS274_BACKEND)
if(CNC_SIM_ENABLE_SMOKE_BACKEND)
message(FATAL_ERROR "CNC_SIM_ENABLE_SMOKE_BACKEND cannot be combined with CNC_SIM_ENABLE_LINUXCNC_RS274_BACKEND")
endif()
if(EMSCRIPTEN)
message(FATAL_ERROR "CNC_SIM_ENABLE_LINUXCNC_RS274_BACKEND is native-only; it links LinuxCNC librs274")
endif()
if(NOT CNC_SIM_LINUXCNC_ROOT)
message(FATAL_ERROR "Set CNC_SIM_LINUXCNC_ROOT to the LinuxCNC source root")
endif()
list(APPEND cnc_sim_core_sources
src/linuxcnc_canon_bridge.cpp
src/linuxcnc_rs274_backend.cpp
src/linuxcnc_tooldata_fixture.cpp
)
list(APPEND cnc_sim_core_sources ${cnc_sim_linuxcnc_rs274_backend_sources})
elseif(CNC_SIM_ENABLE_SMOKE_BACKEND)
list(APPEND cnc_sim_core_sources ${cnc_sim_smoke_backend_sources})
endif()
if(CNC_SIM_ENABLE_LINUXCNC_WASM_SAFE_PROBE)
@@ -67,7 +116,11 @@ if(CNC_SIM_ENABLE_LINUXCNC_WASM_SAFE_PROBE)
set(manifest_group "${CMAKE_MATCH_1}")
set(manifest_path "${CMAKE_MATCH_2}")
if(NOT manifest_group STREQUAL "core" AND NOT manifest_group STREQUAL "blocked")
if(NOT manifest_group STREQUAL "core"
AND NOT manifest_group STREQUAL "blocked"
AND NOT manifest_group STREQUAL "header"
AND NOT manifest_group STREQUAL "metadata"
AND NOT manifest_group STREQUAL "blocked-header")
message(FATAL_ERROR "Unknown LinuxCNC wasm source manifest group: ${manifest_group}")
endif()
@@ -81,7 +134,7 @@ if(CNC_SIM_ENABLE_LINUXCNC_WASM_SAFE_PROBE)
if(manifest_group STREQUAL "core")
list(APPEND linuxcnc_wasm_safe_probe_sources "${manifest_source}")
else()
elseif(manifest_group STREQUAL "blocked")
list(APPEND linuxcnc_wasm_blocked_sources "${manifest_source}")
endif()
endforeach()
@@ -97,6 +150,17 @@ if(CNC_SIM_ENABLE_LINUXCNC_WASM_SAFE_PROBE)
message(STATUS "LinuxCNC wasm-safe core sources: ${linuxcnc_wasm_safe_probe_source_count}")
message(STATUS "LinuxCNC wasm blocked sources: ${linuxcnc_wasm_blocked_source_count}")
set(cnc_sim_wasm_safe_preinclude_options "SHELL:-include wctype.h")
if(EMSCRIPTEN)
list(APPEND cnc_sim_wasm_safe_preinclude_options "SHELL:-include libgen.h")
find_path(CNC_SIM_FMT_INCLUDE_DIR fmt/format.h
PATHS /usr/include /usr/local/include
NO_CMAKE_FIND_ROOT_PATH
REQUIRED
)
list(APPEND cnc_sim_wasm_safe_preinclude_options "SHELL:-idirafter ${CNC_SIM_FMT_INCLUDE_DIR}")
endif()
set(linuxcnc_wasm_safe_probe_shims
${CMAKE_CURRENT_SOURCE_DIR}/wasm_shims/dlfcn.cc
${CMAKE_CURRENT_SOURCE_DIR}/wasm_shims/emc_status_shim.cc
@@ -115,7 +179,7 @@ if(CNC_SIM_ENABLE_LINUXCNC_WASM_SAFE_PROBE)
)
target_compile_features(linuxcnc_rs274_wasm_safe_probe_objects PUBLIC cxx_std_20)
target_compile_definitions(linuxcnc_rs274_wasm_safe_probe_objects PRIVATE ULAPI)
target_compile_options(linuxcnc_rs274_wasm_safe_probe_objects PRIVATE -include wctype.h)
target_compile_options(linuxcnc_rs274_wasm_safe_probe_objects PRIVATE ${cnc_sim_wasm_safe_preinclude_options})
target_include_directories(linuxcnc_rs274_wasm_safe_probe_objects
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/include
@@ -128,12 +192,55 @@ if(CNC_SIM_ENABLE_LINUXCNC_WASM_SAFE_PROBE)
${CNC_SIM_LINUXCNC_ROOT_ABS}/src/emc/motion
${CNC_SIM_LINUXCNC_ROOT_ABS}/include
)
if(EMSCRIPTEN)
target_compile_definitions(linuxcnc_rs274_wasm_safe_probe_objects PRIVATE FMT_HEADER_ONLY=1)
endif()
set(linuxcnc_rs274_wasm_safe_probe_project_sources
${CMAKE_CURRENT_SOURCE_DIR}/src/canon_event_sink.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/linuxcnc_canon_bridge.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/linuxcnc_rs274_backend.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/linuxcnc_tooldata_fixture.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/linuxcnc_5axiskins_adapter.c
${CMAKE_CURRENT_SOURCE_DIR}/src/linuxcnc_5axiskins_adapter.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/linuxcnc_corexykins_adapter.c
${CMAKE_CURRENT_SOURCE_DIR}/src/linuxcnc_corexykins_adapter.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/linuxcnc_cubic_adapter.c
${CMAKE_CURRENT_SOURCE_DIR}/src/linuxcnc_cubic_adapter.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/linuxcnc_genserfuncs_adapter.c
${CMAKE_CURRENT_SOURCE_DIR}/src/linuxcnc_genserfuncs_adapter.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/linuxcnc_genhexkins_adapter.c
${CMAKE_CURRENT_SOURCE_DIR}/src/linuxcnc_genhexkins_adapter.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/linuxcnc_kins_util_adapter.c
${CMAKE_CURRENT_SOURCE_DIR}/src/linuxcnc_kins_util_adapter.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/linuxcnc_lineardeltakins_adapter.c
${CMAKE_CURRENT_SOURCE_DIR}/src/linuxcnc_lineardeltakins_adapter.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/linuxcnc_maxkins_adapter.c
${CMAKE_CURRENT_SOURCE_DIR}/src/linuxcnc_maxkins_adapter.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/linuxcnc_pentakins_adapter.c
${CMAKE_CURRENT_SOURCE_DIR}/src/linuxcnc_pentakins_adapter.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/linuxcnc_pumakins_adapter.c
${CMAKE_CURRENT_SOURCE_DIR}/src/linuxcnc_pumakins_adapter.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/linuxcnc_rotatekins_adapter.c
${CMAKE_CURRENT_SOURCE_DIR}/src/linuxcnc_rotatekins_adapter.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/linuxcnc_rosekins_adapter.c
${CMAKE_CURRENT_SOURCE_DIR}/src/linuxcnc_rosekins_adapter.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/linuxcnc_rotarydeltakins_adapter.c
${CMAKE_CURRENT_SOURCE_DIR}/src/linuxcnc_rotarydeltakins_adapter.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/linuxcnc_scarakins_adapter.c
${CMAKE_CURRENT_SOURCE_DIR}/src/linuxcnc_scarakins_adapter.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/linuxcnc_scorbot_kins_adapter.c
${CMAKE_CURRENT_SOURCE_DIR}/src/linuxcnc_scorbot_kins_adapter.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/linuxcnc_tripodkins_adapter.c
${CMAKE_CURRENT_SOURCE_DIR}/src/linuxcnc_tripodkins_adapter.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/linuxcnc_trtfuncs_adapter.c
${CMAKE_CURRENT_SOURCE_DIR}/src/linuxcnc_trtfuncs_adapter.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/linuxcnc_userkfuncs_adapter.c
${CMAKE_CURRENT_SOURCE_DIR}/src/linuxcnc_userkfuncs_adapter.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/linuxcnc_xyzab_tdr_kins_adapter.c
${CMAKE_CURRENT_SOURCE_DIR}/src/linuxcnc_xyzab_tdr_kins_adapter.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/rtcp_kinematics.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/simulator_gcode_controls.cpp
)
add_executable(linuxcnc_rs274_wasm_safe_probe EXCLUDE_FROM_ALL
@@ -142,8 +249,13 @@ if(CNC_SIM_ENABLE_LINUXCNC_WASM_SAFE_PROBE)
${CMAKE_CURRENT_SOURCE_DIR}/wasm_shims/rs274ngc_pre_probe_main.cc
)
target_compile_features(linuxcnc_rs274_wasm_safe_probe PRIVATE cxx_std_20)
target_compile_definitions(linuxcnc_rs274_wasm_safe_probe PRIVATE ULAPI)
target_compile_options(linuxcnc_rs274_wasm_safe_probe PRIVATE -include wctype.h)
target_compile_definitions(linuxcnc_rs274_wasm_safe_probe
PRIVATE
CNC_SIM_ENABLE_LINUXCNC_RS274_BACKEND
CNC_SIM_ENABLE_LINUXCNC_WASM_SAFE_PROBE
ULAPI
)
target_compile_options(linuxcnc_rs274_wasm_safe_probe PRIVATE ${cnc_sim_wasm_safe_preinclude_options})
target_include_directories(linuxcnc_rs274_wasm_safe_probe
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/include
@@ -156,7 +268,15 @@ if(CNC_SIM_ENABLE_LINUXCNC_WASM_SAFE_PROBE)
${CNC_SIM_LINUXCNC_ROOT_ABS}/src/emc/motion
${CNC_SIM_LINUXCNC_ROOT_ABS}/include
)
target_link_libraries(linuxcnc_rs274_wasm_safe_probe PRIVATE fmt)
if(EMSCRIPTEN)
target_compile_definitions(linuxcnc_rs274_wasm_safe_probe PRIVATE FMT_HEADER_ONLY=1)
else()
target_link_libraries(linuxcnc_rs274_wasm_safe_probe PRIVATE fmt)
endif()
set(cnc_sim_wasm_runtime_probe_main
${CMAKE_CURRENT_SOURCE_DIR}/wasm_shims/cnc_sim_wasm_runtime_probe_main.cc
)
if(linuxcnc_wasm_blocked_sources)
add_custom_target(linuxcnc_rs274_wasm_blocked_sources
@@ -165,6 +285,10 @@ if(CNC_SIM_ENABLE_LINUXCNC_WASM_SAFE_PROBE)
endif()
endif()
if(CNC_SIM_ENABLE_LINUXCNC_WASM_SAFE_PROBE)
list(APPEND cnc_sim_core_sources ${cnc_sim_linuxcnc_rs274_backend_sources})
endif()
add_library(cnc_sim_objects OBJECT
${cnc_sim_core_sources}
)
@@ -174,9 +298,36 @@ target_include_directories(cnc_sim_objects
${CMAKE_CURRENT_SOURCE_DIR}/include
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/src
${CMAKE_CURRENT_SOURCE_DIR}/../../linuxcnc/include
)
target_compile_features(cnc_sim_objects PUBLIC cxx_std_17)
set(cnc_sim_linuxcnc_kinematics_c_sources
src/linuxcnc_5axiskins_adapter.c
src/linuxcnc_corexykins_adapter.c
src/linuxcnc_cubic_adapter.c
src/linuxcnc_genserfuncs_adapter.c
src/linuxcnc_genhexkins_adapter.c
src/linuxcnc_kins_util_adapter.c
src/linuxcnc_lineardeltakins_adapter.c
src/linuxcnc_maxkins_adapter.c
src/linuxcnc_pentakins_adapter.c
src/linuxcnc_pumakins_adapter.c
src/linuxcnc_rotatekins_adapter.c
src/linuxcnc_rosekins_adapter.c
src/linuxcnc_rotarydeltakins_adapter.c
src/linuxcnc_scarakins_adapter.c
src/linuxcnc_scorbot_kins_adapter.c
src/linuxcnc_tripodkins_adapter.c
src/linuxcnc_trtfuncs_adapter.c
src/linuxcnc_userkfuncs_adapter.c
src/linuxcnc_xyzab_tdr_kins_adapter.c
)
set_source_files_properties(
${cnc_sim_linuxcnc_kinematics_c_sources}
PROPERTIES
COMPILE_OPTIONS "$<$<COMPILE_LANGUAGE:CXX>:-fpermissive>"
)
if(CNC_SIM_ENABLE_LINUXCNC_RS274_BACKEND)
find_package(Python3 REQUIRED COMPONENTS Development)
@@ -196,6 +347,64 @@ if(CNC_SIM_ENABLE_LINUXCNC_RS274_BACKEND)
)
endif()
if(CNC_SIM_ENABLE_LINUXCNC_WASM_SAFE_PROBE)
target_compile_definitions(cnc_sim_objects
PRIVATE
CNC_SIM_ENABLE_LINUXCNC_RS274_BACKEND
CNC_SIM_ENABLE_LINUXCNC_WASM_SAFE_PROBE
ULAPI
)
target_compile_options(cnc_sim_objects PRIVATE ${cnc_sim_wasm_safe_preinclude_options})
target_include_directories(cnc_sim_objects
PRIVATE
${CNC_SIM_LINUXCNC_ROOT_ABS}/src
${CNC_SIM_LINUXCNC_ROOT_ABS}/src/emc
${CNC_SIM_LINUXCNC_ROOT_ABS}/src/emc/nml_intf
${CNC_SIM_LINUXCNC_ROOT_ABS}/src/emc/rs274ngc
${CNC_SIM_LINUXCNC_ROOT_ABS}/src/emc/motion
${CNC_SIM_LINUXCNC_ROOT_ABS}/include
${CMAKE_CURRENT_SOURCE_DIR}/wasm_shims
)
if(EMSCRIPTEN)
target_compile_definitions(cnc_sim_objects PRIVATE FMT_HEADER_ONLY=1)
endif()
endif()
if(CNC_SIM_ENABLE_LINUXCNC_WASM_SAFE_PROBE)
add_executable(cnc_sim_wasm_runtime_probe EXCLUDE_FROM_ALL
$<TARGET_OBJECTS:linuxcnc_rs274_wasm_safe_probe_objects>
$<TARGET_OBJECTS:cnc_sim_objects>
${cnc_sim_wasm_runtime_probe_main}
)
target_compile_features(cnc_sim_wasm_runtime_probe PRIVATE cxx_std_20)
target_compile_definitions(cnc_sim_wasm_runtime_probe PRIVATE ULAPI)
target_compile_options(cnc_sim_wasm_runtime_probe PRIVATE ${cnc_sim_wasm_safe_preinclude_options})
target_include_directories(cnc_sim_wasm_runtime_probe
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/include
${CMAKE_CURRENT_SOURCE_DIR}/src
${CMAKE_CURRENT_SOURCE_DIR}/wasm_shims
${CNC_SIM_LINUXCNC_ROOT_ABS}/src
${CNC_SIM_LINUXCNC_ROOT_ABS}/src/emc
${CNC_SIM_LINUXCNC_ROOT_ABS}/src/emc/nml_intf
${CNC_SIM_LINUXCNC_ROOT_ABS}/src/emc/rs274ngc
${CNC_SIM_LINUXCNC_ROOT_ABS}/src/emc/motion
${CNC_SIM_LINUXCNC_ROOT_ABS}/include
)
if(EMSCRIPTEN)
target_compile_definitions(cnc_sim_wasm_runtime_probe PRIVATE FMT_HEADER_ONLY=1)
else()
target_link_libraries(cnc_sim_wasm_runtime_probe PRIVATE fmt)
endif()
endif()
if(CNC_SIM_ENABLE_SMOKE_BACKEND)
target_compile_definitions(cnc_sim_objects
PRIVATE
CNC_SIM_ENABLE_SMOKE_BACKEND
)
endif()
add_library(cnc_sim_core STATIC
$<TARGET_OBJECTS:cnc_sim_objects>
)
@@ -225,11 +434,13 @@ if(CNC_SIM_ENABLE_LINUXCNC_RS274_BACKEND)
endif()
if(NOT EMSCRIPTEN)
if(CNC_SIM_ENABLE_SMOKE_BACKEND)
add_executable(cnc_sim_api_smoke
tests/cnc_sim_api_smoke.cpp
)
target_link_libraries(cnc_sim_api_smoke PRIVATE cnc_sim_core)
target_include_directories(cnc_sim_api_smoke PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src)
endif()
add_executable(canon_event_sink_smoke
tests/canon_event_sink_smoke.cpp
@@ -254,11 +465,13 @@ if(NOT EMSCRIPTEN)
target_link_libraries(simulator_gcode_controls_smoke PRIVATE cnc_sim_core)
target_include_directories(simulator_gcode_controls_smoke PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src)
if(CNC_SIM_ENABLE_SMOKE_BACKEND)
add_executable(cnc_sim_dump
tools/cnc_sim_dump.cpp
)
target_link_libraries(cnc_sim_dump PRIVATE cnc_sim_core)
target_include_directories(cnc_sim_dump PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src)
endif()
if(CNC_SIM_ENABLE_LINUXCNC_RS274_BACKEND)
add_executable(cnc_sim_api_linuxcnc_rs274_smoke
@@ -298,7 +511,11 @@ if(CNC_SIM_ENABLE_LINUXCNC_BRIDGE)
endif()
if(EMSCRIPTEN)
if(NOT CNC_SIM_ENABLE_LINUXCNC_WASM_SAFE_PROBE)
message(FATAL_ERROR "WASM builds must enable CNC_SIM_ENABLE_LINUXCNC_WASM_SAFE_PROBE so LinuxCNC rs274 sources are linked")
endif()
add_executable(cnc_sim_wasm
$<TARGET_OBJECTS:linuxcnc_rs274_wasm_safe_probe_objects>
$<TARGET_OBJECTS:cnc_sim_objects>
)
@@ -306,7 +523,15 @@ if(EMSCRIPTEN)
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/include
${CMAKE_CURRENT_SOURCE_DIR}/src
${CMAKE_CURRENT_SOURCE_DIR}/wasm_shims
${CNC_SIM_LINUXCNC_ROOT_ABS}/src
${CNC_SIM_LINUXCNC_ROOT_ABS}/src/emc
${CNC_SIM_LINUXCNC_ROOT_ABS}/src/emc/nml_intf
${CNC_SIM_LINUXCNC_ROOT_ABS}/src/emc/rs274ngc
${CNC_SIM_LINUXCNC_ROOT_ABS}/src/emc/motion
${CNC_SIM_LINUXCNC_ROOT_ABS}/include
)
target_compile_definitions(cnc_sim_wasm PRIVATE FMT_HEADER_ONLY=1)
set_target_properties(cnc_sim_wasm PROPERTIES
OUTPUT_NAME "cnc_sim"

View File

@@ -88,6 +88,13 @@ void CanonEventSink::configure_fiveaxis(double pivot_length, int kinematics_type
fiveaxis_kinematics_type_ = kinematics_type;
}
void CanonEventSink::configure_switchkins_remap(int m428_type, int m429_type, int m430_type) {
switchkins_remap_configured_ = true;
switchkins_m428_type_ = m428_type;
switchkins_m429_type_ = m429_type;
switchkins_m430_type_ = m430_type;
}
void CanonEventSink::set_tool_length(int h_code, double tool_length) {
if (h_code <= 0) {
default_rtcp_tool_length_ = tool_length;
@@ -151,24 +158,59 @@ void CanonEventSink::switch_kinematics(int kinematics_type, int line) {
emit(event);
}
void CanonEventSink::switch_m_code_kinematics(int m_code, int default_kinematics_type, int line) {
bool CanonEventSink::can_switch_m_code_kinematics(int m_code) const {
if (!switchkins_remap_configured_) {
return true;
}
if (m_code == 428) {
return switchkins_m428_type_ >= 0;
}
if (m_code == 429) {
return switchkins_m429_type_ >= 0;
}
if (m_code == 430) {
return switchkins_m430_type_ >= 0;
}
return true;
}
bool CanonEventSink::switch_m_code_kinematics(int m_code, int default_kinematics_type, int line) {
if (switchkins_remap_configured_) {
int kinematics_type = -1;
if (m_code == 428) {
kinematics_type = switchkins_m428_type_;
} else if (m_code == 429) {
kinematics_type = switchkins_m429_type_;
} else if (m_code == 430) {
kinematics_type = switchkins_m430_type_;
}
if (kinematics_type >= 0) {
switch_kinematics(kinematics_type, line);
return true;
}
return false;
}
if (fiveaxis_configured_) {
// Source: linuxcnc/configs/sim/axis/vismach/5axis/bridgemill/remap_subs/{428,429,430}remap.ngc
// M428 selects 5axiskins type 0, M429 selects identity type 1, M430 selects userk type 2.
// Sources:
// - linuxcnc/configs/sim/axis/vismach/5axis/bridgemill/remap_subs/{428,429,430}remap.ngc
// - linuxcnc/configs/sim/axis/vismach/scara/remap_subs/{428,429,430}remap.ngc
// - linuxcnc/configs/sim/axis/vismach/melfa-sim/remap_subs/{428,429,430}remap.ngc
// These remaps select kinstype 0, 1, and 2 respectively.
if (m_code == 428) {
switch_kinematics(0, line);
return;
return true;
}
if (m_code == 429) {
switch_kinematics(1, line);
return;
return true;
}
if (m_code == 430) {
switch_kinematics(2, line);
return;
return true;
}
}
switch_kinematics(default_kinematics_type, line);
return true;
}
void CanonEventSink::set_g5x_offset(int index, const CncSimPose &offset, int line) {

View File

@@ -16,12 +16,14 @@ public:
void configure_xyzbc_trt(const LinuxCncXyzbcTrtParameters &parameters);
void configure_xyzac_trt(const LinuxCncXyzbcTrtParameters &parameters);
void configure_fiveaxis(double pivot_length, int kinematics_type);
void configure_switchkins_remap(int m428_type, int m429_type, int m430_type);
void set_tool_length(int h_code, double tool_length);
void set_tool_length_offset(const CncSimPose &offset);
void apply_tool_length_offset(const CncSimPose &offset);
void set_rtcp_state(bool enabled, int h_code, int line);
void switch_kinematics(int kinematics_type, int line);
void switch_m_code_kinematics(int m_code, int default_kinematics_type, int line);
bool can_switch_m_code_kinematics(int m_code) const;
bool switch_m_code_kinematics(int m_code, int default_kinematics_type, int line);
void set_g5x_offset(int index, const CncSimPose &offset, int line);
void set_g92_offset(const CncSimPose &offset, int line);
void set_xy_rotation(double angle_degrees, int line);
@@ -108,6 +110,10 @@ private:
bool fiveaxis_configured_ = false;
double fiveaxis_pivot_length_ = 250.0;
int fiveaxis_kinematics_type_ = 0;
bool switchkins_remap_configured_ = false;
int switchkins_m428_type_ = 1;
int switchkins_m429_type_ = 0;
int switchkins_m430_type_ = 2;
CncSimPose tool_length_offset_{};
double xy_rotation_degrees_ = 0.0;
int kinematics_type_ = 0;

View File

@@ -4,16 +4,13 @@
#include <algorithm>
#include <cctype>
#include <cstring>
#include <cstdlib>
#include <string>
struct CncSimHandle {
CncSimDialect dialect = CNC_SIM_DIALECT_LINUXCNC;
#ifdef CNC_SIM_ENABLE_LINUXCNC_RS274_BACKEND
GcodeBackendKind backend = GcodeBackendKind::LinuxCncRs274;
#else
GcodeBackendKind backend = GcodeBackendKind::Smoke;
#endif
std::string last_error;
CanonEventSink sink;
};
@@ -77,6 +74,40 @@ bool contains_bool_value(const std::string &compact, const char *key, bool *valu
return false;
}
bool contains_string_value(const std::string &compact, const char *key, const char *value) {
const std::string quoted_needle = std::string("\"") + key + "\":\"" + value + "\"";
if (compact.find(quoted_needle) != std::string::npos) {
return true;
}
const std::string prefix_needle = std::string("\"") + key + "\":\"";
size_t pos = 0;
while ((pos = compact.find(prefix_needle, pos)) != std::string::npos) {
pos += prefix_needle.size();
const size_t end = compact.find('"', pos);
if (end == std::string::npos) {
return false;
}
const std::string field_value = compact.substr(pos, end - pos);
if (field_value.find(value) != std::string::npos) {
return true;
}
pos = end + 1;
}
return false;
}
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) ||
contains_string_value(compact, "machine", alias) ||
contains_string_value(compact, "kinematics", alias) ||
contains_string_value(compact, "halfile", alias) ||
contains_string_value(compact, "hal_file", alias) ||
contains_string_value(compact, "config", alias) ||
contains_string_value(compact, "configpath", alias) ||
contains_string_value(compact, "config_path", alias);
}
bool find_number_value(const std::string &compact, const char *key, double *value) {
const std::string needle = std::string("\"") + key + "\":";
const size_t pos = compact.find(needle);
@@ -212,6 +243,38 @@ void apply_fiveaxis_config(CanonEventSink &sink, const std::string &compact) {
}
}
void apply_switchkins_remap_config(CanonEventSink &sink, const std::string &compact) {
struct RemapSource {
const char *alias;
int m428_type;
int m429_type;
int m430_type;
};
// Generated from LinuxCNC INI REMAP/SUBROUTINE_PATH entries and the
// adjacent remap_subs #<kinstype> assignments.
static constexpr RemapSource kSources[] = {
#include "linuxcnc_switchkins_remap_table.inc"
};
const RemapSource *matched_source = nullptr;
size_t matched_alias_length = 0;
for (const RemapSource &source : kSources) {
if (contains_switchkins_config_alias(compact, source.alias)) {
const size_t alias_length = std::strlen(source.alias);
if (alias_length > matched_alias_length) {
matched_source = &source;
matched_alias_length = alias_length;
}
}
}
if (matched_source) {
sink.configure_switchkins_remap(matched_source->m428_type,
matched_source->m429_type,
matched_source->m430_type);
}
}
int apply_config(CncSimHandle *handle, const std::string &json) {
if (json.empty()) {
return 0;
@@ -242,6 +305,7 @@ int apply_config(CncSimHandle *handle, const std::string &json) {
handle->sink.set_block_delete(block_delete);
}
apply_tool_length_table(handle->sink, compact);
apply_switchkins_remap_config(handle->sink, compact);
apply_xyzbc_trt_config(handle->sink, compact);
apply_fiveaxis_config(handle->sink, compact);
return 0;

View File

@@ -3,7 +3,9 @@
#ifdef CNC_SIM_ENABLE_LINUXCNC_RS274_BACKEND
#include "linuxcnc_rs274_backend.h"
#endif
#ifdef CNC_SIM_ENABLE_SMOKE_BACKEND
#include "smoke_gcode_parser.h"
#endif
const char *gcode_backend_name(GcodeBackendKind backend) {
switch (backend) {
@@ -23,8 +25,15 @@ int parse_gcode_with_backend(GcodeBackendKind backend,
std::string *error) {
switch (backend) {
case GcodeBackendKind::Smoke: {
#ifdef CNC_SIM_ENABLE_SMOKE_BACKEND
SmokeGcodeParser parser(sink);
return parser.parse(program, program_len, error);
#else
if (error) {
*error = "smoke backend is not compiled into this build";
}
return -1;
#endif
}
case GcodeBackendKind::LinuxCncRs274:
#ifdef CNC_SIM_ENABLE_LINUXCNC_RS274_BACKEND

View File

@@ -0,0 +1,266 @@
#include <ctype.h>
#include <math.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define __LINUXCNC_RTAPI_H
#define __LINUXCNC_RTAPI_MATH_H
#define __LINUXCNC_RTAPI_STRING_H
#define __LINUXCNC_RTAPI_CTYPE_H
#define __LINUXCNC_HAL_H
#define __LINUXCNC_EMCMOTCFG_H
#define __LINUXCNC_KINEMATICS_H
#define SWITCHKINS_H
#define RTAPI_MSG_ERR 1
#define PM_PI 3.1415926535897932384626433832795029
#define TO_RAD (PM_PI / 180.0)
#define EMCMOT_MAX_JOINTS 16
#define EMCMOT_MAX_AXIS 9
typedef double real_t;
typedef double hal_float_t;
typedef int hal_s32_t;
typedef bool hal_bit_t;
typedef enum { HAL_IN = 16, HAL_OUT = 32, HAL_IO = (HAL_IN | HAL_OUT) } hal_pin_dir_t;
typedef struct {
double x;
double y;
double z;
} PmCartesian;
typedef struct EmcPose {
PmCartesian tran;
double a;
double b;
double c;
double u;
double v;
double w;
} EmcPose;
typedef unsigned long int KINEMATICS_FORWARD_FLAGS;
typedef unsigned long int KINEMATICS_INVERSE_FLAGS;
typedef struct kinematics_parms {
char *sparm;
char *kinsname;
char *halprefix;
char *required_coordinates;
int max_joints;
int allow_duplicates;
int fwd_iterates_mask;
int gui_kinstype;
} kparms;
typedef int (*KF)(const double *joint,
EmcPose *pos,
const KINEMATICS_FORWARD_FLAGS *fflags,
KINEMATICS_INVERSE_FLAGS *iflags);
typedef int (*KI)(const struct EmcPose *world,
double *joint,
const KINEMATICS_INVERSE_FLAGS *iflags,
KINEMATICS_FORWARD_FLAGS *fflags);
typedef int (*KS)(const int comp_id, const char *coordinates, kparms *ksetup_parms);
#ifdef __cplusplus
extern "C" {
#endif
static int cnc_sim_axis_idx_for_jno[EMCMOT_MAX_JOINTS];
static int cnc_sim_max_joints;
void cnc_sim_5axis_rtapi_print(const char *fmt, ...) {
(void)fmt;
}
void cnc_sim_5axis_rtapi_print_msg(int level, const char *fmt, ...) {
(void)level;
(void)fmt;
}
void *cnc_sim_5axis_hal_malloc(long int size) {
return calloc(1, (size_t)size);
}
int cnc_sim_5axis_hal_pin_float_newf(hal_pin_dir_t dir,
hal_float_t **data_ptr_addr,
int comp_id,
const char *fmt,
...) {
(void)dir;
(void)comp_id;
(void)fmt;
*data_ptr_addr = (hal_float_t *)calloc(1, sizeof(hal_float_t));
return *data_ptr_addr ? 0 : -1;
}
int cnc_sim_5axis_map_coordinates_to_jnumbers(const char *coordinates,
const int max_joints,
const int allow_duplicates,
int axis_idx_for_jno[]) {
(void)allow_duplicates;
const char *letters = "XYZABCUVW";
int jno = 0;
for (int i = 0; i < EMCMOT_MAX_JOINTS; ++i) {
axis_idx_for_jno[i] = -1;
cnc_sim_axis_idx_for_jno[i] = -1;
}
while (*coordinates) {
const char *found = strchr(letters, toupper((unsigned char)*coordinates));
if (!found || jno >= max_joints) {
return -1;
}
axis_idx_for_jno[jno++] = (int)(found - letters);
++coordinates;
}
cnc_sim_max_joints = jno;
for (int i = 0; i < EMCMOT_MAX_JOINTS; ++i) {
cnc_sim_axis_idx_for_jno[i] = axis_idx_for_jno[i];
}
return 0;
}
int cnc_sim_5axis_position_to_mapped_joints(const int max_joints, const EmcPose *pos, double *joints) {
for (int jno = 0; jno < max_joints; ++jno) {
switch (cnc_sim_axis_idx_for_jno[jno]) {
case 0: joints[jno] = pos->tran.x; break;
case 1: joints[jno] = pos->tran.y; break;
case 2: joints[jno] = pos->tran.z; break;
case 3: joints[jno] = pos->a; break;
case 4: joints[jno] = pos->b; break;
case 5: joints[jno] = pos->c; break;
case 6: joints[jno] = pos->u; break;
case 7: joints[jno] = pos->v; break;
case 8: joints[jno] = pos->w; break;
default: joints[jno] = 0.0; break;
}
}
return 0;
}
int cnc_sim_5axis_identityKinematicsSetup(const int comp_id, const char *coordinates, kparms *ksetup_parms) {
(void)comp_id;
(void)coordinates;
(void)ksetup_parms;
return 0;
}
int cnc_sim_5axis_identityKinematicsForward(const double *joint,
EmcPose *world,
const KINEMATICS_FORWARD_FLAGS *fflags,
KINEMATICS_INVERSE_FLAGS *iflags) {
(void)joint;
(void)world;
(void)fflags;
(void)iflags;
return -1;
}
int cnc_sim_5axis_identityKinematicsInverse(const EmcPose *world,
double *joint,
const KINEMATICS_INVERSE_FLAGS *iflags,
KINEMATICS_FORWARD_FLAGS *fflags) {
(void)world;
(void)joint;
(void)iflags;
(void)fflags;
return -1;
}
int cnc_sim_5axis_userkKinematicsSetup(const int comp_id, const char *coordinates, kparms *ksetup_parms) {
(void)comp_id;
(void)coordinates;
(void)ksetup_parms;
return -1;
}
int cnc_sim_5axis_userkKinematicsForward(const double *joint,
EmcPose *world,
const KINEMATICS_FORWARD_FLAGS *fflags,
KINEMATICS_INVERSE_FLAGS *iflags) {
(void)joint;
(void)world;
(void)fflags;
(void)iflags;
return -1;
}
int cnc_sim_5axis_userkKinematicsInverse(const EmcPose *pos,
double *joint,
const KINEMATICS_INVERSE_FLAGS *iflags,
KINEMATICS_FORWARD_FLAGS *fflags) {
(void)pos;
(void)joint;
(void)iflags;
(void)fflags;
return -1;
}
#define rtapi_print cnc_sim_5axis_rtapi_print
#define rtapi_print_msg cnc_sim_5axis_rtapi_print_msg
#define hal_pin_float_newf cnc_sim_5axis_hal_pin_float_newf
#define map_coordinates_to_jnumbers cnc_sim_5axis_map_coordinates_to_jnumbers
#define position_to_mapped_joints cnc_sim_5axis_position_to_mapped_joints
#define identityKinematicsSetup cnc_sim_5axis_identityKinematicsSetup
#define identityKinematicsForward cnc_sim_5axis_identityKinematicsForward
#define identityKinematicsInverse cnc_sim_5axis_identityKinematicsInverse
#define userkKinematicsSetup cnc_sim_5axis_userkKinematicsSetup
#define userkKinematicsForward cnc_sim_5axis_userkKinematicsForward
#define userkKinematicsInverse cnc_sim_5axis_userkKinematicsInverse
#define switchkinsSetup cnc_sim_5axis_switchkinsSetup
#define haldata cnc_sim_5axis_haldata
#define hal_malloc(size) ((struct haldata *)cnc_sim_5axis_hal_malloc(size))
#include "../../../linuxcnc/src/emc/kinematics/5axiskins.c"
#undef hal_malloc
#undef haldata
#undef switchkinsSetup
#undef userkKinematicsInverse
#undef userkKinematicsForward
#undef userkKinematicsSetup
#undef identityKinematicsInverse
#undef identityKinematicsForward
#undef identityKinematicsSetup
#undef position_to_mapped_joints
#undef map_coordinates_to_jnumbers
#undef hal_pin_float_newf
#undef rtapi_print_msg
#undef rtapi_print
int cnc_sim_linuxcnc_5axiskins_setup(void) {
kparms kp = {0};
static char kinsname[] = "5axiskins";
static char halprefix[] = "5axiskins";
static char required_coordinates[] = "XYZBCW";
kp.kinsname = kinsname;
kp.halprefix = halprefix;
kp.required_coordinates = required_coordinates;
kp.max_joints = EMCMOT_MAX_JOINTS;
kp.allow_duplicates = 1;
return fiveaxis_KinematicsSetup(0, "XYZBCW", &kp);
}
void cnc_sim_linuxcnc_5axiskins_set_pivot_length(double pivot_length) {
*cnc_sim_5axis_haldata->pivot_length = pivot_length;
}
int cnc_sim_linuxcnc_5axiskins_forward(const double *joints, EmcPose *pos) {
KINEMATICS_FORWARD_FLAGS fflags = 0;
KINEMATICS_INVERSE_FLAGS iflags = 0;
return fiveaxis_KinematicsForward(joints, pos, &fflags, &iflags);
}
int cnc_sim_linuxcnc_5axiskins_inverse(const EmcPose *pos, double *joints) {
KINEMATICS_INVERSE_FLAGS iflags = 0;
KINEMATICS_FORWARD_FLAGS fflags = 0;
return fiveaxis_KinematicsInverse(pos, joints, &iflags, &fflags);
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,122 @@
#include "linuxcnc_5axiskins_adapter.h"
#include <cstring>
extern "C" {
struct PmCartesian {
double x;
double y;
double z;
};
struct EmcPose {
PmCartesian tran;
double a;
double b;
double c;
double u;
double v;
double w;
};
int cnc_sim_linuxcnc_5axiskins_setup(void);
void cnc_sim_linuxcnc_5axiskins_set_pivot_length(double pivot_length);
int cnc_sim_linuxcnc_5axiskins_forward(const double *joints, EmcPose *pos);
int cnc_sim_linuxcnc_5axiskins_inverse(const EmcPose *pos, double *joints);
}
namespace {
bool initialized = false;
bool ensure_initialized() {
if (initialized) {
return true;
}
initialized = cnc_sim_linuxcnc_5axiskins_setup() == 0;
return initialized;
}
void to_joints(const LinuxCncFiveAxisJoints &joints, double out[16]) {
std::memset(out, 0, sizeof(double) * 16);
out[0] = joints.x;
out[1] = joints.y;
out[2] = joints.z;
out[3] = joints.b;
out[4] = joints.c;
out[5] = joints.w;
}
LinuxCncFiveAxisJoints from_joints(const double joints[16]) {
LinuxCncFiveAxisJoints out{};
out.x = joints[0];
out.y = joints[1];
out.z = joints[2];
out.b = joints[3];
out.c = joints[4];
out.w = joints[5];
return out;
}
EmcPose to_emc_pose(const CncSimPose &pose) {
EmcPose emc{};
emc.tran.x = pose.x;
emc.tran.y = pose.y;
emc.tran.z = pose.z;
emc.a = pose.a;
emc.b = pose.b;
emc.c = pose.c;
emc.u = pose.u;
emc.v = pose.v;
emc.w = pose.w;
return emc;
}
CncSimPose from_emc_pose(const EmcPose &emc) {
CncSimPose pose{};
pose.x = emc.tran.x;
pose.y = emc.tran.y;
pose.z = emc.tran.z;
pose.a = emc.a;
pose.b = emc.b;
pose.c = emc.c;
pose.u = emc.u;
pose.v = emc.v;
pose.w = emc.w;
return pose;
}
} // namespace
bool linuxcnc_5axiskins_forward(const LinuxCncFiveAxisJoints &joints,
double pivot_length,
CncSimPose *pose) {
if (!ensure_initialized()) {
return false;
}
cnc_sim_linuxcnc_5axiskins_set_pivot_length(pivot_length);
double raw_joints[16];
to_joints(joints, raw_joints);
EmcPose out{};
if (cnc_sim_linuxcnc_5axiskins_forward(raw_joints, &out) != 0) {
return false;
}
*pose = from_emc_pose(out);
return true;
}
bool linuxcnc_5axiskins_inverse(const CncSimPose &pose,
double pivot_length,
LinuxCncFiveAxisJoints *joints) {
if (!ensure_initialized()) {
return false;
}
cnc_sim_linuxcnc_5axiskins_set_pivot_length(pivot_length);
const EmcPose in = to_emc_pose(pose);
double raw_joints[16] = {};
if (cnc_sim_linuxcnc_5axiskins_inverse(&in, raw_joints) != 0) {
return false;
}
*joints = from_joints(raw_joints);
return true;
}

View File

@@ -0,0 +1,10 @@
#pragma once
#include "rtcp_kinematics.h"
bool linuxcnc_5axiskins_forward(const LinuxCncFiveAxisJoints &joints,
double pivot_length,
CncSimPose *pose);
bool linuxcnc_5axiskins_inverse(const CncSimPose &pose,
double pivot_length,
LinuxCncFiveAxisJoints *joints);

View File

@@ -0,0 +1,127 @@
#include <stdarg.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdlib.h>
#define __LINUXCNC_RTAPI_H
#define __LINUXCNC_RTAPI_APP_H
#define __LINUXCNC_RTAPI_MATH_H
#define __LINUXCNC_RTAPI_STRING_H
#define __LINUXCNC_HAL_H
#define __LINUXCNC_EMCMOTCFG_H
#define __LINUXCNC_KINEMATICS_H
#define MODULE_LICENSE(...)
#define EXPORT_SYMBOL(symbol)
#define RTAPI_MSG_ERR 1
#define EMCMOT_MAX_JOINTS 16
typedef int hal_s32_t;
typedef struct {
double x;
double y;
double z;
} PmCartesian;
typedef struct EmcPose {
PmCartesian tran;
double a;
double b;
double c;
double u;
double v;
double w;
} EmcPose;
typedef enum {
KINEMATICS_IDENTITY = 1,
KINEMATICS_FORWARD_ONLY,
KINEMATICS_INVERSE_ONLY,
KINEMATICS_BOTH
} KINEMATICS_TYPE;
typedef unsigned long int KINEMATICS_FORWARD_FLAGS;
typedef unsigned long int KINEMATICS_INVERSE_FLAGS;
typedef struct kinematics_parms {
char *sparm;
char *kinsname;
char *halprefix;
char *required_coordinates;
int max_joints;
int allow_duplicates;
int fwd_iterates_mask;
int gui_kinstype;
} kparms;
#define KINS_NOT_SWITCHABLE \
extern int kinematicsSwitchable() { return 0; } \
extern int kinematicsSwitch(int switchkins_type) { (void)switchkins_type; return 0; }
#ifdef __cplusplus
extern "C" {
#endif
int cnc_sim_corexykins_hal_init(const char *name) {
(void)name;
return 1;
}
void *cnc_sim_corexykins_hal_malloc(long int size) {
return calloc(1, (size_t)size);
}
int cnc_sim_corexykins_hal_ready(int comp_id) {
(void)comp_id;
return 0;
}
void cnc_sim_corexykins_hal_exit(int comp_id) {
(void)comp_id;
}
#define hal_init cnc_sim_corexykins_hal_init
#define hal_malloc(size) ((struct data *)cnc_sim_corexykins_hal_malloc(size))
#define hal_ready cnc_sim_corexykins_hal_ready
#define hal_exit cnc_sim_corexykins_hal_exit
#define kinematicsType cnc_sim_corexykins_kinematicsType
#define kinematicsForward cnc_sim_corexykins_kinematicsForward
#define kinematicsInverse cnc_sim_corexykins_kinematicsInverse
#define kinematicsHome cnc_sim_corexykins_kinematicsHome
#define kinematicsSwitchable cnc_sim_corexykins_kinematicsSwitchable
#define kinematicsSwitch cnc_sim_corexykins_kinematicsSwitch
#define rtapi_app_main cnc_sim_corexykins_rtapi_app_main
#define rtapi_app_exit cnc_sim_corexykins_rtapi_app_exit
#define comp_id cnc_sim_corexykins_comp_id
#define data cnc_sim_corexykins_data
#include "../../../linuxcnc/src/emc/kinematics/corexykins.c"
#undef data
#undef comp_id
#undef rtapi_app_exit
#undef rtapi_app_main
#undef kinematicsSwitch
#undef kinematicsSwitchable
#undef kinematicsHome
#undef kinematicsInverse
#undef kinematicsForward
#undef kinematicsType
#undef hal_exit
#undef hal_ready
#undef hal_malloc
#undef hal_init
int cnc_sim_linuxcnc_corexykins_forward(const double *joints, EmcPose *pos) {
KINEMATICS_FORWARD_FLAGS fflags = 0;
KINEMATICS_INVERSE_FLAGS iflags = 0;
return cnc_sim_corexykins_kinematicsForward(joints, pos, &fflags, &iflags);
}
int cnc_sim_linuxcnc_corexykins_inverse(const EmcPose *pos, double *joints) {
KINEMATICS_INVERSE_FLAGS iflags = 0;
KINEMATICS_FORWARD_FLAGS fflags = 0;
return cnc_sim_corexykins_kinematicsInverse(pos, joints, &iflags, &fflags);
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,104 @@
#include "linuxcnc_corexykins_adapter.h"
#include <cstring>
extern "C" {
struct PmCartesian {
double x;
double y;
double z;
};
struct EmcPose {
PmCartesian tran;
double a;
double b;
double c;
double u;
double v;
double w;
};
int cnc_sim_linuxcnc_corexykins_forward(const double *joints, EmcPose *pos);
int cnc_sim_linuxcnc_corexykins_inverse(const EmcPose *pos, double *joints);
}
namespace {
void to_joints(const LinuxCncAxisJoints &joints, double out[16]) {
std::memset(out, 0, sizeof(double) * 16);
out[0] = joints.x;
out[1] = joints.y;
out[2] = joints.z;
out[3] = joints.a;
out[4] = joints.b;
out[5] = joints.c;
out[6] = joints.u;
out[7] = joints.v;
out[8] = joints.w;
}
LinuxCncAxisJoints from_joints(const double joints[16]) {
LinuxCncAxisJoints out{};
out.x = joints[0];
out.y = joints[1];
out.z = joints[2];
out.a = joints[3];
out.b = joints[4];
out.c = joints[5];
out.u = joints[6];
out.v = joints[7];
out.w = joints[8];
return out;
}
EmcPose to_emc_pose(const CncSimPose &pose) {
EmcPose emc{};
emc.tran.x = pose.x;
emc.tran.y = pose.y;
emc.tran.z = pose.z;
emc.a = pose.a;
emc.b = pose.b;
emc.c = pose.c;
emc.u = pose.u;
emc.v = pose.v;
emc.w = pose.w;
return emc;
}
CncSimPose from_emc_pose(const EmcPose &emc) {
CncSimPose pose{};
pose.x = emc.tran.x;
pose.y = emc.tran.y;
pose.z = emc.tran.z;
pose.a = emc.a;
pose.b = emc.b;
pose.c = emc.c;
pose.u = emc.u;
pose.v = emc.v;
pose.w = emc.w;
return pose;
}
} // namespace
bool linuxcnc_corexykins_source_forward(const LinuxCncAxisJoints &joints, CncSimPose *pose) {
double raw_joints[16];
to_joints(joints, raw_joints);
EmcPose out{};
if (cnc_sim_linuxcnc_corexykins_forward(raw_joints, &out) != 0) {
return false;
}
*pose = from_emc_pose(out);
return true;
}
bool linuxcnc_corexykins_source_inverse(const CncSimPose &pose, LinuxCncAxisJoints *joints) {
const EmcPose in = to_emc_pose(pose);
double raw_joints[16] = {};
if (cnc_sim_linuxcnc_corexykins_inverse(&in, raw_joints) != 0) {
return false;
}
*joints = from_joints(raw_joints);
return true;
}

View File

@@ -0,0 +1,6 @@
#pragma once
#include "rtcp_kinematics.h"
bool linuxcnc_corexykins_source_forward(const LinuxCncAxisJoints &joints, CncSimPose *pose);
bool linuxcnc_corexykins_source_inverse(const CncSimPose &pose, LinuxCncAxisJoints *joints);

View File

@@ -0,0 +1,117 @@
#include <math.h>
#include <stdbool.h>
#include <stddef.h>
#define __LINUXCNC_RTAPI_MATH_H
typedef struct {
double a;
double b;
double c;
double d;
} CUBIC_COEFF;
typedef struct {
int configured;
double segmentTime;
int interpolationRate;
double interpolationTime;
double interpolationIncrement;
double x0, x1, x2, x3;
double wp0, wp1;
double velp0, velp1;
int filled;
int needNextPoint;
CUBIC_COEFF coeff;
} CUBIC_STRUCT;
#define CUBIC_H
#define cubicInit cnc_sim_cubic_cubicInit
#define cubicSetSegmentTime cnc_sim_cubic_cubicSetSegmentTime
#define cubicGetSegmentTime cnc_sim_cubic_cubicGetSegmentTime
#define cubicSetInterpolationRate cnc_sim_cubic_cubicSetInterpolationRate
#define cubicGetInterpolationRate cnc_sim_cubic_cubicGetInterpolationRate
#define cubicAddPoint cnc_sim_cubic_cubicAddPoint
#define cubicOffset cnc_sim_cubic_cubicOffset
#define cubicGetInterpolationIncrement cnc_sim_cubic_cubicGetInterpolationIncrement
#define cubicGetCubicCoeff cnc_sim_cubic_cubicGetCubicCoeff
#define cubicFilled cnc_sim_cubic_cubicFilled
#define cubicInterpolate cnc_sim_cubic_cubicInterpolate
#define cubicNeedNextPoint cnc_sim_cubic_cubicNeedNextPoint
#define cubicDrain cnc_sim_cubic_cubicDrain
int cubicInit(CUBIC_STRUCT *ci);
int cubicSetSegmentTime(CUBIC_STRUCT *ci, double time);
double cubicGetSegmentTime(CUBIC_STRUCT *ci);
int cubicSetInterpolationRate(CUBIC_STRUCT *ci, int rate);
int cubicGetInterpolationRate(CUBIC_STRUCT *ci);
int cubicAddPoint(CUBIC_STRUCT *ci, double point);
int cubicOffset(CUBIC_STRUCT *ci, double offset);
double cubicGetInterpolationIncrement(CUBIC_STRUCT *ci);
CUBIC_COEFF cubicGetCubicCoeff(CUBIC_STRUCT *ci);
int cubicFilled(CUBIC_STRUCT *ci);
double cubicInterpolate(CUBIC_STRUCT *ci, double *x, double *v, double *a, double *j);
int cubicNeedNextPoint(CUBIC_STRUCT *ci);
int cubicDrain(CUBIC_STRUCT *ci);
#include "../../../linuxcnc/src/emc/kinematics/cubic.c"
#undef cubicDrain
#undef cubicNeedNextPoint
#undef cubicInterpolate
#undef cubicFilled
#undef cubicGetCubicCoeff
#undef cubicGetInterpolationIncrement
#undef cubicOffset
#undef cubicAddPoint
#undef cubicGetInterpolationRate
#undef cubicSetInterpolationRate
#undef cubicGetSegmentTime
#undef cubicSetSegmentTime
#undef cubicInit
#undef CUBIC_H
#ifdef __cplusplus
extern "C" {
#endif
int cnc_sim_linuxcnc_cubic_second_segment_samples(double *x,
double *v,
double *a,
double *j,
int sample_count) {
if (!x || !v || !a || !j || sample_count != 4) {
return -1;
}
CUBIC_STRUCT cubic;
if (cnc_sim_cubic_cubicInit(&cubic) != 0 ||
cnc_sim_cubic_cubicSetSegmentTime(&cubic, 1.0) != 0 ||
cnc_sim_cubic_cubicSetInterpolationRate(&cubic, 4) != 0 ||
cnc_sim_cubic_cubicAddPoint(&cubic, 0.0) != 0) {
return -1;
}
for (int i = 0; i < 4; ++i) {
cnc_sim_cubic_cubicInterpolate(&cubic, NULL, NULL, NULL, NULL);
}
if (!cnc_sim_cubic_cubicNeedNextPoint(&cubic) ||
cnc_sim_cubic_cubicAddPoint(&cubic, 10.0) != 0) {
return -1;
}
for (int i = 0; i < sample_count; ++i) {
x[i] = cnc_sim_cubic_cubicInterpolate(&cubic, &x[i], &v[i], &a[i], &j[i]);
}
return cnc_sim_cubic_cubicNeedNextPoint(&cubic) ? 0 : -1;
}
int cnc_sim_linuxcnc_cubic_rejects_invalid_configuration(void) {
CUBIC_STRUCT cubic;
return cnc_sim_cubic_cubicInit(&cubic) == 0 &&
cnc_sim_cubic_cubicSetSegmentTime(&cubic, 0.0) != 0 &&
cnc_sim_cubic_cubicSetInterpolationRate(&cubic, 0) != 0 &&
cnc_sim_cubic_cubicAddPoint(&cubic, 1.0) != 0;
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,36 @@
#include "linuxcnc_cubic_adapter.h"
extern "C" {
int cnc_sim_linuxcnc_cubic_second_segment_samples(double *x,
double *v,
double *a,
double *j,
int sample_count);
int cnc_sim_linuxcnc_cubic_rejects_invalid_configuration(void);
}
bool linuxcnc_cubic_source_second_segment_samples(LinuxCncCubicSample *samples, int sample_count) {
if (!samples || sample_count != 4) {
return false;
}
double x[4] = {};
double v[4] = {};
double a[4] = {};
double j[4] = {};
if (cnc_sim_linuxcnc_cubic_second_segment_samples(x, v, a, j, sample_count) != 0) {
return false;
}
for (int i = 0; i < sample_count; ++i) {
samples[i].x = x[i];
samples[i].v = v[i];
samples[i].a = a[i];
samples[i].j = j[i];
}
return true;
}
bool linuxcnc_cubic_source_rejects_invalid_configuration() {
return cnc_sim_linuxcnc_cubic_rejects_invalid_configuration() != 0;
}

View File

@@ -0,0 +1,11 @@
#pragma once
struct LinuxCncCubicSample {
double x;
double v;
double a;
double j;
};
bool linuxcnc_cubic_source_second_segment_samples(LinuxCncCubicSample *samples, int sample_count);
bool linuxcnc_cubic_source_rejects_invalid_configuration();

View File

@@ -0,0 +1,223 @@
#include <math.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#define __LINUXCNC_RTAPI_H
#define __LINUXCNC_RTAPI_MATH_H
#define __LINUXCNC_RTAPI_STRING_H
#define __LINUXCNC_HAL_H
#define __LINUXCNC_EMCMOTCFG_H
#define __LINUXCNC_KINEMATICS_H
#define SWITCHKINS_H
#define RTAPI_MSG_ERR 1
#define RTAPI_MSG_INFO 2
#define EMCMOT_MAX_JOINTS 16
typedef double real_t;
typedef double hal_float_t;
typedef int hal_bit_t;
typedef uint32_t hal_u32_t;
typedef enum { HAL_IN = 16, HAL_OUT = 32, HAL_IO = (HAL_IN | HAL_OUT) } hal_pin_dir_t;
typedef unsigned long int KINEMATICS_FORWARD_FLAGS;
typedef unsigned long int KINEMATICS_INVERSE_FLAGS;
#include "../../../linuxcnc/src/libnml/posemath/posemath.h"
typedef struct EmcPose {
PmCartesian tran;
double a;
double b;
double c;
double u;
double v;
double w;
} EmcPose;
typedef struct kinematics_parms {
char *sparm;
char *kinsname;
char *halprefix;
char *required_coordinates;
int max_joints;
int allow_duplicates;
int fwd_iterates_mask;
int gui_kinstype;
} kparms;
typedef int (*KF)(const double *joint,
EmcPose *pos,
const KINEMATICS_FORWARD_FLAGS *fflags,
KINEMATICS_INVERSE_FLAGS *iflags);
typedef int (*KI)(const EmcPose *world,
double *joint,
const KINEMATICS_INVERSE_FLAGS *iflags,
KINEMATICS_FORWARD_FLAGS *fflags);
typedef int (*KS)(const int comp_id, const char *coordinates, kparms *ksetup_parms);
#ifdef __cplusplus
extern "C" {
#endif
void cnc_sim_genhex_rtapi_print_msg(int level, const char *fmt, ...) {
(void)level;
(void)fmt;
}
void *cnc_sim_genhex_hal_malloc(long int size) {
return calloc(1, (size_t)size);
}
int cnc_sim_genhex_hal_pin_float_newf(hal_pin_dir_t dir,
hal_float_t **data_ptr_addr,
int comp_id,
const char *fmt,
...) {
(void)dir;
(void)comp_id;
(void)fmt;
*data_ptr_addr = (hal_float_t *)calloc(1, sizeof(hal_float_t));
return *data_ptr_addr ? 0 : -1;
}
int cnc_sim_genhex_hal_pin_u32_newf(hal_pin_dir_t dir,
hal_u32_t **data_ptr_addr,
int comp_id,
const char *fmt,
...) {
(void)dir;
(void)comp_id;
(void)fmt;
*data_ptr_addr = (hal_u32_t *)calloc(1, sizeof(hal_u32_t));
return *data_ptr_addr ? 0 : -1;
}
int cnc_sim_genhex_hal_pin_bit_newf(hal_pin_dir_t dir,
hal_bit_t **data_ptr_addr,
int comp_id,
const char *fmt,
...) {
(void)dir;
(void)comp_id;
(void)fmt;
*data_ptr_addr = (hal_bit_t *)calloc(1, sizeof(hal_bit_t));
return *data_ptr_addr ? 0 : -1;
}
int cnc_sim_genhex_identityKinematicsSetup(const int comp_id, const char *coordinates, kparms *ksetup_parms) {
(void)comp_id;
(void)coordinates;
(void)ksetup_parms;
return 0;
}
int cnc_sim_genhex_identityKinematicsForward(const double *joint,
EmcPose *world,
const KINEMATICS_FORWARD_FLAGS *fflags,
KINEMATICS_INVERSE_FLAGS *iflags) {
(void)joint;
(void)world;
(void)fflags;
(void)iflags;
return -1;
}
int cnc_sim_genhex_identityKinematicsInverse(const EmcPose *world,
double *joint,
const KINEMATICS_INVERSE_FLAGS *iflags,
KINEMATICS_FORWARD_FLAGS *fflags) {
(void)world;
(void)joint;
(void)iflags;
(void)fflags;
return -1;
}
int cnc_sim_genhex_userkKinematicsSetup(const int comp_id, const char *coordinates, kparms *ksetup_parms) {
(void)comp_id;
(void)coordinates;
(void)ksetup_parms;
return -1;
}
int cnc_sim_genhex_userkKinematicsForward(const double *joint,
EmcPose *world,
const KINEMATICS_FORWARD_FLAGS *fflags,
KINEMATICS_INVERSE_FLAGS *iflags) {
(void)joint;
(void)world;
(void)fflags;
(void)iflags;
return -1;
}
int cnc_sim_genhex_userkKinematicsInverse(const EmcPose *world,
double *joint,
const KINEMATICS_INVERSE_FLAGS *iflags,
KINEMATICS_FORWARD_FLAGS *fflags) {
(void)world;
(void)joint;
(void)iflags;
(void)fflags;
return -1;
}
#define rtapi_print_msg cnc_sim_genhex_rtapi_print_msg
#define hal_pin_float_newf cnc_sim_genhex_hal_pin_float_newf
#define hal_pin_u32_newf cnc_sim_genhex_hal_pin_u32_newf
#define hal_pin_bit_newf cnc_sim_genhex_hal_pin_bit_newf
#define identityKinematicsSetup cnc_sim_genhex_identityKinematicsSetup
#define identityKinematicsForward cnc_sim_genhex_identityKinematicsForward
#define identityKinematicsInverse cnc_sim_genhex_identityKinematicsInverse
#define userkKinematicsSetup cnc_sim_genhex_userkKinematicsSetup
#define userkKinematicsForward cnc_sim_genhex_userkKinematicsForward
#define userkKinematicsInverse cnc_sim_genhex_userkKinematicsInverse
#define switchkinsSetup cnc_sim_genhex_switchkinsSetup
#define haldata cnc_sim_genhex_haldata
#define hal_malloc(size) ((struct haldata *)cnc_sim_genhex_hal_malloc(size))
#include "../../../linuxcnc/src/emc/kinematics/genhexkins.c"
#undef hal_malloc
#undef haldata
#undef switchkinsSetup
#undef userkKinematicsInverse
#undef userkKinematicsForward
#undef userkKinematicsSetup
#undef identityKinematicsInverse
#undef identityKinematicsForward
#undef identityKinematicsSetup
#undef hal_pin_bit_newf
#undef hal_pin_u32_newf
#undef hal_pin_float_newf
#undef rtapi_print_msg
int cnc_sim_linuxcnc_genhexkins_setup(void) {
kparms kp;
memset(&kp, 0, sizeof(kp));
static char kinsname[] = "genhexkins";
static char halprefix[] = "genhexkins";
kp.kinsname = kinsname;
kp.halprefix = halprefix;
kp.max_joints = NUM_STRUTS;
return genhexKinematicsSetup(0, "XYZABC", &kp);
}
int cnc_sim_linuxcnc_genhexkins_forward(const double *joints, EmcPose *pos) {
KINEMATICS_FORWARD_FLAGS fflags = 0;
KINEMATICS_INVERSE_FLAGS iflags = 0;
return genhexKinematicsForward(joints, pos, &fflags, &iflags);
}
int cnc_sim_linuxcnc_genhexkins_inverse(const EmcPose *pos, double *joints) {
KINEMATICS_INVERSE_FLAGS iflags = 0;
KINEMATICS_FORWARD_FLAGS fflags = 0;
return genhexKinematicsInverse(pos, joints, &iflags, &fflags);
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,96 @@
#include "linuxcnc_genhexkins_adapter.h"
#include <cstring>
extern "C" {
struct PmCartesian {
double x;
double y;
double z;
};
struct EmcPose {
PmCartesian tran;
double a;
double b;
double c;
double u;
double v;
double w;
};
int cnc_sim_linuxcnc_genhexkins_setup(void);
int cnc_sim_linuxcnc_genhexkins_forward(const double *joints, EmcPose *pos);
int cnc_sim_linuxcnc_genhexkins_inverse(const EmcPose *pos, double *joints);
}
namespace {
bool initialized = false;
bool ensure_initialized() {
if (initialized) {
return true;
}
initialized = cnc_sim_linuxcnc_genhexkins_setup() == 0;
return initialized;
}
EmcPose to_emc_pose(const CncSimPose &pose) {
EmcPose emc{};
emc.tran.x = pose.x;
emc.tran.y = pose.y;
emc.tran.z = pose.z;
emc.a = pose.a;
emc.b = pose.b;
emc.c = pose.c;
emc.u = pose.u;
emc.v = pose.v;
emc.w = pose.w;
return emc;
}
CncSimPose from_emc_pose(const EmcPose &emc) {
CncSimPose pose{};
pose.x = emc.tran.x;
pose.y = emc.tran.y;
pose.z = emc.tran.z;
pose.a = emc.a;
pose.b = emc.b;
pose.c = emc.c;
pose.u = emc.u;
pose.v = emc.v;
pose.w = emc.w;
return pose;
}
} // namespace
bool linuxcnc_genhexkins_source_forward(const LinuxCncGenhexJoints &joints,
const CncSimPose &initial_pose,
CncSimPose *pose) {
if (!ensure_initialized()) {
return false;
}
double raw_joints[6];
std::memcpy(raw_joints, joints.strut, sizeof(raw_joints));
EmcPose emc_pose = to_emc_pose(initial_pose);
if (cnc_sim_linuxcnc_genhexkins_forward(raw_joints, &emc_pose) != 0) {
return false;
}
*pose = from_emc_pose(emc_pose);
return true;
}
bool linuxcnc_genhexkins_source_inverse(const CncSimPose &pose, LinuxCncGenhexJoints *joints) {
if (!ensure_initialized()) {
return false;
}
const EmcPose emc_pose = to_emc_pose(pose);
double raw_joints[6] = {};
if (cnc_sim_linuxcnc_genhexkins_inverse(&emc_pose, raw_joints) != 0) {
return false;
}
std::memcpy(joints->strut, raw_joints, sizeof(raw_joints));
return true;
}

View File

@@ -0,0 +1,8 @@
#pragma once
#include "rtcp_kinematics.h"
bool linuxcnc_genhexkins_source_forward(const LinuxCncGenhexJoints &joints,
const CncSimPose &initial_pose,
CncSimPose *pose);
bool linuxcnc_genhexkins_source_inverse(const CncSimPose &pose, LinuxCncGenhexJoints *joints);

View File

@@ -0,0 +1,206 @@
#include <math.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define __LINUXCNC_RTAPI_H
#define __LINUXCNC_RTAPI_MATH_H
#define __LINUXCNC_RTAPI_STRING_H
#define __LINUXCNC_HAL_H
#define __LINUXCNC_KINEMATICS_H
#define RTAPI_MSG_ERR 1
#define PM_PI 3.1415926535897932384626433832795029
typedef double real_t;
typedef double hal_float_t;
typedef unsigned int hal_u32_t;
typedef int hal_s32_t;
typedef enum { HAL_IN = 16, HAL_OUT = 32, HAL_IO = (HAL_IN | HAL_OUT) } hal_pin_dir_t;
typedef struct {
double x;
double y;
double z;
} PmCartesian;
typedef struct EmcPose {
PmCartesian tran;
double a;
double b;
double c;
double u;
double v;
double w;
} EmcPose;
typedef unsigned long int KINEMATICS_FORWARD_FLAGS;
typedef unsigned long int KINEMATICS_INVERSE_FLAGS;
typedef struct kinematics_parms {
char *sparm;
char *kinsname;
char *halprefix;
char *required_coordinates;
int max_joints;
int allow_duplicates;
int fwd_iterates_mask;
int gui_kinstype;
} kparms;
#ifdef __cplusplus
extern "C" {
#endif
void cnc_sim_genser_rtapi_print(const char *fmt, ...) {
(void)fmt;
}
void cnc_sim_genser_rtapi_print_msg(int level, const char *fmt, ...) {
(void)level;
(void)fmt;
}
void *cnc_sim_genser_hal_malloc(long int size) {
return calloc(1, (size_t)size);
}
int cnc_sim_genser_hal_pin_float_newf(hal_pin_dir_t dir,
hal_float_t **data_ptr_addr,
int comp_id,
const char *fmt,
...) {
(void)dir;
(void)comp_id;
(void)fmt;
*data_ptr_addr = (hal_float_t *)calloc(1, sizeof(hal_float_t));
return *data_ptr_addr ? 0 : -1;
}
int cnc_sim_genser_hal_pin_u32_newf(hal_pin_dir_t dir,
hal_u32_t **data_ptr_addr,
int comp_id,
const char *fmt,
...) {
(void)dir;
(void)comp_id;
(void)fmt;
*data_ptr_addr = (hal_u32_t *)calloc(1, sizeof(hal_u32_t));
return *data_ptr_addr ? 0 : -1;
}
int cnc_sim_genser_hal_pin_s32_newf(hal_pin_dir_t dir,
hal_s32_t **data_ptr_addr,
int comp_id,
const char *fmt,
...) {
(void)dir;
(void)comp_id;
(void)fmt;
*data_ptr_addr = (hal_s32_t *)calloc(1, sizeof(hal_s32_t));
return *data_ptr_addr ? 0 : -1;
}
#define rtapi_print cnc_sim_genser_rtapi_print
#define rtapi_print_msg cnc_sim_genser_rtapi_print_msg
#define hal_pin_float_newf cnc_sim_genser_hal_pin_float_newf
#define hal_pin_u32_newf cnc_sim_genser_hal_pin_u32_newf
#define hal_pin_s32_newf cnc_sim_genser_hal_pin_s32_newf
#define pm_sincos cnc_sim_genser_pm_sincos
#include "../../../linuxcnc/src/libnml/posemath/sincos.c"
#include "../../../linuxcnc/src/libnml/posemath/gomath.c"
#define hal_malloc(size) cnc_sim_genser_hal_malloc(size)
#include "../../../linuxcnc/src/emc/kinematics/genserfuncs.c"
#undef hal_malloc
#undef pm_sincos
#undef hal_pin_s32_newf
#undef hal_pin_u32_newf
#undef hal_pin_float_newf
#undef rtapi_print_msg
#undef rtapi_print
int cnc_sim_linuxcnc_genserfuncs_setup(void) {
kparms kp = {0};
static char kinsname[] = "genserkins";
static char halprefix[] = "genserkins";
kp.kinsname = kinsname;
kp.halprefix = halprefix;
kp.max_joints = 6;
return genserKinematicsSetup(0, "XYZABC", &kp);
}
void cnc_sim_linuxcnc_genserfuncs_set_parameters(const double *a,
const double *alpha,
const double *d,
const int *unrotate,
int max_iterations) {
for (int i = 0; i < GENSER_MAX_JOINTS; ++i) {
*haldata->a[i] = a[i];
*haldata->alpha[i] = alpha[i];
*haldata->d[i] = d[i];
*haldata->unrotate[i] = unrotate[i];
}
*haldata->max_iterations = (hal_u32_t)max_iterations;
}
void cnc_sim_linuxcnc_genserfuncs_default_parameters(double *a,
double *alpha,
double *d,
int *unrotate,
int *max_iterations) {
const double default_a[GENSER_MAX_JOINTS] = {
DEFAULT_A1,
DEFAULT_A2,
DEFAULT_A3,
DEFAULT_A4,
DEFAULT_A5,
DEFAULT_A6,
};
const double default_alpha[GENSER_MAX_JOINTS] = {
DEFAULT_ALPHA1,
DEFAULT_ALPHA2,
DEFAULT_ALPHA3,
DEFAULT_ALPHA4,
DEFAULT_ALPHA5,
DEFAULT_ALPHA6,
};
const double default_d[GENSER_MAX_JOINTS] = {
DEFAULT_D1,
DEFAULT_D2,
DEFAULT_D3,
DEFAULT_D4,
DEFAULT_D5,
DEFAULT_D6,
};
for (int i = 0; i < GENSER_MAX_JOINTS; ++i) {
a[i] = default_a[i];
alpha[i] = default_alpha[i];
d[i] = default_d[i];
unrotate[i] = 0;
}
*max_iterations = GENSER_DEFAULT_MAX_ITERATIONS;
}
int cnc_sim_linuxcnc_genserfuncs_forward(const double *joints, EmcPose *pos) {
KINEMATICS_FORWARD_FLAGS fflags = 0;
KINEMATICS_INVERSE_FLAGS iflags = 0;
return genserKinematicsForward(joints, pos, &fflags, &iflags);
}
int cnc_sim_linuxcnc_genserfuncs_inverse(const EmcPose *pos, double *joints, int *iterations) {
KINEMATICS_INVERSE_FLAGS iflags = 0;
KINEMATICS_FORWARD_FLAGS fflags = 0;
const int result = genserKinematicsInverse(pos, joints, &iflags, &fflags);
if (iterations) {
*iterations = genser_kin_inv_iterations(KINS_PTR);
}
return result;
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,166 @@
#include "linuxcnc_genserfuncs_adapter.h"
#include <cstring>
extern "C" {
struct PmCartesian {
double x;
double y;
double z;
};
struct EmcPose {
PmCartesian tran;
double a;
double b;
double c;
double u;
double v;
double w;
};
int cnc_sim_linuxcnc_genserfuncs_setup(void);
void cnc_sim_linuxcnc_genserfuncs_set_parameters(const double *a,
const double *alpha,
const double *d,
const int *unrotate,
int max_iterations);
void cnc_sim_linuxcnc_genserfuncs_default_parameters(double *a,
double *alpha,
double *d,
int *unrotate,
int *max_iterations);
int cnc_sim_linuxcnc_genserfuncs_forward(const double *joints, EmcPose *pos);
int cnc_sim_linuxcnc_genserfuncs_inverse(const EmcPose *pos, double *joints, int *iterations);
}
namespace {
bool initialized = false;
bool ensure_initialized() {
if (initialized) {
return true;
}
initialized = cnc_sim_linuxcnc_genserfuncs_setup() == 0;
return initialized;
}
void apply_parameters(const LinuxCncGenserParameters &parameters, int max_iterations) {
cnc_sim_linuxcnc_genserfuncs_set_parameters(parameters.a,
parameters.alpha,
parameters.d,
parameters.unrotate,
max_iterations);
}
void to_joints(const LinuxCncAxisJoints &joints, double out[16]) {
std::memset(out, 0, sizeof(double) * 16);
out[0] = joints.x;
out[1] = joints.y;
out[2] = joints.z;
out[3] = joints.a;
out[4] = joints.b;
out[5] = joints.c;
out[6] = joints.u;
out[7] = joints.v;
out[8] = joints.w;
}
LinuxCncAxisJoints from_joints(const double joints[16]) {
LinuxCncAxisJoints out{};
out.x = joints[0];
out.y = joints[1];
out.z = joints[2];
out.a = joints[3];
out.b = joints[4];
out.c = joints[5];
out.u = joints[6];
out.v = joints[7];
out.w = joints[8];
return out;
}
EmcPose to_emc_pose(const CncSimPose &pose) {
EmcPose emc{};
emc.tran.x = pose.x;
emc.tran.y = pose.y;
emc.tran.z = pose.z;
emc.a = pose.a;
emc.b = pose.b;
emc.c = pose.c;
emc.u = pose.u;
emc.v = pose.v;
emc.w = pose.w;
return emc;
}
CncSimPose from_emc_pose(const EmcPose &emc) {
CncSimPose pose{};
pose.x = emc.tran.x;
pose.y = emc.tran.y;
pose.z = emc.tran.z;
pose.a = emc.a;
pose.b = emc.b;
pose.c = emc.c;
pose.u = emc.u;
pose.v = emc.v;
pose.w = emc.w;
return pose;
}
} // namespace
bool linuxcnc_genserfuncs_forward(const LinuxCncAxisJoints &joints,
const LinuxCncGenserParameters &parameters,
CncSimPose *pose) {
if (!ensure_initialized()) {
return false;
}
apply_parameters(parameters, 100);
double raw_joints[16];
to_joints(joints, raw_joints);
EmcPose out{};
if (cnc_sim_linuxcnc_genserfuncs_forward(raw_joints, &out) != 0) {
return false;
}
*pose = from_emc_pose(out);
return true;
}
bool linuxcnc_genserfuncs_source_default_parameters(LinuxCncGenserParameters *parameters,
int *max_iterations) {
if (!parameters) {
return false;
}
int raw_max_iterations = 0;
cnc_sim_linuxcnc_genserfuncs_default_parameters(parameters->a,
parameters->alpha,
parameters->d,
parameters->unrotate,
&raw_max_iterations);
if (max_iterations) {
*max_iterations = raw_max_iterations;
}
return true;
}
bool linuxcnc_genserfuncs_inverse(const CncSimPose &pose,
const LinuxCncAxisJoints &joint_estimate,
const LinuxCncGenserParameters &parameters,
int max_iterations,
LinuxCncAxisJoints *joints,
int *iterations) {
if (!ensure_initialized()) {
return false;
}
apply_parameters(parameters, max_iterations);
double raw_joints[16];
to_joints(joint_estimate, raw_joints);
const EmcPose in = to_emc_pose(pose);
if (cnc_sim_linuxcnc_genserfuncs_inverse(&in, raw_joints, iterations) != 0) {
return false;
}
*joints = from_joints(raw_joints);
return true;
}

View File

@@ -0,0 +1,15 @@
#pragma once
#include "rtcp_kinematics.h"
bool linuxcnc_genserfuncs_forward(const LinuxCncAxisJoints &joints,
const LinuxCncGenserParameters &parameters,
CncSimPose *pose);
bool linuxcnc_genserfuncs_source_default_parameters(LinuxCncGenserParameters *parameters,
int *max_iterations);
bool linuxcnc_genserfuncs_inverse(const CncSimPose &pose,
const LinuxCncAxisJoints &joint_estimate,
const LinuxCncGenserParameters &parameters,
int max_iterations,
LinuxCncAxisJoints *joints,
int *iterations);

View File

@@ -0,0 +1,116 @@
#include <ctype.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#define __LINUXCNC_RTAPI_H
#define __LINUXCNC_RTAPI_STRING_H
#define __LINUXCNC_EMCMOTCFG_H
#define __LINUXCNC_EMCPOS_H
#define __LINUXCNC_KINEMATICS_H
#define RTAPI_MSG_ERR 1
#define EMCMOT_MAX_JOINTS 16
#define EMCMOT_MAX_AXIS 9
typedef struct {
double x;
double y;
double z;
} PmCartesian;
typedef struct EmcPose {
PmCartesian tran;
double a;
double b;
double c;
double u;
double v;
double w;
} EmcPose;
typedef unsigned long int KINEMATICS_FORWARD_FLAGS;
typedef unsigned long int KINEMATICS_INVERSE_FLAGS;
typedef enum {
KINEMATICS_IDENTITY = 1,
KINEMATICS_FORWARD_ONLY,
KINEMATICS_INVERSE_ONLY,
KINEMATICS_BOTH
} KINEMATICS_TYPE;
typedef struct kinematics_parms {
char *sparm;
char *kinsname;
char *halprefix;
char *required_coordinates;
int max_joints;
int allow_duplicates;
int fwd_iterates_mask;
int gui_kinstype;
} kparms;
#ifdef __cplusplus
extern "C" {
#endif
void cnc_sim_kins_util_rtapi_print(const char *fmt, ...) {
(void)fmt;
}
void cnc_sim_kins_util_rtapi_print_msg(int level, const char *fmt, ...) {
(void)level;
(void)fmt;
}
KINEMATICS_TYPE kinematicsType(void) {
return KINEMATICS_BOTH;
}
#define rtapi_print cnc_sim_kins_util_rtapi_print
#define rtapi_print_msg cnc_sim_kins_util_rtapi_print_msg
#define map_coordinates_to_jnumbers cnc_sim_kins_util_map_coordinates_to_jnumbers
#define mapped_joints_to_position cnc_sim_kins_util_mapped_joints_to_position
#define position_to_mapped_joints cnc_sim_kins_util_position_to_mapped_joints
#define identityKinematicsSetup cnc_sim_kins_util_identityKinematicsSetup
#define identityKinematicsForward cnc_sim_kins_util_identityKinematicsForward
#define identityKinematicsInverse cnc_sim_kins_util_identityKinematicsInverse
#include "../../../linuxcnc/src/emc/kinematics/kins_util.c"
#undef identityKinematicsInverse
#undef identityKinematicsForward
#undef identityKinematicsSetup
#undef position_to_mapped_joints
#undef mapped_joints_to_position
#undef map_coordinates_to_jnumbers
#undef rtapi_print_msg
#undef rtapi_print
int cnc_sim_linuxcnc_kins_util_setup(void) {
kparms kp = {0};
static char kinsname[] = "kins_util_identity";
static char halprefix[] = "identity";
kp.kinsname = kinsname;
kp.halprefix = halprefix;
kp.max_joints = EMCMOT_MAX_JOINTS;
kp.allow_duplicates = 0;
return cnc_sim_kins_util_identityKinematicsSetup(0, "XYZABCUVW", &kp);
}
int cnc_sim_linuxcnc_kins_util_forward(const double *joints, EmcPose *pos) {
KINEMATICS_FORWARD_FLAGS fflags = 0;
KINEMATICS_INVERSE_FLAGS iflags = 0;
return cnc_sim_kins_util_identityKinematicsForward(joints, pos, &fflags, &iflags);
}
int cnc_sim_linuxcnc_kins_util_inverse(const EmcPose *pos, double *joints) {
KINEMATICS_INVERSE_FLAGS iflags = 0;
KINEMATICS_FORWARD_FLAGS fflags = 0;
return cnc_sim_kins_util_identityKinematicsInverse(pos, joints, &iflags, &fflags);
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,121 @@
#include "linuxcnc_kins_util_adapter.h"
#include <cstring>
extern "C" {
struct PmCartesian {
double x;
double y;
double z;
};
struct EmcPose {
PmCartesian tran;
double a;
double b;
double c;
double u;
double v;
double w;
};
int cnc_sim_linuxcnc_kins_util_setup(void);
int cnc_sim_linuxcnc_kins_util_forward(const double *joints, EmcPose *pos);
int cnc_sim_linuxcnc_kins_util_inverse(const EmcPose *pos, double *joints);
}
namespace {
bool initialized = false;
bool ensure_initialized() {
if (initialized) {
return true;
}
initialized = cnc_sim_linuxcnc_kins_util_setup() == 0;
return initialized;
}
void to_joints(const LinuxCncAxisJoints &joints, double out[16]) {
std::memset(out, 0, sizeof(double) * 16);
out[0] = joints.x;
out[1] = joints.y;
out[2] = joints.z;
out[3] = joints.a;
out[4] = joints.b;
out[5] = joints.c;
out[6] = joints.u;
out[7] = joints.v;
out[8] = joints.w;
}
LinuxCncAxisJoints from_joints(const double joints[16]) {
LinuxCncAxisJoints out{};
out.x = joints[0];
out.y = joints[1];
out.z = joints[2];
out.a = joints[3];
out.b = joints[4];
out.c = joints[5];
out.u = joints[6];
out.v = joints[7];
out.w = joints[8];
return out;
}
EmcPose to_emc_pose(const CncSimPose &pose) {
EmcPose emc{};
emc.tran.x = pose.x;
emc.tran.y = pose.y;
emc.tran.z = pose.z;
emc.a = pose.a;
emc.b = pose.b;
emc.c = pose.c;
emc.u = pose.u;
emc.v = pose.v;
emc.w = pose.w;
return emc;
}
CncSimPose from_emc_pose(const EmcPose &emc) {
CncSimPose pose{};
pose.x = emc.tran.x;
pose.y = emc.tran.y;
pose.z = emc.tran.z;
pose.a = emc.a;
pose.b = emc.b;
pose.c = emc.c;
pose.u = emc.u;
pose.v = emc.v;
pose.w = emc.w;
return pose;
}
} // namespace
bool linuxcnc_kins_util_identity_forward(const LinuxCncAxisJoints &joints, CncSimPose *pose) {
if (!ensure_initialized()) {
return false;
}
double raw_joints[16];
to_joints(joints, raw_joints);
EmcPose out{};
if (cnc_sim_linuxcnc_kins_util_forward(raw_joints, &out) != 0) {
return false;
}
*pose = from_emc_pose(out);
return true;
}
bool linuxcnc_kins_util_identity_inverse(const CncSimPose &pose, LinuxCncAxisJoints *joints) {
if (!ensure_initialized()) {
return false;
}
const EmcPose in = to_emc_pose(pose);
double raw_joints[16] = {};
if (cnc_sim_linuxcnc_kins_util_inverse(&in, raw_joints) != 0) {
return false;
}
*joints = from_joints(raw_joints);
return true;
}

View File

@@ -0,0 +1,6 @@
#pragma once
#include "rtcp_kinematics.h"
bool linuxcnc_kins_util_identity_forward(const LinuxCncAxisJoints &joints, CncSimPose *pose);
bool linuxcnc_kins_util_identity_inverse(const CncSimPose &pose, LinuxCncAxisJoints *joints);

View File

@@ -0,0 +1,155 @@
#include <math.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdlib.h>
#define __LINUXCNC_RTAPI_H
#define __LINUXCNC_RTAPI_MATH_H
#define __LINUXCNC_RTAPI_APP_H
#define __LINUXCNC_HAL_H
#define __LINUXCNC_KINEMATICS_H
#define __LINUXCNC_EMCPOS_H
#define MODULE_LICENSE(...)
#define EXPORT_SYMBOL(symbol)
#define EMCMOT_MAX_JOINTS 16
typedef double real_t;
typedef double hal_float_t;
typedef enum { HAL_IN = 16, HAL_OUT = 32, HAL_IO = (HAL_IN | HAL_OUT) } hal_pin_dir_t;
typedef struct {
double x;
double y;
double z;
} PmCartesian;
typedef struct EmcPose {
PmCartesian tran;
double a;
double b;
double c;
double u;
double v;
double w;
} EmcPose;
typedef enum {
KINEMATICS_IDENTITY = 1,
KINEMATICS_FORWARD_ONLY,
KINEMATICS_INVERSE_ONLY,
KINEMATICS_BOTH
} KINEMATICS_TYPE;
typedef unsigned long int KINEMATICS_FORWARD_FLAGS;
typedef unsigned long int KINEMATICS_INVERSE_FLAGS;
typedef struct kinematics_parms {
char *sparm;
char *kinsname;
char *halprefix;
char *required_coordinates;
int max_joints;
int allow_duplicates;
int fwd_iterates_mask;
int gui_kinstype;
} kparms;
#define KINS_NOT_SWITCHABLE \
extern int kinematicsSwitchable() { return 0; } \
extern int kinematicsSwitch(int switchkins_type) { (void)switchkins_type; return 0; }
#ifdef __cplusplus
extern "C" {
#endif
int cnc_sim_lineardelta_hal_init(const char *name) {
(void)name;
return 1;
}
void *cnc_sim_lineardelta_hal_malloc(long int size) {
return calloc(1, (size_t)size);
}
int cnc_sim_lineardelta_hal_ready(int comp_id) {
(void)comp_id;
return 0;
}
void cnc_sim_lineardelta_hal_exit(int comp_id) {
(void)comp_id;
}
int cnc_sim_lineardelta_hal_pin_float_newf(hal_pin_dir_t dir,
hal_float_t **data_ptr_addr,
int comp_id,
const char *fmt,
...) {
(void)dir;
(void)comp_id;
(void)fmt;
*data_ptr_addr = (hal_float_t *)calloc(1, sizeof(hal_float_t));
return *data_ptr_addr ? 0 : -1;
}
#define hal_init cnc_sim_lineardelta_hal_init
#define hal_malloc(size) ((struct haldata *)cnc_sim_lineardelta_hal_malloc(size))
#define hal_pin_float_newf cnc_sim_lineardelta_hal_pin_float_newf
#define hal_ready cnc_sim_lineardelta_hal_ready
#define hal_exit cnc_sim_lineardelta_hal_exit
#define kinematicsType cnc_sim_lineardelta_kinematicsType
#define kinematicsForward cnc_sim_lineardelta_kinematicsForward
#define kinematicsInverse cnc_sim_lineardelta_kinematicsInverse
#define kinematicsSwitchable cnc_sim_lineardelta_kinematicsSwitchable
#define kinematicsSwitch cnc_sim_lineardelta_kinematicsSwitch
#define rtapi_app_main cnc_sim_lineardelta_rtapi_app_main
#define rtapi_app_exit cnc_sim_lineardelta_rtapi_app_exit
#define comp_id cnc_sim_lineardelta_comp_id
#define haldata cnc_sim_lineardelta_haldata
#include "../../../linuxcnc/src/emc/kinematics/lineardeltakins.c"
#undef haldata
#undef comp_id
#undef rtapi_app_exit
#undef rtapi_app_main
#undef kinematicsSwitch
#undef kinematicsSwitchable
#undef kinematicsInverse
#undef kinematicsForward
#undef kinematicsType
#undef hal_exit
#undef hal_ready
#undef hal_pin_float_newf
#undef hal_malloc
#undef hal_init
int cnc_sim_linuxcnc_lineardeltakins_setup(void) {
return cnc_sim_lineardelta_rtapi_app_main();
}
void cnc_sim_linuxcnc_lineardeltakins_default_parameters(double *r, double *l) {
*r = DELTA_RADIUS;
*l = DELTA_DIAGONAL_ROD;
}
void cnc_sim_linuxcnc_lineardeltakins_set_parameters(double r, double l) {
*cnc_sim_lineardelta_haldata->r = r;
*cnc_sim_lineardelta_haldata->l = l;
}
int cnc_sim_linuxcnc_lineardeltakins_forward(const double *joints, EmcPose *pos) {
KINEMATICS_FORWARD_FLAGS fflags = 0;
KINEMATICS_INVERSE_FLAGS iflags = 0;
return cnc_sim_lineardelta_kinematicsForward(joints, pos, &fflags, &iflags);
}
int cnc_sim_linuxcnc_lineardeltakins_inverse(const EmcPose *pos, double *joints) {
KINEMATICS_INVERSE_FLAGS iflags = 0;
KINEMATICS_FORWARD_FLAGS fflags = 0;
return cnc_sim_lineardelta_kinematicsInverse(pos, joints, &iflags, &fflags);
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,138 @@
#include "linuxcnc_lineardeltakins_adapter.h"
#include <cstring>
extern "C" {
struct PmCartesian {
double x;
double y;
double z;
};
struct EmcPose {
PmCartesian tran;
double a;
double b;
double c;
double u;
double v;
double w;
};
int cnc_sim_linuxcnc_lineardeltakins_setup(void);
void cnc_sim_linuxcnc_lineardeltakins_default_parameters(double *r, double *l);
void cnc_sim_linuxcnc_lineardeltakins_set_parameters(double r, double l);
int cnc_sim_linuxcnc_lineardeltakins_forward(const double *joints, EmcPose *pos);
int cnc_sim_linuxcnc_lineardeltakins_inverse(const EmcPose *pos, double *joints);
}
namespace {
bool initialized = false;
bool ensure_initialized() {
if (initialized) {
return true;
}
initialized = cnc_sim_linuxcnc_lineardeltakins_setup() == 0;
return initialized;
}
void to_joints(const LinuxCncAxisJoints &joints, double out[16]) {
std::memset(out, 0, sizeof(double) * 16);
out[0] = joints.x;
out[1] = joints.y;
out[2] = joints.z;
out[3] = joints.a;
out[4] = joints.b;
out[5] = joints.c;
out[6] = joints.u;
out[7] = joints.v;
out[8] = joints.w;
}
LinuxCncAxisJoints from_joints(const double joints[16]) {
LinuxCncAxisJoints out{};
out.x = joints[0];
out.y = joints[1];
out.z = joints[2];
out.a = joints[3];
out.b = joints[4];
out.c = joints[5];
out.u = joints[6];
out.v = joints[7];
out.w = joints[8];
return out;
}
EmcPose to_emc_pose(const CncSimPose &pose) {
EmcPose emc{};
emc.tran.x = pose.x;
emc.tran.y = pose.y;
emc.tran.z = pose.z;
emc.a = pose.a;
emc.b = pose.b;
emc.c = pose.c;
emc.u = pose.u;
emc.v = pose.v;
emc.w = pose.w;
return emc;
}
CncSimPose from_emc_pose(const EmcPose &emc) {
CncSimPose pose{};
pose.x = emc.tran.x;
pose.y = emc.tran.y;
pose.z = emc.tran.z;
pose.a = emc.a;
pose.b = emc.b;
pose.c = emc.c;
pose.u = emc.u;
pose.v = emc.v;
pose.w = emc.w;
return pose;
}
} // namespace
bool linuxcnc_lineardeltakins_source_default_parameters(LinuxCncLinearDeltaParameters *parameters) {
double r = 0.0;
double l = 0.0;
cnc_sim_linuxcnc_lineardeltakins_default_parameters(&r, &l);
parameters->r = r;
parameters->l = l;
return true;
}
bool linuxcnc_lineardeltakins_source_forward(const LinuxCncAxisJoints &joints,
const LinuxCncLinearDeltaParameters &parameters,
CncSimPose *pose) {
if (!ensure_initialized()) {
return false;
}
cnc_sim_linuxcnc_lineardeltakins_set_parameters(parameters.r, parameters.l);
double raw_joints[16];
to_joints(joints, raw_joints);
EmcPose out{};
if (cnc_sim_linuxcnc_lineardeltakins_forward(raw_joints, &out) != 0) {
return false;
}
*pose = from_emc_pose(out);
return true;
}
bool linuxcnc_lineardeltakins_source_inverse(const CncSimPose &pose,
const LinuxCncLinearDeltaParameters &parameters,
LinuxCncAxisJoints *joints) {
if (!ensure_initialized()) {
return false;
}
cnc_sim_linuxcnc_lineardeltakins_set_parameters(parameters.r, parameters.l);
const EmcPose in = to_emc_pose(pose);
double raw_joints[16] = {};
if (cnc_sim_linuxcnc_lineardeltakins_inverse(&in, raw_joints) != 0) {
return false;
}
*joints = from_joints(raw_joints);
return true;
}

View File

@@ -0,0 +1,11 @@
#pragma once
#include "rtcp_kinematics.h"
bool linuxcnc_lineardeltakins_source_default_parameters(LinuxCncLinearDeltaParameters *parameters);
bool linuxcnc_lineardeltakins_source_forward(const LinuxCncAxisJoints &joints,
const LinuxCncLinearDeltaParameters &parameters,
CncSimPose *pose);
bool linuxcnc_lineardeltakins_source_inverse(const CncSimPose &pose,
const LinuxCncLinearDeltaParameters &parameters,
LinuxCncAxisJoints *joints);

View File

@@ -0,0 +1,168 @@
#include <math.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdlib.h>
#define __LINUXCNC_RTAPI_H
#define __LINUXCNC_RTAPI_MATH_H
#define __LINUXCNC_RTAPI_APP_H
#define __LINUXCNC_HAL_H
#define __LINUXCNC_KINEMATICS_H
#define __LINUXCNC_EMCPOS_H
#define MODULE_LICENSE(...)
#define EXPORT_SYMBOL(symbol)
#define EMCMOT_MAX_JOINTS 16
#define PM_PI 3.1415926535897932384626433832795029
typedef double real_t;
typedef double hal_float_t;
typedef bool hal_bit_t;
typedef enum { HAL_IN = 16, HAL_OUT = 32, HAL_IO = (HAL_IN | HAL_OUT) } hal_pin_dir_t;
typedef struct {
double x;
double y;
double z;
} PmCartesian;
typedef struct EmcPose {
PmCartesian tran;
double a;
double b;
double c;
double u;
double v;
double w;
} EmcPose;
typedef enum {
KINEMATICS_IDENTITY = 1,
KINEMATICS_FORWARD_ONLY,
KINEMATICS_INVERSE_ONLY,
KINEMATICS_BOTH
} KINEMATICS_TYPE;
typedef unsigned long int KINEMATICS_FORWARD_FLAGS;
typedef unsigned long int KINEMATICS_INVERSE_FLAGS;
typedef struct kinematics_parms {
char *sparm;
char *kinsname;
char *halprefix;
char *required_coordinates;
int max_joints;
int allow_duplicates;
int fwd_iterates_mask;
int gui_kinstype;
} kparms;
#define KINS_NOT_SWITCHABLE \
extern int kinematicsSwitchable() { return 0; } \
extern int kinematicsSwitch(int switchkins_type) { (void)switchkins_type; return 0; }
#ifdef __cplusplus
extern "C" {
#endif
int cnc_sim_maxkins_hal_init(const char *name) {
(void)name;
return 1;
}
void *cnc_sim_maxkins_hal_malloc(long int size) {
return calloc(1, (size_t)size);
}
int cnc_sim_maxkins_hal_ready(int comp_id) {
(void)comp_id;
return 0;
}
void cnc_sim_maxkins_hal_exit(int comp_id) {
(void)comp_id;
}
int cnc_sim_maxkins_hal_pin_float_new(const char *name,
hal_pin_dir_t dir,
hal_float_t **data_ptr_addr,
int comp_id) {
(void)name;
(void)dir;
(void)comp_id;
*data_ptr_addr = (hal_float_t *)calloc(1, sizeof(hal_float_t));
return *data_ptr_addr ? 0 : -1;
}
int cnc_sim_maxkins_hal_pin_bit_new(const char *name,
hal_pin_dir_t dir,
hal_bit_t **data_ptr_addr,
int comp_id) {
(void)name;
(void)dir;
(void)comp_id;
*data_ptr_addr = (hal_bit_t *)calloc(1, sizeof(hal_bit_t));
return *data_ptr_addr ? 0 : -1;
}
#define hal_init cnc_sim_maxkins_hal_init
#define hal_malloc(size) ((struct haldata *)cnc_sim_maxkins_hal_malloc(size))
#define hal_pin_float_new cnc_sim_maxkins_hal_pin_float_new
#define hal_pin_bit_new cnc_sim_maxkins_hal_pin_bit_new
#define hal_ready cnc_sim_maxkins_hal_ready
#define hal_exit cnc_sim_maxkins_hal_exit
#define kinematicsType cnc_sim_maxkins_kinematicsType
#define kinematicsForward cnc_sim_maxkins_kinematicsForward
#define kinematicsInverse cnc_sim_maxkins_kinematicsInverse
#define kinematicsSwitchable cnc_sim_maxkins_kinematicsSwitchable
#define kinematicsSwitch cnc_sim_maxkins_kinematicsSwitch
#define rtapi_app_main cnc_sim_maxkins_rtapi_app_main
#define rtapi_app_exit cnc_sim_maxkins_rtapi_app_exit
#define comp_id cnc_sim_maxkins_comp_id
#define haldata cnc_sim_maxkins_haldata
#include "../../../linuxcnc/src/emc/kinematics/maxkins.c"
#undef haldata
#undef comp_id
#undef rtapi_app_exit
#undef rtapi_app_main
#undef kinematicsSwitch
#undef kinematicsSwitchable
#undef kinematicsInverse
#undef kinematicsForward
#undef kinematicsType
#undef hal_exit
#undef hal_ready
#undef hal_pin_bit_new
#undef hal_pin_float_new
#undef hal_malloc
#undef hal_init
int cnc_sim_linuxcnc_maxkins_setup(void) {
return cnc_sim_maxkins_rtapi_app_main();
}
void cnc_sim_linuxcnc_maxkins_default_parameters(double *pivot_length, int *conventional_directions) {
*pivot_length = 0.666;
*conventional_directions = 0;
}
void cnc_sim_linuxcnc_maxkins_set_parameters(double pivot_length, int conventional_directions) {
*cnc_sim_maxkins_haldata->pivot_length = pivot_length;
*cnc_sim_maxkins_haldata->conventional_directions = conventional_directions != 0;
}
int cnc_sim_linuxcnc_maxkins_forward(const double *joints, EmcPose *pos) {
KINEMATICS_FORWARD_FLAGS fflags = 0;
KINEMATICS_INVERSE_FLAGS iflags = 0;
return cnc_sim_maxkins_kinematicsForward(joints, pos, &fflags, &iflags);
}
int cnc_sim_linuxcnc_maxkins_inverse(const EmcPose *pos, double *joints) {
KINEMATICS_INVERSE_FLAGS iflags = 0;
KINEMATICS_FORWARD_FLAGS fflags = 0;
return cnc_sim_maxkins_kinematicsInverse(pos, joints, &iflags, &fflags);
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,140 @@
#include "linuxcnc_maxkins_adapter.h"
#include <cstring>
extern "C" {
struct PmCartesian {
double x;
double y;
double z;
};
struct EmcPose {
PmCartesian tran;
double a;
double b;
double c;
double u;
double v;
double w;
};
int cnc_sim_linuxcnc_maxkins_setup(void);
void cnc_sim_linuxcnc_maxkins_default_parameters(double *pivot_length, int *conventional_directions);
void cnc_sim_linuxcnc_maxkins_set_parameters(double pivot_length, int conventional_directions);
int cnc_sim_linuxcnc_maxkins_forward(const double *joints, EmcPose *pos);
int cnc_sim_linuxcnc_maxkins_inverse(const EmcPose *pos, double *joints);
}
namespace {
bool initialized = false;
bool ensure_initialized() {
if (initialized) {
return true;
}
initialized = cnc_sim_linuxcnc_maxkins_setup() == 0;
return initialized;
}
void to_joints(const LinuxCncAxisJoints &joints, double out[16]) {
std::memset(out, 0, sizeof(double) * 16);
out[0] = joints.x;
out[1] = joints.y;
out[2] = joints.z;
out[3] = joints.a;
out[4] = joints.b;
out[5] = joints.c;
out[6] = joints.u;
out[7] = joints.v;
out[8] = joints.w;
}
LinuxCncAxisJoints from_joints(const double joints[16]) {
LinuxCncAxisJoints out{};
out.x = joints[0];
out.y = joints[1];
out.z = joints[2];
out.a = joints[3];
out.b = joints[4];
out.c = joints[5];
out.u = joints[6];
out.v = joints[7];
out.w = joints[8];
return out;
}
EmcPose to_emc_pose(const CncSimPose &pose) {
EmcPose emc{};
emc.tran.x = pose.x;
emc.tran.y = pose.y;
emc.tran.z = pose.z;
emc.a = pose.a;
emc.b = pose.b;
emc.c = pose.c;
emc.u = pose.u;
emc.v = pose.v;
emc.w = pose.w;
return emc;
}
CncSimPose from_emc_pose(const EmcPose &emc) {
CncSimPose pose{};
pose.x = emc.tran.x;
pose.y = emc.tran.y;
pose.z = emc.tran.z;
pose.a = emc.a;
pose.b = emc.b;
pose.c = emc.c;
pose.u = emc.u;
pose.v = emc.v;
pose.w = emc.w;
return pose;
}
} // namespace
bool linuxcnc_maxkins_source_default_parameters(LinuxCncMaxkinsParameters *parameters) {
double pivot_length = 0.0;
int conventional_directions = 0;
cnc_sim_linuxcnc_maxkins_default_parameters(&pivot_length, &conventional_directions);
parameters->pivot_length = pivot_length;
parameters->conventional_directions = conventional_directions != 0;
return true;
}
bool linuxcnc_maxkins_source_forward(const LinuxCncAxisJoints &joints,
const LinuxCncMaxkinsParameters &parameters,
CncSimPose *pose) {
if (!ensure_initialized()) {
return false;
}
cnc_sim_linuxcnc_maxkins_set_parameters(parameters.pivot_length,
parameters.conventional_directions ? 1 : 0);
double raw_joints[16];
to_joints(joints, raw_joints);
EmcPose out{};
if (cnc_sim_linuxcnc_maxkins_forward(raw_joints, &out) != 0) {
return false;
}
*pose = from_emc_pose(out);
return true;
}
bool linuxcnc_maxkins_source_inverse(const CncSimPose &pose,
const LinuxCncMaxkinsParameters &parameters,
LinuxCncAxisJoints *joints) {
if (!ensure_initialized()) {
return false;
}
cnc_sim_linuxcnc_maxkins_set_parameters(parameters.pivot_length,
parameters.conventional_directions ? 1 : 0);
const EmcPose in = to_emc_pose(pose);
double raw_joints[16] = {};
if (cnc_sim_linuxcnc_maxkins_inverse(&in, raw_joints) != 0) {
return false;
}
*joints = from_joints(raw_joints);
return true;
}

View File

@@ -0,0 +1,11 @@
#pragma once
#include "rtcp_kinematics.h"
bool linuxcnc_maxkins_source_default_parameters(LinuxCncMaxkinsParameters *parameters);
bool linuxcnc_maxkins_source_forward(const LinuxCncAxisJoints &joints,
const LinuxCncMaxkinsParameters &parameters,
CncSimPose *pose);
bool linuxcnc_maxkins_source_inverse(const CncSimPose &pose,
const LinuxCncMaxkinsParameters &parameters,
LinuxCncAxisJoints *joints);

View File

@@ -0,0 +1,172 @@
#include <math.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#define __LINUXCNC_RTAPI_H
#define __LINUXCNC_RTAPI_MATH_H
#define __LINUXCNC_RTAPI_APP_H
#define __LINUXCNC_HAL_H
#define __LINUXCNC_KINEMATICS_H
#define __LINUXCNC_EMCPOS_H
#define MODULE_LICENSE(...)
#define EXPORT_SYMBOL(symbol)
#define EMCMOT_MAX_JOINTS 16
typedef double real_t;
typedef double hal_float_t;
typedef uint32_t hal_u32_t;
typedef enum { HAL_IN = 16, HAL_OUT = 32, HAL_IO = (HAL_IN | HAL_OUT) } hal_pin_dir_t;
typedef enum { HAL_RO = 64, HAL_RW = (HAL_RO | 128) } hal_param_dir_t;
typedef unsigned long int KINEMATICS_FORWARD_FLAGS;
typedef unsigned long int KINEMATICS_INVERSE_FLAGS;
#include "../../../linuxcnc/src/libnml/posemath/posemath.h"
typedef struct EmcPose {
PmCartesian tran;
double a;
double b;
double c;
double u;
double v;
double w;
} EmcPose;
typedef enum {
KINEMATICS_IDENTITY = 1,
KINEMATICS_FORWARD_ONLY,
KINEMATICS_INVERSE_ONLY,
KINEMATICS_BOTH
} KINEMATICS_TYPE;
typedef struct kinematics_parms {
char *sparm;
char *kinsname;
char *halprefix;
char *required_coordinates;
int max_joints;
int allow_duplicates;
int fwd_iterates_mask;
int gui_kinstype;
} kparms;
#define KINS_NOT_SWITCHABLE \
extern int kinematicsSwitchable() { return 0; } \
extern int kinematicsSwitch(int switchkins_type) { (void)switchkins_type; return 0; }
#ifdef __cplusplus
extern "C" {
#endif
int cnc_sim_pentakins_hal_init(const char *name) {
(void)name;
return 1;
}
void *cnc_sim_pentakins_hal_malloc(long int size) {
return calloc(1, (size_t)size);
}
int cnc_sim_pentakins_hal_ready(int comp_id) {
(void)comp_id;
return 0;
}
void cnc_sim_pentakins_hal_exit(int comp_id) {
(void)comp_id;
}
int cnc_sim_pentakins_hal_param_float_newf(hal_param_dir_t dir,
hal_float_t *data_addr,
int comp_id,
const char *fmt,
...) {
(void)dir;
(void)data_addr;
(void)comp_id;
(void)fmt;
return 0;
}
int cnc_sim_pentakins_hal_pin_float_newf(hal_pin_dir_t dir,
hal_float_t **data_ptr_addr,
int comp_id,
const char *fmt,
...) {
(void)dir;
(void)comp_id;
(void)fmt;
*data_ptr_addr = (hal_float_t *)calloc(1, sizeof(hal_float_t));
return *data_ptr_addr ? 0 : -1;
}
int cnc_sim_pentakins_hal_pin_u32_newf(hal_pin_dir_t dir,
hal_u32_t **data_ptr_addr,
int comp_id,
const char *fmt,
...) {
(void)dir;
(void)comp_id;
(void)fmt;
*data_ptr_addr = (hal_u32_t *)calloc(1, sizeof(hal_u32_t));
return *data_ptr_addr ? 0 : -1;
}
#define hal_init cnc_sim_pentakins_hal_init
#define hal_malloc(size) ((struct haldata *)cnc_sim_pentakins_hal_malloc(size))
#define hal_param_float_newf cnc_sim_pentakins_hal_param_float_newf
#define hal_pin_float_newf cnc_sim_pentakins_hal_pin_float_newf
#define hal_pin_u32_newf cnc_sim_pentakins_hal_pin_u32_newf
#define hal_ready cnc_sim_pentakins_hal_ready
#define hal_exit cnc_sim_pentakins_hal_exit
#define kinematicsType cnc_sim_pentakins_kinematicsType
#define kinematicsForward cnc_sim_pentakins_kinematicsForward
#define kinematicsInverse cnc_sim_pentakins_kinematicsInverse
#define kinematicsSwitchable cnc_sim_pentakins_kinematicsSwitchable
#define kinematicsSwitch cnc_sim_pentakins_kinematicsSwitch
#define rtapi_app_main cnc_sim_pentakins_rtapi_app_main
#define rtapi_app_exit cnc_sim_pentakins_rtapi_app_exit
#define comp_id cnc_sim_pentakins_comp_id
#define haldata cnc_sim_pentakins_haldata
#include "../../../linuxcnc/src/emc/kinematics/pentakins.c"
#undef haldata
#undef comp_id
#undef rtapi_app_exit
#undef rtapi_app_main
#undef kinematicsSwitch
#undef kinematicsSwitchable
#undef kinematicsInverse
#undef kinematicsForward
#undef kinematicsType
#undef hal_exit
#undef hal_ready
#undef hal_pin_u32_newf
#undef hal_pin_float_newf
#undef hal_param_float_newf
#undef hal_malloc
#undef hal_init
int cnc_sim_linuxcnc_pentakins_setup(void) {
return cnc_sim_pentakins_rtapi_app_main();
}
int cnc_sim_linuxcnc_pentakins_forward(const double *joints, EmcPose *pos) {
KINEMATICS_FORWARD_FLAGS fflags = 0;
KINEMATICS_INVERSE_FLAGS iflags = 0;
return cnc_sim_pentakins_kinematicsForward(joints, pos, &fflags, &iflags);
}
int cnc_sim_linuxcnc_pentakins_inverse(const EmcPose *pos, double *joints) {
KINEMATICS_INVERSE_FLAGS iflags = 0;
KINEMATICS_FORWARD_FLAGS fflags = 0;
return cnc_sim_pentakins_kinematicsInverse(pos, joints, &iflags, &fflags);
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,97 @@
#include "linuxcnc_pentakins_adapter.h"
#include <cstring>
extern "C" {
struct PmCartesian {
double x;
double y;
double z;
};
struct EmcPose {
PmCartesian tran;
double a;
double b;
double c;
double u;
double v;
double w;
};
int cnc_sim_linuxcnc_pentakins_setup(void);
int cnc_sim_linuxcnc_pentakins_forward(const double *joints, EmcPose *pos);
int cnc_sim_linuxcnc_pentakins_inverse(const EmcPose *pos, double *joints);
}
namespace {
bool initialized = false;
bool ensure_initialized() {
if (initialized) {
return true;
}
initialized = cnc_sim_linuxcnc_pentakins_setup() == 0;
return initialized;
}
EmcPose to_emc_pose(const CncSimPose &pose) {
EmcPose emc{};
emc.tran.x = pose.x;
emc.tran.y = pose.y;
emc.tran.z = pose.z;
emc.a = pose.a;
emc.b = pose.b;
emc.c = pose.c;
emc.u = pose.u;
emc.v = pose.v;
emc.w = pose.w;
return emc;
}
CncSimPose from_emc_pose(const EmcPose &emc) {
CncSimPose pose{};
pose.x = emc.tran.x;
pose.y = emc.tran.y;
pose.z = emc.tran.z;
pose.a = emc.a;
pose.b = emc.b;
pose.c = emc.c;
pose.u = emc.u;
pose.v = emc.v;
pose.w = emc.w;
return pose;
}
} // namespace
bool linuxcnc_pentakins_source_forward(const LinuxCncPentakinsJoints &joints,
const CncSimPose &initial_pose,
CncSimPose *pose) {
if (!ensure_initialized()) {
return false;
}
double raw_joints[5];
std::memcpy(raw_joints, joints.strut, sizeof(raw_joints));
EmcPose emc_pose = to_emc_pose(initial_pose);
if (cnc_sim_linuxcnc_pentakins_forward(raw_joints, &emc_pose) != 0) {
return false;
}
*pose = from_emc_pose(emc_pose);
return true;
}
bool linuxcnc_pentakins_source_inverse(const CncSimPose &pose,
LinuxCncPentakinsJoints *joints) {
if (!ensure_initialized()) {
return false;
}
const EmcPose emc_pose = to_emc_pose(pose);
double raw_joints[5] = {};
if (cnc_sim_linuxcnc_pentakins_inverse(&emc_pose, raw_joints) != 0) {
return false;
}
std::memcpy(joints->strut, raw_joints, sizeof(raw_joints));
return true;
}

View File

@@ -0,0 +1,9 @@
#pragma once
#include "rtcp_kinematics.h"
bool linuxcnc_pentakins_source_forward(const LinuxCncPentakinsJoints &joints,
const CncSimPose &initial_pose,
CncSimPose *pose);
bool linuxcnc_pentakins_source_inverse(const CncSimPose &pose,
LinuxCncPentakinsJoints *joints);

View File

@@ -0,0 +1,218 @@
#include <math.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define __LINUXCNC_RTAPI_H
#define __LINUXCNC_RTAPI_MATH_H
#define __LINUXCNC_RTAPI_STRING_H
#define __LINUXCNC_HAL_H
#define __LINUXCNC_KINEMATICS_H
#define SWITCHKINS_H
#ifdef __cplusplus
#define CNC_SIM_EXTERN_C extern "C"
#else
#define CNC_SIM_EXTERN_C
#endif
typedef double real_t;
typedef double hal_float_t;
typedef int hal_s32_t;
typedef bool hal_bit_t;
typedef enum { HAL_IN = 16, HAL_OUT = 32, HAL_IO = (HAL_IN | HAL_OUT) } hal_pin_dir_t;
typedef unsigned long int KINEMATICS_FORWARD_FLAGS;
typedef unsigned long int KINEMATICS_INVERSE_FLAGS;
#include "../../../linuxcnc/src/libnml/posemath/sincos.c"
#include "../../../linuxcnc/src/libnml/posemath/_posemath.c"
typedef struct EmcPose {
PmCartesian tran;
double a;
double b;
double c;
double u;
double v;
double w;
} EmcPose;
typedef struct kinematics_parms {
char *sparm;
char *kinsname;
char *halprefix;
char *required_coordinates;
int max_joints;
int allow_duplicates;
int fwd_iterates_mask;
int gui_kinstype;
} kparms;
typedef int (*KF)(const double *joint,
EmcPose *pos,
const KINEMATICS_FORWARD_FLAGS *fflags,
KINEMATICS_INVERSE_FLAGS *iflags);
typedef int (*KI)(const EmcPose *world,
double *joint,
const KINEMATICS_INVERSE_FLAGS *iflags,
KINEMATICS_FORWARD_FLAGS *fflags);
typedef int (*KS)(const int comp_id, const char *coordinates, kparms *ksetup_parms);
void cnc_sim_puma_rtapi_print(const char *fmt, ...) {
(void)fmt;
}
void cnc_sim_puma_rtapi_print_msg(int level, const char *fmt, ...) {
(void)level;
(void)fmt;
}
void *cnc_sim_puma_hal_malloc(long int size) {
return calloc(1, (size_t)size);
}
int cnc_sim_puma_hal_pin_float_newf(hal_pin_dir_t dir,
hal_float_t **data_ptr_addr,
int comp_id,
const char *fmt,
...) {
(void)dir;
(void)comp_id;
(void)fmt;
*data_ptr_addr = (hal_float_t *)calloc(1, sizeof(hal_float_t));
return *data_ptr_addr ? 0 : -1;
}
int cnc_sim_puma_identityKinematicsSetup(const int comp_id, const char *coordinates, kparms *ksetup_parms) {
(void)comp_id;
(void)coordinates;
(void)ksetup_parms;
return 0;
}
int cnc_sim_puma_identityKinematicsForward(const double *joint,
EmcPose *world,
const KINEMATICS_FORWARD_FLAGS *fflags,
KINEMATICS_INVERSE_FLAGS *iflags) {
(void)joint;
(void)world;
(void)fflags;
(void)iflags;
return -1;
}
int cnc_sim_puma_identityKinematicsInverse(const EmcPose *world,
double *joint,
const KINEMATICS_INVERSE_FLAGS *iflags,
KINEMATICS_FORWARD_FLAGS *fflags) {
(void)world;
(void)joint;
(void)iflags;
(void)fflags;
return -1;
}
int cnc_sim_puma_userkKinematicsSetup(const int comp_id, const char *coordinates, kparms *ksetup_parms) {
(void)comp_id;
(void)coordinates;
(void)ksetup_parms;
return -1;
}
int cnc_sim_puma_userkKinematicsForward(const double *joint,
EmcPose *world,
const KINEMATICS_FORWARD_FLAGS *fflags,
KINEMATICS_INVERSE_FLAGS *iflags) {
(void)joint;
(void)world;
(void)fflags;
(void)iflags;
return -1;
}
int cnc_sim_puma_userkKinematicsInverse(const EmcPose *world,
double *joint,
const KINEMATICS_INVERSE_FLAGS *iflags,
KINEMATICS_FORWARD_FLAGS *fflags) {
(void)world;
(void)joint;
(void)iflags;
(void)fflags;
return -1;
}
#define rtapi_print cnc_sim_puma_rtapi_print
#define rtapi_print_msg cnc_sim_puma_rtapi_print_msg
#define hal_pin_float_newf cnc_sim_puma_hal_pin_float_newf
#define identityKinematicsSetup cnc_sim_puma_identityKinematicsSetup
#define identityKinematicsForward cnc_sim_puma_identityKinematicsForward
#define identityKinematicsInverse cnc_sim_puma_identityKinematicsInverse
#define userkKinematicsSetup cnc_sim_puma_userkKinematicsSetup
#define userkKinematicsForward cnc_sim_puma_userkKinematicsForward
#define userkKinematicsInverse cnc_sim_puma_userkKinematicsInverse
#define switchkinsSetup cnc_sim_puma_switchkinsSetup
#define haldata cnc_sim_puma_haldata
#define hal_malloc(size) ((struct haldata *)cnc_sim_puma_hal_malloc(size))
#include "../../../linuxcnc/src/emc/kinematics/pumakins.c"
#undef hal_malloc
#undef haldata
#undef switchkinsSetup
#undef userkKinematicsInverse
#undef userkKinematicsForward
#undef userkKinematicsSetup
#undef identityKinematicsInverse
#undef identityKinematicsForward
#undef identityKinematicsSetup
#undef hal_pin_float_newf
#undef rtapi_print_msg
#undef rtapi_print
CNC_SIM_EXTERN_C int cnc_sim_linuxcnc_pumakins_setup(void) {
kparms kp = {0};
static char kinsname[] = "pumakins";
static char halprefix[] = "pumakins";
kp.kinsname = kinsname;
kp.halprefix = halprefix;
return pumaKinematicsSetup(0, "XYZABC", &kp);
}
CNC_SIM_EXTERN_C void cnc_sim_linuxcnc_pumakins_set_parameters(double a2,
double a3,
double d3,
double d4,
double d6) {
*cnc_sim_puma_haldata->a2 = a2;
*cnc_sim_puma_haldata->a3 = a3;
*cnc_sim_puma_haldata->d3 = d3;
*cnc_sim_puma_haldata->d4 = d4;
*cnc_sim_puma_haldata->d6 = d6;
}
CNC_SIM_EXTERN_C int cnc_sim_linuxcnc_pumakins_forward(const double *joints,
struct EmcPose *pos,
int *iflags) {
KINEMATICS_FORWARD_FLAGS fflags = 0;
KINEMATICS_INVERSE_FLAGS raw_iflags = 0;
const int result = pumaKinematicsForward(joints, pos, &fflags, &raw_iflags);
if (iflags) {
*iflags = (int)raw_iflags;
}
return result;
}
CNC_SIM_EXTERN_C int cnc_sim_linuxcnc_pumakins_inverse(const struct EmcPose *pos,
double *joints,
int iflags,
int *fflags) {
KINEMATICS_INVERSE_FLAGS raw_iflags = (KINEMATICS_INVERSE_FLAGS)iflags;
KINEMATICS_FORWARD_FLAGS raw_fflags = 0;
const int result = pumaKinematicsInverse(pos, joints, &raw_iflags, &raw_fflags);
if (fflags) {
*fflags = (int)raw_fflags;
}
return result;
}

View File

@@ -0,0 +1,156 @@
#include "linuxcnc_pumakins_adapter.h"
#include <cstring>
extern "C" {
struct PmCartesian {
double x;
double y;
double z;
};
struct EmcPose {
PmCartesian tran;
double a;
double b;
double c;
double u;
double v;
double w;
};
int cnc_sim_linuxcnc_pumakins_setup(void);
void cnc_sim_linuxcnc_pumakins_set_parameters(double a2,
double a3,
double d3,
double d4,
double d6);
int cnc_sim_linuxcnc_pumakins_forward(const double *joints, EmcPose *pos, int *iflags);
int cnc_sim_linuxcnc_pumakins_inverse(const EmcPose *pos,
double *joints,
int iflags,
int *fflags);
}
namespace {
bool initialized = false;
bool ensure_initialized() {
if (initialized) {
return true;
}
initialized = cnc_sim_linuxcnc_pumakins_setup() == 0;
return initialized;
}
void apply_parameters(const LinuxCncPumaParameters &parameters) {
cnc_sim_linuxcnc_pumakins_set_parameters(parameters.a2,
parameters.a3,
parameters.d3,
parameters.d4,
parameters.d6);
}
void to_joints(const LinuxCncAxisJoints &joints, double out[16]) {
std::memset(out, 0, sizeof(double) * 16);
out[0] = joints.x;
out[1] = joints.y;
out[2] = joints.z;
out[3] = joints.a;
out[4] = joints.b;
out[5] = joints.c;
out[6] = joints.u;
out[7] = joints.v;
out[8] = joints.w;
}
LinuxCncAxisJoints from_joints(const double joints[16]) {
LinuxCncAxisJoints out{};
out.x = joints[0];
out.y = joints[1];
out.z = joints[2];
out.a = joints[3];
out.b = joints[4];
out.c = joints[5];
out.u = joints[6];
out.v = joints[7];
out.w = joints[8];
return out;
}
EmcPose to_emc_pose(const CncSimPose &pose) {
EmcPose emc{};
emc.tran.x = pose.x;
emc.tran.y = pose.y;
emc.tran.z = pose.z;
emc.a = pose.a;
emc.b = pose.b;
emc.c = pose.c;
emc.u = pose.u;
emc.v = pose.v;
emc.w = pose.w;
return emc;
}
CncSimPose from_emc_pose(const EmcPose &emc) {
CncSimPose pose{};
pose.x = emc.tran.x;
pose.y = emc.tran.y;
pose.z = emc.tran.z;
pose.a = emc.a;
pose.b = emc.b;
pose.c = emc.c;
pose.u = emc.u;
pose.v = emc.v;
pose.w = emc.w;
return pose;
}
} // namespace
bool linuxcnc_pumakins_forward(const LinuxCncAxisJoints &joints,
const LinuxCncPumaParameters &parameters,
CncSimPose *pose,
int *iflags) {
if (!ensure_initialized()) {
return false;
}
apply_parameters(parameters);
double raw_joints[16];
to_joints(joints, raw_joints);
EmcPose out{};
int raw_iflags = 0;
if (cnc_sim_linuxcnc_pumakins_forward(raw_joints, &out, &raw_iflags) != 0) {
return false;
}
if (iflags) {
*iflags = raw_iflags;
}
*pose = from_emc_pose(out);
return true;
}
bool linuxcnc_pumakins_inverse(const CncSimPose &pose,
const LinuxCncAxisJoints &current_joints,
const LinuxCncPumaParameters &parameters,
int iflags,
LinuxCncAxisJoints *joints,
int *fflags) {
if (!ensure_initialized()) {
return false;
}
apply_parameters(parameters);
double raw_joints[16];
to_joints(current_joints, raw_joints);
const EmcPose in = to_emc_pose(pose);
int raw_fflags = 0;
if (cnc_sim_linuxcnc_pumakins_inverse(&in, raw_joints, iflags, &raw_fflags) != 0) {
return false;
}
if (fflags) {
*fflags = raw_fflags;
}
*joints = from_joints(raw_joints);
return true;
}

View File

@@ -0,0 +1,14 @@
#pragma once
#include "rtcp_kinematics.h"
bool linuxcnc_pumakins_forward(const LinuxCncAxisJoints &joints,
const LinuxCncPumaParameters &parameters,
CncSimPose *pose,
int *iflags);
bool linuxcnc_pumakins_inverse(const CncSimPose &pose,
const LinuxCncAxisJoints &current_joints,
const LinuxCncPumaParameters &parameters,
int iflags,
LinuxCncAxisJoints *joints,
int *fflags);

View File

@@ -0,0 +1,147 @@
#include <math.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdlib.h>
#define __LINUXCNC_RTAPI_H
#define __LINUXCNC_RTAPI_MATH_H
#define __LINUXCNC_RTAPI_APP_H
#define __LINUXCNC_HAL_H
#define __LINUXCNC_KINEMATICS_H
#define __LINUXCNC_EMCPOS_H
#define MODULE_LICENSE(...)
#define EXPORT_SYMBOL(symbol)
#define EMCMOT_MAX_JOINTS 16
#define PM_PI 3.1415926535897932384626433832795029
#define PM_2_PI (2.0 * PM_PI)
#define TO_RAD (PM_PI / 180.0)
#define TO_DEG (180.0 / PM_PI)
typedef double real_t;
typedef double hal_float_t;
typedef enum { HAL_IN = 16, HAL_OUT = 32, HAL_IO = (HAL_IN | HAL_OUT) } hal_pin_dir_t;
typedef struct {
double x;
double y;
double z;
} PmCartesian;
typedef struct EmcPose {
PmCartesian tran;
double a;
double b;
double c;
double u;
double v;
double w;
} EmcPose;
typedef enum {
KINEMATICS_IDENTITY = 1,
KINEMATICS_FORWARD_ONLY,
KINEMATICS_INVERSE_ONLY,
KINEMATICS_BOTH
} KINEMATICS_TYPE;
typedef unsigned long int KINEMATICS_FORWARD_FLAGS;
typedef unsigned long int KINEMATICS_INVERSE_FLAGS;
typedef struct kinematics_parms {
char *sparm;
char *kinsname;
char *halprefix;
char *required_coordinates;
int max_joints;
int allow_duplicates;
int fwd_iterates_mask;
int gui_kinstype;
} kparms;
#define KINS_NOT_SWITCHABLE \
extern int kinematicsSwitchable() { return 0; } \
extern int kinematicsSwitch(int switchkins_type) { (void)switchkins_type; return 0; }
#ifdef __cplusplus
extern "C" {
#endif
int cnc_sim_rosekins_hal_init(const char *name) {
(void)name;
return 1;
}
void *cnc_sim_rosekins_hal_malloc(long int size) {
return calloc(1, (size_t)size);
}
int cnc_sim_rosekins_hal_ready(int comp_id) {
(void)comp_id;
return 0;
}
void cnc_sim_rosekins_hal_exit(int comp_id) {
(void)comp_id;
}
int cnc_sim_rosekins_hal_pin_float_new(const char *name,
hal_pin_dir_t dir,
hal_float_t **data_ptr_addr,
int comp_id) {
(void)name;
(void)dir;
(void)comp_id;
*data_ptr_addr = (hal_float_t *)calloc(1, sizeof(hal_float_t));
return *data_ptr_addr ? 0 : -1;
}
#define hal_init cnc_sim_rosekins_hal_init
#define hal_malloc(size) ((struct haldata *)cnc_sim_rosekins_hal_malloc(size))
#define hal_pin_float_new cnc_sim_rosekins_hal_pin_float_new
#define hal_ready cnc_sim_rosekins_hal_ready
#define hal_exit cnc_sim_rosekins_hal_exit
#define kinematicsType cnc_sim_rosekins_kinematicsType
#define kinematicsForward cnc_sim_rosekins_kinematicsForward
#define kinematicsInverse cnc_sim_rosekins_kinematicsInverse
#define kinematicsSwitchable cnc_sim_rosekins_kinematicsSwitchable
#define kinematicsSwitch cnc_sim_rosekins_kinematicsSwitch
#define rtapi_app_main cnc_sim_rosekins_rtapi_app_main
#define rtapi_app_exit cnc_sim_rosekins_rtapi_app_exit
#define comp_id cnc_sim_rosekins_comp_id
#define haldata cnc_sim_rosekins_haldata
#include "../../../linuxcnc/src/emc/kinematics/rosekins.c"
#undef haldata
#undef comp_id
#undef rtapi_app_exit
#undef rtapi_app_main
#undef kinematicsSwitch
#undef kinematicsSwitchable
#undef kinematicsInverse
#undef kinematicsForward
#undef kinematicsType
#undef hal_exit
#undef hal_ready
#undef hal_pin_float_new
#undef hal_malloc
#undef hal_init
int cnc_sim_linuxcnc_rosekins_setup(void) {
return cnc_sim_rosekins_rtapi_app_main();
}
int cnc_sim_linuxcnc_rosekins_forward(const double *joints, EmcPose *pos) {
KINEMATICS_FORWARD_FLAGS fflags = 0;
KINEMATICS_INVERSE_FLAGS iflags = 0;
return cnc_sim_rosekins_kinematicsForward(joints, pos, &fflags, &iflags);
}
int cnc_sim_linuxcnc_rosekins_inverse(const EmcPose *pos, double *joints) {
KINEMATICS_INVERSE_FLAGS iflags = 0;
KINEMATICS_FORWARD_FLAGS fflags = 0;
return cnc_sim_rosekins_kinematicsInverse(pos, joints, &iflags, &fflags);
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,121 @@
#include "linuxcnc_rosekins_adapter.h"
#include <cstring>
extern "C" {
struct PmCartesian {
double x;
double y;
double z;
};
struct EmcPose {
PmCartesian tran;
double a;
double b;
double c;
double u;
double v;
double w;
};
int cnc_sim_linuxcnc_rosekins_setup(void);
int cnc_sim_linuxcnc_rosekins_forward(const double *joints, EmcPose *pos);
int cnc_sim_linuxcnc_rosekins_inverse(const EmcPose *pos, double *joints);
}
namespace {
bool initialized = false;
bool ensure_initialized() {
if (initialized) {
return true;
}
initialized = cnc_sim_linuxcnc_rosekins_setup() == 0;
return initialized;
}
void to_joints(const LinuxCncAxisJoints &joints, double out[16]) {
std::memset(out, 0, sizeof(double) * 16);
out[0] = joints.x;
out[1] = joints.y;
out[2] = joints.z;
out[3] = joints.a;
out[4] = joints.b;
out[5] = joints.c;
out[6] = joints.u;
out[7] = joints.v;
out[8] = joints.w;
}
LinuxCncAxisJoints from_joints(const double joints[16]) {
LinuxCncAxisJoints out{};
out.x = joints[0];
out.y = joints[1];
out.z = joints[2];
out.a = joints[3];
out.b = joints[4];
out.c = joints[5];
out.u = joints[6];
out.v = joints[7];
out.w = joints[8];
return out;
}
EmcPose to_emc_pose(const CncSimPose &pose) {
EmcPose emc{};
emc.tran.x = pose.x;
emc.tran.y = pose.y;
emc.tran.z = pose.z;
emc.a = pose.a;
emc.b = pose.b;
emc.c = pose.c;
emc.u = pose.u;
emc.v = pose.v;
emc.w = pose.w;
return emc;
}
CncSimPose from_emc_pose(const EmcPose &emc) {
CncSimPose pose{};
pose.x = emc.tran.x;
pose.y = emc.tran.y;
pose.z = emc.tran.z;
pose.a = emc.a;
pose.b = emc.b;
pose.c = emc.c;
pose.u = emc.u;
pose.v = emc.v;
pose.w = emc.w;
return pose;
}
} // namespace
bool linuxcnc_rosekins_source_forward(const LinuxCncAxisJoints &joints, CncSimPose *pose) {
if (!ensure_initialized()) {
return false;
}
double raw_joints[16];
to_joints(joints, raw_joints);
EmcPose out{};
if (cnc_sim_linuxcnc_rosekins_forward(raw_joints, &out) != 0) {
return false;
}
*pose = from_emc_pose(out);
return true;
}
bool linuxcnc_rosekins_source_inverse(const CncSimPose &pose, LinuxCncAxisJoints *joints) {
if (!ensure_initialized()) {
return false;
}
const EmcPose in = to_emc_pose(pose);
double raw_joints[16] = {};
if (cnc_sim_linuxcnc_rosekins_inverse(&in, raw_joints) != 0) {
return false;
}
*joints = from_joints(raw_joints);
return true;
}

View File

@@ -0,0 +1,6 @@
#pragma once
#include "rtcp_kinematics.h"
bool linuxcnc_rosekins_source_forward(const LinuxCncAxisJoints &joints, CncSimPose *pose);
bool linuxcnc_rosekins_source_inverse(const CncSimPose &pose, LinuxCncAxisJoints *joints);

View File

@@ -0,0 +1,165 @@
#include <math.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdlib.h>
#define __LINUXCNC_RTAPI_H
#define __LINUXCNC_RTAPI_MATH_H
#define __LINUXCNC_RTAPI_APP_H
#define __LINUXCNC_HAL_H
#define __LINUXCNC_KINEMATICS_H
#define __LINUXCNC_EMCPOS_H
#define MODULE_LICENSE(...)
#define EXPORT_SYMBOL(symbol)
#define EMCMOT_MAX_JOINTS 16
typedef double real_t;
typedef double hal_float_t;
typedef enum { HAL_IN = 16, HAL_OUT = 32, HAL_IO = (HAL_IN | HAL_OUT) } hal_pin_dir_t;
typedef struct {
double x;
double y;
double z;
} PmCartesian;
typedef struct EmcPose {
PmCartesian tran;
double a;
double b;
double c;
double u;
double v;
double w;
} EmcPose;
typedef enum {
KINEMATICS_IDENTITY = 1,
KINEMATICS_FORWARD_ONLY,
KINEMATICS_INVERSE_ONLY,
KINEMATICS_BOTH
} KINEMATICS_TYPE;
typedef unsigned long int KINEMATICS_FORWARD_FLAGS;
typedef unsigned long int KINEMATICS_INVERSE_FLAGS;
typedef struct kinematics_parms {
char *sparm;
char *kinsname;
char *halprefix;
char *required_coordinates;
int max_joints;
int allow_duplicates;
int fwd_iterates_mask;
int gui_kinstype;
} kparms;
#define KINS_NOT_SWITCHABLE \
extern int kinematicsSwitchable() { return 0; } \
extern int kinematicsSwitch(int switchkins_type) { (void)switchkins_type; return 0; }
#ifdef __cplusplus
extern "C" {
#endif
int cnc_sim_rotarydelta_hal_init(const char *name) {
(void)name;
return 1;
}
void *cnc_sim_rotarydelta_hal_malloc(long int size) {
return calloc(1, (size_t)size);
}
int cnc_sim_rotarydelta_hal_ready(int comp_id) {
(void)comp_id;
return 0;
}
void cnc_sim_rotarydelta_hal_exit(int comp_id) {
(void)comp_id;
}
int cnc_sim_rotarydelta_hal_pin_float_newf(hal_pin_dir_t dir,
hal_float_t **data_ptr_addr,
int comp_id,
const char *fmt,
...) {
(void)dir;
(void)comp_id;
(void)fmt;
*data_ptr_addr = (hal_float_t *)calloc(1, sizeof(hal_float_t));
return *data_ptr_addr ? 0 : -1;
}
#define hal_init cnc_sim_rotarydelta_hal_init
#define hal_malloc(size) ((struct haldata *)cnc_sim_rotarydelta_hal_malloc(size))
#define hal_pin_float_newf cnc_sim_rotarydelta_hal_pin_float_newf
#define hal_ready cnc_sim_rotarydelta_hal_ready
#define hal_exit cnc_sim_rotarydelta_hal_exit
#define kinematicsType cnc_sim_rotarydelta_kinematicsType
#define kinematicsForward cnc_sim_rotarydelta_kinematicsForward
#define kinematicsInverse cnc_sim_rotarydelta_kinematicsInverse
#define kinematicsSwitchable cnc_sim_rotarydelta_kinematicsSwitchable
#define kinematicsSwitch cnc_sim_rotarydelta_kinematicsSwitch
#define rtapi_app_main cnc_sim_rotarydelta_rtapi_app_main
#define rtapi_app_exit cnc_sim_rotarydelta_rtapi_app_exit
#define comp_id cnc_sim_rotarydelta_comp_id
#define haldata cnc_sim_rotarydelta_haldata
#include "../../../linuxcnc/src/emc/kinematics/rotarydeltakins.c"
#undef haldata
#undef comp_id
#undef rtapi_app_exit
#undef rtapi_app_main
#undef kinematicsSwitch
#undef kinematicsSwitchable
#undef kinematicsInverse
#undef kinematicsForward
#undef kinematicsType
#undef hal_exit
#undef hal_ready
#undef hal_pin_float_newf
#undef hal_malloc
#undef hal_init
int cnc_sim_linuxcnc_rotarydeltakins_setup(void) {
return cnc_sim_rotarydelta_rtapi_app_main();
}
void cnc_sim_linuxcnc_rotarydeltakins_default_parameters(double *platformradius,
double *thighlength,
double *shinlength,
double *footradius) {
*platformradius = RDELTA_PFR;
*thighlength = RDELTA_TL;
*shinlength = RDELTA_SL;
*footradius = RDELTA_FR;
}
void cnc_sim_linuxcnc_rotarydeltakins_set_parameters(double platformradius,
double thighlength,
double shinlength,
double footradius) {
*cnc_sim_rotarydelta_haldata->pfr = platformradius;
*cnc_sim_rotarydelta_haldata->tl = thighlength;
*cnc_sim_rotarydelta_haldata->sl = shinlength;
*cnc_sim_rotarydelta_haldata->fr = footradius;
}
int cnc_sim_linuxcnc_rotarydeltakins_forward(const double *joints, EmcPose *pos) {
KINEMATICS_FORWARD_FLAGS fflags = 0;
KINEMATICS_INVERSE_FLAGS iflags = 0;
return cnc_sim_rotarydelta_kinematicsForward(joints, pos, &fflags, &iflags);
}
int cnc_sim_linuxcnc_rotarydeltakins_inverse(const EmcPose *pos, double *joints) {
KINEMATICS_INVERSE_FLAGS iflags = 0;
KINEMATICS_FORWARD_FLAGS fflags = 0;
return cnc_sim_rotarydelta_kinematicsInverse(pos, joints, &iflags, &fflags);
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,157 @@
#include "linuxcnc_rotarydeltakins_adapter.h"
#include <cstring>
extern "C" {
struct PmCartesian {
double x;
double y;
double z;
};
struct EmcPose {
PmCartesian tran;
double a;
double b;
double c;
double u;
double v;
double w;
};
int cnc_sim_linuxcnc_rotarydeltakins_setup(void);
void cnc_sim_linuxcnc_rotarydeltakins_default_parameters(double *platformradius,
double *thighlength,
double *shinlength,
double *footradius);
void cnc_sim_linuxcnc_rotarydeltakins_set_parameters(double platformradius,
double thighlength,
double shinlength,
double footradius);
int cnc_sim_linuxcnc_rotarydeltakins_forward(const double *joints, EmcPose *pos);
int cnc_sim_linuxcnc_rotarydeltakins_inverse(const EmcPose *pos, double *joints);
}
namespace {
bool initialized = false;
bool ensure_initialized() {
if (initialized) {
return true;
}
initialized = cnc_sim_linuxcnc_rotarydeltakins_setup() == 0;
return initialized;
}
void to_joints(const LinuxCncAxisJoints &joints, double out[16]) {
std::memset(out, 0, sizeof(double) * 16);
out[0] = joints.x;
out[1] = joints.y;
out[2] = joints.z;
out[3] = joints.a;
out[4] = joints.b;
out[5] = joints.c;
out[6] = joints.u;
out[7] = joints.v;
out[8] = joints.w;
}
LinuxCncAxisJoints from_joints(const double joints[16]) {
LinuxCncAxisJoints out{};
out.x = joints[0];
out.y = joints[1];
out.z = joints[2];
out.a = joints[3];
out.b = joints[4];
out.c = joints[5];
out.u = joints[6];
out.v = joints[7];
out.w = joints[8];
return out;
}
EmcPose to_emc_pose(const CncSimPose &pose) {
EmcPose emc{};
emc.tran.x = pose.x;
emc.tran.y = pose.y;
emc.tran.z = pose.z;
emc.a = pose.a;
emc.b = pose.b;
emc.c = pose.c;
emc.u = pose.u;
emc.v = pose.v;
emc.w = pose.w;
return emc;
}
CncSimPose from_emc_pose(const EmcPose &emc) {
CncSimPose pose{};
pose.x = emc.tran.x;
pose.y = emc.tran.y;
pose.z = emc.tran.z;
pose.a = emc.a;
pose.b = emc.b;
pose.c = emc.c;
pose.u = emc.u;
pose.v = emc.v;
pose.w = emc.w;
return pose;
}
} // namespace
bool linuxcnc_rotarydeltakins_source_default_parameters(LinuxCncRotaryDeltaParameters *parameters) {
double platformradius = 0.0;
double thighlength = 0.0;
double shinlength = 0.0;
double footradius = 0.0;
cnc_sim_linuxcnc_rotarydeltakins_default_parameters(&platformradius,
&thighlength,
&shinlength,
&footradius);
parameters->platformradius = platformradius;
parameters->thighlength = thighlength;
parameters->shinlength = shinlength;
parameters->footradius = footradius;
return true;
}
bool linuxcnc_rotarydeltakins_source_forward(const LinuxCncAxisJoints &joints,
const LinuxCncRotaryDeltaParameters &parameters,
CncSimPose *pose) {
if (!ensure_initialized()) {
return false;
}
cnc_sim_linuxcnc_rotarydeltakins_set_parameters(parameters.platformradius,
parameters.thighlength,
parameters.shinlength,
parameters.footradius);
double raw_joints[16];
to_joints(joints, raw_joints);
EmcPose out{};
if (cnc_sim_linuxcnc_rotarydeltakins_forward(raw_joints, &out) != 0) {
return false;
}
*pose = from_emc_pose(out);
return true;
}
bool linuxcnc_rotarydeltakins_source_inverse(const CncSimPose &pose,
const LinuxCncRotaryDeltaParameters &parameters,
LinuxCncAxisJoints *joints) {
if (!ensure_initialized()) {
return false;
}
cnc_sim_linuxcnc_rotarydeltakins_set_parameters(parameters.platformradius,
parameters.thighlength,
parameters.shinlength,
parameters.footradius);
const EmcPose in = to_emc_pose(pose);
double raw_joints[16] = {};
if (cnc_sim_linuxcnc_rotarydeltakins_inverse(&in, raw_joints) != 0) {
return false;
}
*joints = from_joints(raw_joints);
return true;
}

View File

@@ -0,0 +1,11 @@
#pragma once
#include "rtcp_kinematics.h"
bool linuxcnc_rotarydeltakins_source_default_parameters(LinuxCncRotaryDeltaParameters *parameters);
bool linuxcnc_rotarydeltakins_source_forward(const LinuxCncAxisJoints &joints,
const LinuxCncRotaryDeltaParameters &parameters,
CncSimPose *pose);
bool linuxcnc_rotarydeltakins_source_inverse(const CncSimPose &pose,
const LinuxCncRotaryDeltaParameters &parameters,
LinuxCncAxisJoints *joints);

View File

@@ -0,0 +1,118 @@
#include <math.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#define __LINUXCNC_RTAPI_H
#define __LINUXCNC_RTAPI_APP_H
#define __LINUXCNC_RTAPI_MATH_H
#define __LINUXCNC_HAL_H
#define __LINUXCNC_KINEMATICS_H
#define MODULE_LICENSE(...)
#define EXPORT_SYMBOL(symbol)
#define RTAPI_MSG_ERR 1
typedef enum { HAL_IN = 16, HAL_OUT = 32, HAL_IO = (HAL_IN | HAL_OUT) } hal_pin_dir_t;
typedef struct {
double x;
double y;
double z;
} PmCartesian;
typedef struct EmcPose {
PmCartesian tran;
double a;
double b;
double c;
double u;
double v;
double w;
} EmcPose;
typedef enum {
KINEMATICS_IDENTITY = 1,
KINEMATICS_FORWARD_ONLY,
KINEMATICS_INVERSE_ONLY,
KINEMATICS_BOTH
} KINEMATICS_TYPE;
typedef unsigned long int KINEMATICS_FORWARD_FLAGS;
typedef unsigned long int KINEMATICS_INVERSE_FLAGS;
typedef struct kinematics_parms {
char *sparm;
char *kinsname;
char *halprefix;
char *required_coordinates;
int max_joints;
int allow_duplicates;
int fwd_iterates_mask;
int gui_kinstype;
} kparms;
#define KINS_NOT_SWITCHABLE \
extern int kinematicsSwitchable() { return 0; } \
extern int kinematicsSwitch(int switchkins_type) { (void)switchkins_type; return 0; }
#ifdef __cplusplus
extern "C" {
#endif
int cnc_sim_rotatekins_hal_init(const char *name) {
(void)name;
return 1;
}
int cnc_sim_rotatekins_hal_ready(int comp_id) {
(void)comp_id;
return 0;
}
void cnc_sim_rotatekins_hal_exit(int comp_id) {
(void)comp_id;
}
#define hal_init cnc_sim_rotatekins_hal_init
#define hal_ready cnc_sim_rotatekins_hal_ready
#define hal_exit cnc_sim_rotatekins_hal_exit
#define kinematicsType cnc_sim_rotatekins_kinematicsType
#define kinematicsForward cnc_sim_rotatekins_kinematicsForward
#define kinematicsInverse cnc_sim_rotatekins_kinematicsInverse
#define kinematicsHome cnc_sim_rotatekins_kinematicsHome
#define kinematicsSwitchable cnc_sim_rotatekins_kinematicsSwitchable
#define kinematicsSwitch cnc_sim_rotatekins_kinematicsSwitch
#define rtapi_app_main cnc_sim_rotatekins_rtapi_app_main
#define rtapi_app_exit cnc_sim_rotatekins_rtapi_app_exit
#define comp_id cnc_sim_rotatekins_comp_id
#include "../../../linuxcnc/src/emc/kinematics/rotatekins.c"
#undef comp_id
#undef rtapi_app_exit
#undef rtapi_app_main
#undef kinematicsSwitch
#undef kinematicsSwitchable
#undef kinematicsHome
#undef kinematicsInverse
#undef kinematicsForward
#undef kinematicsType
#undef hal_exit
#undef hal_ready
#undef hal_init
int cnc_sim_linuxcnc_rotatekins_forward(const double *joints, EmcPose *pos) {
KINEMATICS_FORWARD_FLAGS fflags = 0;
KINEMATICS_INVERSE_FLAGS iflags = 0;
return cnc_sim_rotatekins_kinematicsForward(joints, pos, &fflags, &iflags);
}
int cnc_sim_linuxcnc_rotatekins_inverse(const EmcPose *pos, double *joints) {
KINEMATICS_INVERSE_FLAGS iflags = 0;
KINEMATICS_FORWARD_FLAGS fflags = 0;
return cnc_sim_rotatekins_kinematicsInverse(pos, joints, &iflags, &fflags);
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,104 @@
#include "linuxcnc_rotatekins_adapter.h"
#include <cstring>
extern "C" {
struct PmCartesian {
double x;
double y;
double z;
};
struct EmcPose {
PmCartesian tran;
double a;
double b;
double c;
double u;
double v;
double w;
};
int cnc_sim_linuxcnc_rotatekins_forward(const double *joints, EmcPose *pos);
int cnc_sim_linuxcnc_rotatekins_inverse(const EmcPose *pos, double *joints);
}
namespace {
void to_joints(const LinuxCncAxisJoints &joints, double out[16]) {
std::memset(out, 0, sizeof(double) * 16);
out[0] = joints.x;
out[1] = joints.y;
out[2] = joints.z;
out[3] = joints.a;
out[4] = joints.b;
out[5] = joints.c;
out[6] = joints.u;
out[7] = joints.v;
out[8] = joints.w;
}
LinuxCncAxisJoints from_joints(const double joints[16]) {
LinuxCncAxisJoints out{};
out.x = joints[0];
out.y = joints[1];
out.z = joints[2];
out.a = joints[3];
out.b = joints[4];
out.c = joints[5];
out.u = joints[6];
out.v = joints[7];
out.w = joints[8];
return out;
}
EmcPose to_emc_pose(const CncSimPose &pose) {
EmcPose emc{};
emc.tran.x = pose.x;
emc.tran.y = pose.y;
emc.tran.z = pose.z;
emc.a = pose.a;
emc.b = pose.b;
emc.c = pose.c;
emc.u = pose.u;
emc.v = pose.v;
emc.w = pose.w;
return emc;
}
CncSimPose from_emc_pose(const EmcPose &emc) {
CncSimPose pose{};
pose.x = emc.tran.x;
pose.y = emc.tran.y;
pose.z = emc.tran.z;
pose.a = emc.a;
pose.b = emc.b;
pose.c = emc.c;
pose.u = emc.u;
pose.v = emc.v;
pose.w = emc.w;
return pose;
}
} // namespace
bool linuxcnc_rotatekins_source_forward(const LinuxCncAxisJoints &joints, CncSimPose *pose) {
double raw_joints[16];
to_joints(joints, raw_joints);
EmcPose out{};
if (cnc_sim_linuxcnc_rotatekins_forward(raw_joints, &out) != 0) {
return false;
}
*pose = from_emc_pose(out);
return true;
}
bool linuxcnc_rotatekins_source_inverse(const CncSimPose &pose, LinuxCncAxisJoints *joints) {
const EmcPose in = to_emc_pose(pose);
double raw_joints[16] = {};
if (cnc_sim_linuxcnc_rotatekins_inverse(&in, raw_joints) != 0) {
return false;
}
*joints = from_joints(raw_joints);
return true;
}

View File

@@ -0,0 +1,6 @@
#pragma once
#include "rtcp_kinematics.h"
bool linuxcnc_rotatekins_source_forward(const LinuxCncAxisJoints &joints, CncSimPose *pose);
bool linuxcnc_rotatekins_source_inverse(const CncSimPose &pose, LinuxCncAxisJoints *joints);

View File

@@ -1,6 +1,10 @@
#include "linuxcnc_rs274_backend.h"
#ifdef CNC_SIM_ENABLE_LINUXCNC_WASM_SAFE_PROBE
#include "boost/python/object.hpp"
#else
#include <Python.h>
#endif
#include "linuxcnc_canon_bridge.h"
#include "linuxcnc_tooldata_fixture.h"
@@ -16,11 +20,15 @@
#include <vector>
#include <cstdlib>
#include <fstream>
#ifndef CNC_SIM_ENABLE_LINUXCNC_WASM_SAFE_PROBE
#include <unistd.h>
#endif
int _task = 0;
char _parameter_file_name[LINELEN];
#ifndef CNC_SIM_ENABLE_LINUXCNC_WASM_SAFE_PROBE
int _task = 0;
extern "C" PyObject *PyInit_interpreter(void);
extern "C" PyObject *PyInit_emccanon(void);
extern "C" struct _inittab builtin_modules[];
@@ -29,6 +37,7 @@ struct _inittab builtin_modules[] = {
{"emccanon", PyInit_emccanon},
{nullptr, nullptr},
};
#endif
namespace {
@@ -73,6 +82,7 @@ bool file_mode_enabled() {
return std::getenv("CNC_SIM_RS274_FILE_MODE") != nullptr;
}
#ifndef CNC_SIM_ENABLE_LINUXCNC_WASM_SAFE_PROBE
bool write_temp_program(const char *program,
size_t program_len,
std::string *path,
@@ -113,6 +123,7 @@ bool write_temp_program(const char *program,
*path = tmpl_buffer.data();
return true;
}
#endif
int execute_file_mode(InterpBase *interp,
CanonEventSink &sink,
@@ -192,6 +203,15 @@ int parse_linuxcnc_rs274_backend(CanonEventSink &sink,
SET_BLOCK_DELETE(sink.block_delete());
if (file_mode_enabled()) {
#ifdef CNC_SIM_ENABLE_LINUXCNC_WASM_SAFE_PROBE
if (error) {
*error = "linuxcnc-rs274 file mode is not available in wasm-safe builds";
}
interp->exit();
delete interp;
cnc_sim_linuxcnc_set_canon_sink(nullptr);
return -1;
#else
std::string temp_path;
if (!write_temp_program(program, program_len, &temp_path, error)) {
interp->exit();
@@ -207,6 +227,7 @@ int parse_linuxcnc_rs274_backend(CanonEventSink &sink,
cnc_sim_linuxcnc_set_canon_sink(nullptr);
return -1;
}
#endif
} else {
std::string source(program, program + program_len);
std::istringstream input(source);
@@ -219,19 +240,45 @@ int parse_linuxcnc_rs274_backend(CanonEventSink &sink,
std::vector<SimulatorGcodeControlAction> control_actions;
if (parse_simulator_gcode_control_line(line, sink.block_delete(), &control_actions)) {
bool simulator_only_line = true;
bool all_control_actions_handled = true;
for (const auto &action : control_actions) {
emit_simulator_gcode_control_action(sink, action, line_number);
if (!can_emit_simulator_gcode_control_action(sink, action)) {
all_control_actions_handled = false;
simulator_only_line = false;
}
if (action.kind == SimulatorGcodeControlKind::RtcpState &&
!action.rtcp_enabled) {
simulator_only_line = false;
}
if (stop_if_callback_aborted(sink, error)) {
interp->exit();
delete interp;
cnc_sim_linuxcnc_set_canon_sink(nullptr);
return -1;
}
if (!all_control_actions_handled && control_actions.size() > 1) {
for (const auto &action : control_actions) {
if (!can_emit_simulator_gcode_control_action(sink, action) &&
action.kind == SimulatorGcodeControlKind::KinematicsSwitch) {
if (error) {
*error = "M-code greater than 199: M" + std::to_string(action.m_code);
}
interp->exit();
delete interp;
cnc_sim_linuxcnc_set_canon_sink(nullptr);
return -1;
}
}
}
if (all_control_actions_handled) {
for (const auto &action : control_actions) {
emit_simulator_gcode_control_action(sink, action, line_number);
if (stop_if_callback_aborted(sink, error)) {
interp->exit();
delete interp;
cnc_sim_linuxcnc_set_canon_sink(nullptr);
return -1;
}
}
}
if (!all_control_actions_handled) {
simulator_only_line = false;
}
if (simulator_only_line) {
continue;
}

View File

@@ -0,0 +1,224 @@
#include <math.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define __LINUXCNC_RTAPI_H
#define __LINUXCNC_RTAPI_MATH_H
#define __LINUXCNC_RTAPI_STRING_H
#define __LINUXCNC_HAL_H
#define __LINUXCNC_KINEMATICS_H
#define SWITCHKINS_H
#ifdef __cplusplus
#define CNC_SIM_EXTERN_C extern "C"
#else
#define CNC_SIM_EXTERN_C
#endif
#define PM_PI 3.1415926535897932384626433832795029
typedef double real_t;
typedef double hal_float_t;
typedef int hal_s32_t;
typedef bool hal_bit_t;
typedef enum { HAL_IN = 16, HAL_OUT = 32, HAL_IO = (HAL_IN | HAL_OUT) } hal_pin_dir_t;
typedef struct {
double x;
double y;
double z;
} PmCartesian;
typedef struct EmcPose {
PmCartesian tran;
double a;
double b;
double c;
double u;
double v;
double w;
} EmcPose;
typedef unsigned long int KINEMATICS_FORWARD_FLAGS;
typedef unsigned long int KINEMATICS_INVERSE_FLAGS;
typedef struct kinematics_parms {
char *sparm;
char *kinsname;
char *halprefix;
char *required_coordinates;
int max_joints;
int allow_duplicates;
int fwd_iterates_mask;
int gui_kinstype;
} kparms;
typedef int (*KF)(const double *joint,
EmcPose *pos,
const KINEMATICS_FORWARD_FLAGS *fflags,
KINEMATICS_INVERSE_FLAGS *iflags);
typedef int (*KI)(const struct EmcPose *world,
double *joint,
const KINEMATICS_INVERSE_FLAGS *iflags,
KINEMATICS_FORWARD_FLAGS *fflags);
typedef int (*KS)(const int comp_id, const char *coordinates, kparms *ksetup_parms);
void cnc_sim_scara_rtapi_print(const char *fmt, ...) {
(void)fmt;
}
void cnc_sim_scara_rtapi_print_msg(int level, const char *fmt, ...) {
(void)level;
(void)fmt;
}
void *cnc_sim_scara_hal_malloc(long int size) {
return calloc(1, (size_t)size);
}
int cnc_sim_scara_hal_pin_float_newf(hal_pin_dir_t dir,
hal_float_t **data_ptr_addr,
int comp_id,
const char *fmt,
...) {
(void)dir;
(void)comp_id;
(void)fmt;
*data_ptr_addr = (hal_float_t *)calloc(1, sizeof(hal_float_t));
return *data_ptr_addr ? 0 : -1;
}
int cnc_sim_scara_identityKinematicsSetup(const int comp_id,
const char *coordinates,
kparms *ksetup_parms) {
(void)comp_id;
(void)coordinates;
(void)ksetup_parms;
return 0;
}
int cnc_sim_scara_identityKinematicsForward(const double *joint,
struct EmcPose *world,
const KINEMATICS_FORWARD_FLAGS *fflags,
KINEMATICS_INVERSE_FLAGS *iflags) {
(void)joint;
(void)world;
(void)fflags;
(void)iflags;
return -1;
}
int cnc_sim_scara_identityKinematicsInverse(const struct EmcPose *world,
double *joint,
const KINEMATICS_INVERSE_FLAGS *iflags,
KINEMATICS_FORWARD_FLAGS *fflags) {
(void)world;
(void)joint;
(void)iflags;
(void)fflags;
return -1;
}
int cnc_sim_scara_userkKinematicsSetup(const int comp_id,
const char *coordinates,
kparms *ksetup_parms) {
(void)comp_id;
(void)coordinates;
(void)ksetup_parms;
return -1;
}
int cnc_sim_scara_userkKinematicsForward(const double *joint,
struct EmcPose *world,
const KINEMATICS_FORWARD_FLAGS *fflags,
KINEMATICS_INVERSE_FLAGS *iflags) {
(void)joint;
(void)world;
(void)fflags;
(void)iflags;
return -1;
}
int cnc_sim_scara_userkKinematicsInverse(const struct EmcPose *world,
double *joint,
const KINEMATICS_INVERSE_FLAGS *iflags,
KINEMATICS_FORWARD_FLAGS *fflags) {
(void)world;
(void)joint;
(void)iflags;
(void)fflags;
return -1;
}
#define rtapi_print cnc_sim_scara_rtapi_print
#define rtapi_print_msg cnc_sim_scara_rtapi_print_msg
#define hal_pin_float_newf cnc_sim_scara_hal_pin_float_newf
#define identityKinematicsSetup cnc_sim_scara_identityKinematicsSetup
#define identityKinematicsForward cnc_sim_scara_identityKinematicsForward
#define identityKinematicsInverse cnc_sim_scara_identityKinematicsInverse
#define userkKinematicsSetup cnc_sim_scara_userkKinematicsSetup
#define userkKinematicsForward cnc_sim_scara_userkKinematicsForward
#define userkKinematicsInverse cnc_sim_scara_userkKinematicsInverse
#define switchkinsSetup cnc_sim_scara_switchkinsSetup
#define haldata cnc_sim_scara_haldata
#define hal_malloc(size) ((struct scara_data *)cnc_sim_scara_hal_malloc(size))
#include "../../../linuxcnc/src/emc/kinematics/scarakins.c"
#undef hal_malloc
#undef haldata
#undef switchkinsSetup
#undef userkKinematicsInverse
#undef userkKinematicsForward
#undef userkKinematicsSetup
#undef identityKinematicsInverse
#undef identityKinematicsForward
#undef identityKinematicsSetup
#undef hal_pin_float_newf
#undef rtapi_print_msg
#undef rtapi_print
CNC_SIM_EXTERN_C int cnc_sim_linuxcnc_scarakins_setup(void) {
kparms kp = {0};
static char kinsname[] = "scarakins";
static char halprefix[] = "scarakins";
kp.kinsname = kinsname;
kp.halprefix = halprefix;
return scaraKinematicsSetup(0, "XYZABC", &kp);
}
CNC_SIM_EXTERN_C void cnc_sim_linuxcnc_scarakins_set_parameters(double d1,
double d2,
double d3,
double d4,
double d5,
double d6) {
*cnc_sim_scara_haldata->d1 = d1;
*cnc_sim_scara_haldata->d2 = d2;
*cnc_sim_scara_haldata->d3 = d3;
*cnc_sim_scara_haldata->d4 = d4;
*cnc_sim_scara_haldata->d5 = d5;
*cnc_sim_scara_haldata->d6 = d6;
}
CNC_SIM_EXTERN_C int cnc_sim_linuxcnc_scarakins_forward(const double *joints,
struct EmcPose *pos,
int *iflags) {
KINEMATICS_FORWARD_FLAGS fflags = 0;
KINEMATICS_INVERSE_FLAGS raw_iflags = 0;
const int result = scaraKinematicsForward(joints, pos, &fflags, &raw_iflags);
if (iflags) {
*iflags = (int)raw_iflags;
}
return result;
}
CNC_SIM_EXTERN_C int cnc_sim_linuxcnc_scarakins_inverse(const struct EmcPose *pos,
double *joints,
int iflags) {
KINEMATICS_INVERSE_FLAGS raw_iflags = (KINEMATICS_INVERSE_FLAGS)iflags;
KINEMATICS_FORWARD_FLAGS fflags = 0;
return scaraKinematicsInverse(pos, joints, &raw_iflags, &fflags);
}

View File

@@ -0,0 +1,144 @@
#include "linuxcnc_scarakins_adapter.h"
#include <cstring>
extern "C" {
struct PmCartesian {
double x;
double y;
double z;
};
struct EmcPose {
PmCartesian tran;
double a;
double b;
double c;
double u;
double v;
double w;
};
int cnc_sim_linuxcnc_scarakins_setup(void);
void cnc_sim_linuxcnc_scarakins_set_parameters(double d1,
double d2,
double d3,
double d4,
double d5,
double d6);
int cnc_sim_linuxcnc_scarakins_forward(const double *joints, EmcPose *pos, int *iflags);
int cnc_sim_linuxcnc_scarakins_inverse(const EmcPose *pos,
double *joints,
int iflags);
}
namespace {
bool initialized = false;
bool ensure_initialized() {
if (initialized) {
return true;
}
initialized = cnc_sim_linuxcnc_scarakins_setup() == 0;
return initialized;
}
void apply_parameters(const LinuxCncScaraParameters &parameters) {
cnc_sim_linuxcnc_scarakins_set_parameters(parameters.d1,
parameters.d2,
parameters.d3,
parameters.d4,
parameters.d5,
parameters.d6);
}
void to_joints(const LinuxCncScaraJoints &joints, double out[16]) {
std::memset(out, 0, sizeof(double) * 16);
out[0] = joints.j0;
out[1] = joints.j1;
out[2] = joints.j2;
out[3] = joints.j3;
out[4] = joints.j4;
out[5] = joints.j5;
}
LinuxCncScaraJoints from_joints(const double joints[16]) {
LinuxCncScaraJoints out{};
out.j0 = joints[0];
out.j1 = joints[1];
out.j2 = joints[2];
out.j3 = joints[3];
out.j4 = joints[4];
out.j5 = joints[5];
return out;
}
EmcPose to_emc_pose(const CncSimPose &pose) {
EmcPose emc{};
emc.tran.x = pose.x;
emc.tran.y = pose.y;
emc.tran.z = pose.z;
emc.a = pose.a;
emc.b = pose.b;
emc.c = pose.c;
emc.u = pose.u;
emc.v = pose.v;
emc.w = pose.w;
return emc;
}
CncSimPose from_emc_pose(const EmcPose &emc) {
CncSimPose pose{};
pose.x = emc.tran.x;
pose.y = emc.tran.y;
pose.z = emc.tran.z;
pose.a = emc.a;
pose.b = emc.b;
pose.c = emc.c;
pose.u = emc.u;
pose.v = emc.v;
pose.w = emc.w;
return pose;
}
} // namespace
bool linuxcnc_scarakins_forward(const LinuxCncScaraJoints &joints,
const LinuxCncScaraParameters &parameters,
CncSimPose *pose,
int *iflags) {
if (!ensure_initialized()) {
return false;
}
apply_parameters(parameters);
double raw_joints[16];
to_joints(joints, raw_joints);
EmcPose out{};
int raw_iflags = 0;
if (cnc_sim_linuxcnc_scarakins_forward(raw_joints, &out, &raw_iflags) != 0) {
return false;
}
if (iflags) {
*iflags = raw_iflags;
}
*pose = from_emc_pose(out);
return true;
}
bool linuxcnc_scarakins_inverse(const CncSimPose &pose,
const LinuxCncScaraParameters &parameters,
int iflags,
LinuxCncScaraJoints *joints) {
if (!ensure_initialized()) {
return false;
}
apply_parameters(parameters);
const EmcPose in = to_emc_pose(pose);
double raw_joints[16] = {};
if (cnc_sim_linuxcnc_scarakins_inverse(&in, raw_joints, iflags) != 0) {
return false;
}
*joints = from_joints(raw_joints);
return true;
}

View File

@@ -0,0 +1,12 @@
#pragma once
#include "rtcp_kinematics.h"
bool linuxcnc_scarakins_forward(const LinuxCncScaraJoints &joints,
const LinuxCncScaraParameters &parameters,
CncSimPose *pose,
int *iflags);
bool linuxcnc_scarakins_inverse(const CncSimPose &pose,
const LinuxCncScaraParameters &parameters,
int iflags,
LinuxCncScaraJoints *joints);

View File

@@ -0,0 +1,121 @@
#include <math.h>
#include <stdbool.h>
#include <stddef.h>
#define __LINUXCNC_RTAPI_H
#define __LINUXCNC_RTAPI_APP_H
#define __LINUXCNC_RTAPI_MATH_H
#define __LINUXCNC_HAL_H
#define __LINUXCNC_GO_TYPES_H
#define __LINUXCNC_KINEMATICS_H
#define __LINUXCNC_EMCPOS_H
#define MODULE_LICENSE(...)
#define EXPORT_SYMBOL(symbol)
#define PM_PI 3.1415926535897932384626433832795029
#define TO_RAD (PM_PI / 180.0)
#define TO_DEG (180.0 / PM_PI)
typedef struct {
double x;
double y;
double z;
} PmCartesian;
typedef struct EmcPose {
PmCartesian tran;
double a;
double b;
double c;
double u;
double v;
double w;
} EmcPose;
typedef enum {
KINEMATICS_IDENTITY = 1,
KINEMATICS_FORWARD_ONLY,
KINEMATICS_INVERSE_ONLY,
KINEMATICS_BOTH
} KINEMATICS_TYPE;
typedef unsigned long int KINEMATICS_FORWARD_FLAGS;
typedef unsigned long int KINEMATICS_INVERSE_FLAGS;
typedef struct kinematics_parms {
char *sparm;
char *kinsname;
char *halprefix;
char *required_coordinates;
int max_joints;
int allow_duplicates;
int fwd_iterates_mask;
int gui_kinstype;
} kparms;
#define KINS_NOT_SWITCHABLE \
extern int kinematicsSwitchable() { return 0; } \
extern int kinematicsSwitch(int switchkins_type) { (void)switchkins_type; return 0; }
#ifdef __cplusplus
extern "C" {
#endif
int cnc_sim_scorbot_kins_hal_init(const char *name) {
(void)name;
return 1;
}
int cnc_sim_scorbot_kins_hal_ready(int comp_id) {
(void)comp_id;
return 0;
}
void cnc_sim_scorbot_kins_hal_exit(int comp_id) {
(void)comp_id;
}
#define hal_init cnc_sim_scorbot_kins_hal_init
#define hal_ready cnc_sim_scorbot_kins_hal_ready
#define hal_exit cnc_sim_scorbot_kins_hal_exit
#define kinematicsType cnc_sim_scorbot_kins_kinematicsType
#define kinematicsForward cnc_sim_scorbot_kins_kinematicsForward
#define kinematicsInverse cnc_sim_scorbot_kins_kinematicsInverse
#define kinematicsSwitchable cnc_sim_scorbot_kins_kinematicsSwitchable
#define kinematicsSwitch cnc_sim_scorbot_kins_kinematicsSwitch
#define rtapi_app_main cnc_sim_scorbot_kins_rtapi_app_main
#define rtapi_app_exit cnc_sim_scorbot_kins_rtapi_app_exit
#define comp_id cnc_sim_scorbot_kins_comp_id
#include "../../../linuxcnc/src/emc/kinematics/scorbot-kins.c"
#undef comp_id
#undef rtapi_app_exit
#undef rtapi_app_main
#undef kinematicsSwitch
#undef kinematicsSwitchable
#undef kinematicsInverse
#undef kinematicsForward
#undef kinematicsType
#undef hal_exit
#undef hal_ready
#undef hal_init
int cnc_sim_linuxcnc_scorbot_kins_setup(void) {
return cnc_sim_scorbot_kins_rtapi_app_main();
}
int cnc_sim_linuxcnc_scorbot_kins_forward(const double *joints, EmcPose *pos) {
KINEMATICS_FORWARD_FLAGS fflags = 0;
KINEMATICS_INVERSE_FLAGS iflags = 0;
return cnc_sim_scorbot_kins_kinematicsForward(joints, pos, &fflags, &iflags);
}
int cnc_sim_linuxcnc_scorbot_kins_inverse(const EmcPose *pos, double *joints) {
KINEMATICS_INVERSE_FLAGS iflags = 0;
KINEMATICS_FORWARD_FLAGS fflags = 0;
return cnc_sim_scorbot_kins_kinematicsInverse(pos, joints, &iflags, &fflags);
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,110 @@
#include "linuxcnc_scorbot_kins_adapter.h"
extern "C" {
struct PmCartesian {
double x;
double y;
double z;
};
struct EmcPose {
PmCartesian tran;
double a;
double b;
double c;
double u;
double v;
double w;
};
int cnc_sim_linuxcnc_scorbot_kins_setup(void);
int cnc_sim_linuxcnc_scorbot_kins_forward(const double *joints, EmcPose *pos);
int cnc_sim_linuxcnc_scorbot_kins_inverse(const EmcPose *pos, double *joints);
}
namespace {
bool initialized = false;
bool ensure_initialized() {
if (initialized) {
return true;
}
initialized = cnc_sim_linuxcnc_scorbot_kins_setup() == 0;
return initialized;
}
void to_joints(const LinuxCncScorbotJoints &joints, double out[5]) {
out[0] = joints.j0;
out[1] = joints.j1;
out[2] = joints.j2;
out[3] = joints.j3;
out[4] = joints.j4;
}
LinuxCncScorbotJoints from_joints(const double joints[5]) {
LinuxCncScorbotJoints out{};
out.j0 = joints[0];
out.j1 = joints[1];
out.j2 = joints[2];
out.j3 = joints[3];
out.j4 = joints[4];
return out;
}
EmcPose to_emc_pose(const CncSimPose &pose) {
EmcPose emc{};
emc.tran.x = pose.x;
emc.tran.y = pose.y;
emc.tran.z = pose.z;
emc.a = pose.a;
emc.b = pose.b;
emc.c = pose.c;
emc.u = pose.u;
emc.v = pose.v;
emc.w = pose.w;
return emc;
}
CncSimPose from_emc_pose(const EmcPose &emc) {
CncSimPose pose{};
pose.x = emc.tran.x;
pose.y = emc.tran.y;
pose.z = emc.tran.z;
pose.a = emc.a;
pose.b = emc.b;
pose.c = emc.c;
pose.u = emc.u;
pose.v = emc.v;
pose.w = emc.w;
return pose;
}
} // namespace
bool linuxcnc_scorbot_kins_source_forward(const LinuxCncScorbotJoints &joints, CncSimPose *pose) {
if (!ensure_initialized()) {
return false;
}
double raw_joints[5] = {};
to_joints(joints, raw_joints);
EmcPose out{};
if (cnc_sim_linuxcnc_scorbot_kins_forward(raw_joints, &out) != 0) {
return false;
}
*pose = from_emc_pose(out);
return true;
}
bool linuxcnc_scorbot_kins_source_inverse(const CncSimPose &pose, LinuxCncScorbotJoints *joints) {
if (!ensure_initialized()) {
return false;
}
const EmcPose in = to_emc_pose(pose);
double raw_joints[5] = {};
if (cnc_sim_linuxcnc_scorbot_kins_inverse(&in, raw_joints) != 0) {
return false;
}
*joints = from_joints(raw_joints);
return true;
}

View File

@@ -0,0 +1,6 @@
#pragma once
#include "rtcp_kinematics.h"
bool linuxcnc_scorbot_kins_source_forward(const LinuxCncScorbotJoints &joints, CncSimPose *pose);
bool linuxcnc_scorbot_kins_source_inverse(const CncSimPose &pose, LinuxCncScorbotJoints *joints);

View File

@@ -0,0 +1,110 @@
// Generated by ./generate-linuxcnc-switchkins-remap-table.sh.
// Source: LinuxCNC INI MACHINE/KINEMATICS/HALFILE/SUBROUTINE_PATH/REMAP entries and
// adjacent remap_subs/{428,429,430}remap.ngc #<kinstype> assignments.
{"configs/sim/axis/vismach/5axis/bridgemill/5axis.ini", 0, 1, 2},
{"configs/sim/axis/vismach/5axis/bridgemill", 0, 1, 2},
{"bridgemill", 0, 1, 2},
{"5axis", 0, 1, 2},
{"sim-5axisbridgemill(xyzbcw)", 0, 1, 2},
{"sim-5axisbridgemill", 0, 1, 2},
{"5axiskinscoordinates=xyzbcwy", 0, 1, 2},
{"5axiskins", 0, 1, 2},
{"5axisgui.hal", 0, 1, 2},
{"5axisgui", 0, 1, 2},
{"configs/sim/axis/vismach/5axis/bridgemill/remap_subs", 0, 1, 2},
{"configs/sim/axis/vismach/5axis/table-dual-rotary/xyzab-tdr.ini", 1, 0, -1},
{"configs/sim/axis/vismach/5axis/table-dual-rotary", 1, 0, -1},
{"table-dual-rotary", 1, 0, -1},
{"xyzab-tdr", 1, 0, -1},
{"sim-xyzab-tdr-kins(switchkins)", 1, 0, -1},
{"sim-xyzab-tdr-kins", 1, 0, -1},
{"xyzab_tdr_kins", 1, 0, -1},
{"xyzab_tdr", 1, 0, -1},
{"xyzab-tdr-kins", 1, 0, -1},
{"configs/sim/axis/vismach/5axis/table-dual-rotary/remap_subs", 1, 0, -1},
{"configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzac-trt.ini", 1, 0, 2},
{"configs/sim/axis/vismach/5axis/table-rotary-tilting", 1, 0, 2},
{"table-rotary-tilting", 1, 0, 2},
{"xyzac-trt", 1, 0, 2},
{"sim-xyzac-trt-kins(switchkins)", 1, 0, 2},
{"sim-xyzac-trt-kins", 1, 0, 2},
{"xyzac-trt-kinssparm=identityfirst", 1, 0, 2},
{"xyzac-trt-kins", 1, 0, 2},
{"configs/sim/axis/vismach/5axis/table-rotary-tilting/remap_subs", 1, 0, 2},
{"configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzbc-trt.ini", 1, 0, 2},
{"xyzbc-trt", 1, 0, 2},
{"sim-xyzbc-trt-kins(switchkins)", 1, 0, 2},
{"sim-xyzbc-trt-kins", 1, 0, 2},
{"xyzbc-trt-kinssparm=identityfirst", 1, 0, 2},
{"xyzbc-trt-kins", 1, 0, 2},
{"configs/sim/axis/vismach/5axis/table-rotary_spindle-rotary-nutating/xyzacb-trsrn_twp/xyzacb-trsrn.ini", 0, 1, 2},
{"configs/sim/axis/vismach/5axis/table-rotary_spindle-rotary-nutating/xyzacb-trsrn_twp", 0, 1, 2},
{"xyzacb-trsrn_twp", 0, 1, 2},
{"xyzacb-trsrn", 0, 1, 2},
{"xyzacb-trsrn(switchkins)", 0, 1, 2},
{"xyzacb_trsrn", 0, 1, 2},
{"configs/sim/axis/vismach/5axis/table-rotary_spindle-rotary-nutating/remap_subs", 0, 1, 2},
{"configs/sim/axis/vismach/5axis/table-rotary_spindle-rotary-nutating", 0, 1, 2},
{"table-rotary_spindle-rotary-nutating", 0, 1, 2},
{"configs/sim/axis/vismach/5axis/table-rotary_spindle-rotary-nutating/xyzbca-trsrn_twp/xyzbca-trsrn.ini", 0, 1, 2},
{"configs/sim/axis/vismach/5axis/table-rotary_spindle-rotary-nutating/xyzbca-trsrn_twp", 0, 1, 2},
{"xyzbca-trsrn_twp", 0, 1, 2},
{"xyzbca-trsrn", 0, 1, 2},
{"xyzbca-trsrn(switchkins)", 0, 1, 2},
{"xyzbca_trsrn", 0, 1, 2},
{"configs/sim/axis/vismach/hexapod-sim/hexapod.ini", 0, 1, 2},
{"configs/sim/axis/vismach/hexapod-sim", 0, 1, 2},
{"hexapod-sim", 0, 1, 2},
{"hexapod", 0, 1, 2},
{"hexapod(switchkins)", 0, 1, 2},
{"genhexkins", 0, 1, 2},
{"kinematics.hal", 0, 1, 2},
{"kinematics", 0, 1, 2},
{"configs/sim/axis/vismach/hexapod-sim/remap_subs", 0, 1, 2},
{"configs/sim/axis/vismach/melfa-sim/melfa.ini", 0, 1, 2},
{"configs/sim/axis/vismach/melfa-sim", 0, 1, 2},
{"melfa-sim", 0, 1, 2},
{"melfa", 0, 1, 2},
{"melfa(mm)", 0, 1, 2},
{"genserkins", 0, 1, 2},
{"melfa_dh.hal", 0, 1, 2},
{"melfa_dh", 0, 1, 2},
{"configs/sim/axis/vismach/melfa-sim/remap_subs", 0, 1, 2},
{"configs/sim/axis/vismach/millturn/millturn.ini", 0, 1, -1},
{"configs/sim/axis/vismach/millturn", 0, 1, -1},
{"millturn", 0, 1, -1},
{"millturn(mm)", 0, 1, -1},
{"millturn.hal", 0, 1, -1},
{"configs/sim/axis/vismach/millturn/remap_subs", 0, 1, -1},
{"configs/sim/axis/vismach/puma/puma.ini", 0, 1, 2},
{"configs/sim/axis/vismach/puma", 0, 1, 2},
{"puma", 0, 1, 2},
{"puma(pumakins,switchkins)", 0, 1, 2},
{"pumakins", 0, 1, 2},
{"puma_dh.hal", 0, 1, 2},
{"puma_dh", 0, 1, 2},
{"configs/sim/axis/vismach/puma/remap_subs", 0, 1, 2},
{"configs/sim/axis/vismach/puma/puma_cube.ini", 0, 1, 2},
{"puma_cube", 0, 1, 2},
{"puma_cube.ini(pumakins)", 0, 1, 2},
{"puma_cube.ini", 0, 1, 2},
{"configs/sim/axis/vismach/puma/puma560.ini", 0, 1, 2},
{"puma560", 0, 1, 2},
{"puma560(switchkins)(inch)", 0, 1, 2},
{"puma560_dh.hal", 0, 1, 2},
{"puma560_dh", 0, 1, 2},
{"configs/sim/axis/vismach/puma/puma560_uvw.ini", 0, 1, 2},
{"puma560_uvw", 0, 1, 2},
{"configs/sim/axis/vismach/scara/scara.ini", 0, 1, 2},
{"configs/sim/axis/vismach/scara", 0, 1, 2},
{"scara", 0, 1, 2},
{"scara(genserkins,switchkins)", 0, 1, 2},
{"scarakinscoordinates=xyzcab", 0, 1, 2},
{"scarakins", 0, 1, 2},
{"configs/sim/axis/vismach/scara/remap_subs", 0, 1, 2},
{"configs/sim/qtaxis/non-trivial/scara/scara.ini", 0, 1, 2},
{"configs/sim/qtaxis/non-trivial/scara", 0, 1, 2},
{"configs/sim/qtaxis/non-trivial/scara/remap_subs", 0, 1, 2},
{"configs/sim/qtvcp_screens/non-trivial/scara/scara.ini", 0, 1, 2},
{"configs/sim/qtvcp_screens/non-trivial/scara", 0, 1, 2},
{"configs/sim/qtvcp_screens/non-trivial/scara/remap_subs", 0, 1, 2},

View File

@@ -0,0 +1,142 @@
#include <math.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdlib.h>
#define __LINUXCNC_RTAPI_H
#define __LINUXCNC_RTAPI_MATH_H
#define __LINUXCNC_RTAPI_APP_H
#define __LINUXCNC_HAL_H
#define __LINUXCNC_KINEMATICS_H
#define __LINUXCNC_EMCPOS_H
#define MODULE_LICENSE(...)
#define EXPORT_SYMBOL(symbol)
typedef double real_t;
typedef double hal_float_t;
typedef enum { HAL_IN = 16, HAL_OUT = 32, HAL_IO = (HAL_IN | HAL_OUT) } hal_pin_dir_t;
typedef struct {
double x;
double y;
double z;
} PmCartesian;
typedef struct EmcPose {
PmCartesian tran;
double a;
double b;
double c;
double u;
double v;
double w;
} EmcPose;
typedef enum {
KINEMATICS_IDENTITY = 1,
KINEMATICS_FORWARD_ONLY,
KINEMATICS_INVERSE_ONLY,
KINEMATICS_BOTH
} KINEMATICS_TYPE;
typedef unsigned long int KINEMATICS_FORWARD_FLAGS;
typedef unsigned long int KINEMATICS_INVERSE_FLAGS;
typedef struct kinematics_parms {
char *sparm;
char *kinsname;
char *halprefix;
char *required_coordinates;
int max_joints;
int allow_duplicates;
int fwd_iterates_mask;
int gui_kinstype;
} kparms;
#define KINS_NOT_SWITCHABLE \
extern int kinematicsSwitchable() { return 0; } \
extern int kinematicsSwitch(int switchkins_type) { (void)switchkins_type; return 0; }
#ifdef __cplusplus
extern "C" {
#endif
int cnc_sim_tripodkins_hal_init(const char *name) {
(void)name;
return 1;
}
void *cnc_sim_tripodkins_hal_malloc(long int size) {
return calloc(1, (size_t)size);
}
int cnc_sim_tripodkins_hal_ready(int comp_id) {
(void)comp_id;
return 0;
}
void cnc_sim_tripodkins_hal_exit(int comp_id) {
(void)comp_id;
}
int cnc_sim_tripodkins_hal_pin_float_new(const char *name,
hal_pin_dir_t dir,
hal_float_t **data_ptr_addr,
int comp_id) {
(void)name;
(void)dir;
(void)comp_id;
*data_ptr_addr = (hal_float_t *)calloc(1, sizeof(hal_float_t));
return *data_ptr_addr ? 0 : -1;
}
#define hal_init cnc_sim_tripodkins_hal_init
#define hal_malloc(size) ((struct haldata *)cnc_sim_tripodkins_hal_malloc(size))
#define hal_pin_float_new cnc_sim_tripodkins_hal_pin_float_new
#define hal_ready cnc_sim_tripodkins_hal_ready
#define hal_exit cnc_sim_tripodkins_hal_exit
#define kinematicsType cnc_sim_tripodkins_kinematicsType
#define kinematicsForward cnc_sim_tripodkins_kinematicsForward
#define kinematicsInverse cnc_sim_tripodkins_kinematicsInverse
#define kinematicsSwitchable cnc_sim_tripodkins_kinematicsSwitchable
#define kinematicsSwitch cnc_sim_tripodkins_kinematicsSwitch
#define rtapi_app_main cnc_sim_tripodkins_rtapi_app_main
#define rtapi_app_exit cnc_sim_tripodkins_rtapi_app_exit
#define comp_id cnc_sim_tripodkins_comp_id
#define haldata cnc_sim_tripodkins_haldata
#include "../../../linuxcnc/src/emc/kinematics/tripodkins.c"
#undef haldata
#undef comp_id
#undef rtapi_app_exit
#undef rtapi_app_main
#undef kinematicsSwitch
#undef kinematicsSwitchable
#undef kinematicsInverse
#undef kinematicsForward
#undef kinematicsType
#undef hal_exit
#undef hal_ready
#undef hal_pin_float_new
#undef hal_malloc
#undef hal_init
int cnc_sim_linuxcnc_tripodkins_setup(void) {
return cnc_sim_tripodkins_rtapi_app_main();
}
int cnc_sim_linuxcnc_tripodkins_forward(const double *joints, EmcPose *pos) {
KINEMATICS_FORWARD_FLAGS fflags = 0;
KINEMATICS_INVERSE_FLAGS iflags = 0;
return cnc_sim_tripodkins_kinematicsForward(joints, pos, &fflags, &iflags);
}
int cnc_sim_linuxcnc_tripodkins_inverse(const EmcPose *pos, double *joints) {
KINEMATICS_INVERSE_FLAGS iflags = 0;
KINEMATICS_FORWARD_FLAGS fflags = 0;
return cnc_sim_tripodkins_kinematicsInverse(pos, joints, &iflags, &fflags);
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,94 @@
#include "linuxcnc_tripodkins_adapter.h"
#include <cstring>
extern "C" {
struct PmCartesian {
double x;
double y;
double z;
};
struct EmcPose {
PmCartesian tran;
double a;
double b;
double c;
double u;
double v;
double w;
};
int cnc_sim_linuxcnc_tripodkins_setup(void);
int cnc_sim_linuxcnc_tripodkins_forward(const double *joints, EmcPose *pos);
int cnc_sim_linuxcnc_tripodkins_inverse(const EmcPose *pos, double *joints);
}
namespace {
bool initialized = false;
bool ensure_initialized() {
if (initialized) {
return true;
}
initialized = cnc_sim_linuxcnc_tripodkins_setup() == 0;
return initialized;
}
EmcPose to_emc_pose(const CncSimPose &pose) {
EmcPose emc{};
emc.tran.x = pose.x;
emc.tran.y = pose.y;
emc.tran.z = pose.z;
emc.a = pose.a;
emc.b = pose.b;
emc.c = pose.c;
emc.u = pose.u;
emc.v = pose.v;
emc.w = pose.w;
return emc;
}
CncSimPose from_emc_pose(const EmcPose &emc) {
CncSimPose pose{};
pose.x = emc.tran.x;
pose.y = emc.tran.y;
pose.z = emc.tran.z;
pose.a = emc.a;
pose.b = emc.b;
pose.c = emc.c;
pose.u = emc.u;
pose.v = emc.v;
pose.w = emc.w;
return pose;
}
} // namespace
bool linuxcnc_tripodkins_source_forward(const LinuxCncTripodJoints &joints, CncSimPose *pose) {
if (!ensure_initialized()) {
return false;
}
double raw_joints[3];
std::memcpy(raw_joints, joints.strut, sizeof(raw_joints));
EmcPose out{};
if (cnc_sim_linuxcnc_tripodkins_forward(raw_joints, &out) != 0) {
return false;
}
*pose = from_emc_pose(out);
return true;
}
bool linuxcnc_tripodkins_source_inverse(const CncSimPose &pose, LinuxCncTripodJoints *joints) {
if (!ensure_initialized()) {
return false;
}
const EmcPose emc_pose = to_emc_pose(pose);
double raw_joints[3] = {};
if (cnc_sim_linuxcnc_tripodkins_inverse(&emc_pose, raw_joints) != 0) {
return false;
}
std::memcpy(joints->strut, raw_joints, sizeof(raw_joints));
return true;
}

View File

@@ -0,0 +1,6 @@
#pragma once
#include "rtcp_kinematics.h"
bool linuxcnc_tripodkins_source_forward(const LinuxCncTripodJoints &joints, CncSimPose *pose);
bool linuxcnc_tripodkins_source_inverse(const CncSimPose &pose, LinuxCncTripodJoints *joints);

View File

@@ -0,0 +1,163 @@
#include <ctype.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#define __LINUXCNC_RTAPI_H
#define __LINUXCNC_RTAPI_APP_H
#define __LINUXCNC_RTAPI_MATH_H
#define __LINUXCNC_RTAPI_STRING_H
#define __LINUXCNC_HAL_H
#define __LINUXCNC_EMCMOTCFG_H
#define __LINUXCNC_EMCPOS_H
#define __LINUXCNC_KINEMATICS_H
#define MODULE_LICENSE(...)
#define EXPORT_SYMBOL(symbol)
#define RTAPI_MP_STRING(name, desc)
#define RTAPI_MSG_ERR 1
#define EMCMOT_MAX_JOINTS 16
#define EMCMOT_MAX_AXIS 9
typedef struct {
double x;
double y;
double z;
} PmCartesian;
typedef struct EmcPose {
PmCartesian tran;
double a;
double b;
double c;
double u;
double v;
double w;
} EmcPose;
typedef enum {
KINEMATICS_IDENTITY = 1,
KINEMATICS_FORWARD_ONLY,
KINEMATICS_INVERSE_ONLY,
KINEMATICS_BOTH
} KINEMATICS_TYPE;
typedef unsigned long int KINEMATICS_FORWARD_FLAGS;
typedef unsigned long int KINEMATICS_INVERSE_FLAGS;
typedef struct kinematics_parms {
char *sparm;
char *kinsname;
char *halprefix;
char *required_coordinates;
int max_joints;
int allow_duplicates;
int fwd_iterates_mask;
int gui_kinstype;
} kparms;
#define KINS_NOT_SWITCHABLE \
extern int kinematicsSwitchable() { return 0; } \
extern int kinematicsSwitch(int switchkins_type) { (void)switchkins_type; return 0; }
#ifdef __cplusplus
extern "C" {
#endif
void cnc_sim_trivkins_rtapi_print(const char *fmt, ...) {
(void)fmt;
}
void cnc_sim_trivkins_rtapi_print_msg(int level, const char *fmt, ...) {
(void)level;
(void)fmt;
}
int cnc_sim_trivkins_hal_init(const char *name) {
(void)name;
return 1;
}
int cnc_sim_trivkins_hal_ready(int comp_id) {
(void)comp_id;
return 0;
}
void cnc_sim_trivkins_hal_exit(int comp_id) {
(void)comp_id;
}
#define rtapi_print cnc_sim_trivkins_rtapi_print
#define rtapi_print_msg cnc_sim_trivkins_rtapi_print_msg
#define kinematicsType cnc_sim_trivkins_kinematicsType
KINEMATICS_TYPE kinematicsType(void);
#define map_coordinates_to_jnumbers cnc_sim_trivkins_map_coordinates_to_jnumbers
#define mapped_joints_to_position cnc_sim_trivkins_mapped_joints_to_position
#define position_to_mapped_joints cnc_sim_trivkins_position_to_mapped_joints
#define identityKinematicsSetup cnc_sim_trivkins_identityKinematicsSetup
#define identityKinematicsForward cnc_sim_trivkins_identityKinematicsForward
#define identityKinematicsInverse cnc_sim_trivkins_identityKinematicsInverse
#include "../../../linuxcnc/src/emc/kinematics/kins_util.c"
#define hal_init cnc_sim_trivkins_hal_init
#define hal_ready cnc_sim_trivkins_hal_ready
#define hal_exit cnc_sim_trivkins_hal_exit
#define kinematicsForward cnc_sim_trivkins_kinematicsForward
#define kinematicsInverse cnc_sim_trivkins_kinematicsInverse
#define kinematicsSwitchable cnc_sim_trivkins_kinematicsSwitchable
#define kinematicsSwitch cnc_sim_trivkins_kinematicsSwitch
#define rtapi_app_main cnc_sim_trivkins_rtapi_app_main
#define rtapi_app_exit cnc_sim_trivkins_rtapi_app_exit
#define comp_id cnc_sim_trivkins_comp_id
#define coordinates cnc_sim_trivkins_coordinates
#define kinstype cnc_sim_trivkins_kinstype
#include "../../../linuxcnc/src/emc/kinematics/trivkins.c"
#undef kinstype
#undef coordinates
#undef comp_id
#undef rtapi_app_exit
#undef rtapi_app_main
#undef kinematicsSwitch
#undef kinematicsSwitchable
#undef kinematicsInverse
#undef kinematicsForward
#undef hal_exit
#undef hal_ready
#undef hal_init
#undef identityKinematicsInverse
#undef identityKinematicsForward
#undef identityKinematicsSetup
#undef position_to_mapped_joints
#undef mapped_joints_to_position
#undef map_coordinates_to_jnumbers
#undef kinematicsType
#undef rtapi_print_msg
#undef rtapi_print
int cnc_sim_linuxcnc_trivkins_setup(void) {
return cnc_sim_trivkins_rtapi_app_main();
}
int cnc_sim_linuxcnc_trivkins_forward(const double *joints, EmcPose *pos) {
KINEMATICS_FORWARD_FLAGS fflags = 0;
KINEMATICS_INVERSE_FLAGS iflags = 0;
return cnc_sim_trivkins_kinematicsForward(joints, pos, &fflags, &iflags);
}
int cnc_sim_linuxcnc_trivkins_inverse(const EmcPose *pos, double *joints) {
KINEMATICS_INVERSE_FLAGS iflags = 0;
KINEMATICS_FORWARD_FLAGS fflags = 0;
return cnc_sim_trivkins_kinematicsInverse(pos, joints, &iflags, &fflags);
}
int cnc_sim_linuxcnc_trivkins_type(void) {
return (int)cnc_sim_trivkins_kinematicsType();
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,129 @@
#include "linuxcnc_trivkins_adapter.h"
#include <cstring>
extern "C" {
struct PmCartesian {
double x;
double y;
double z;
};
struct EmcPose {
PmCartesian tran;
double a;
double b;
double c;
double u;
double v;
double w;
};
int cnc_sim_linuxcnc_trivkins_setup(void);
int cnc_sim_linuxcnc_trivkins_forward(const double *joints, EmcPose *pos);
int cnc_sim_linuxcnc_trivkins_inverse(const EmcPose *pos, double *joints);
int cnc_sim_linuxcnc_trivkins_type(void);
}
namespace {
bool initialized = false;
bool ensure_initialized() {
if (initialized) {
return true;
}
initialized = cnc_sim_linuxcnc_trivkins_setup() == 0;
return initialized;
}
void to_joints(const LinuxCncAxisJoints &joints, double out[16]) {
std::memset(out, 0, sizeof(double) * 16);
out[0] = joints.x;
out[1] = joints.y;
out[2] = joints.z;
out[3] = joints.a;
out[4] = joints.b;
out[5] = joints.c;
out[6] = joints.u;
out[7] = joints.v;
out[8] = joints.w;
}
LinuxCncAxisJoints from_joints(const double joints[16]) {
LinuxCncAxisJoints out{};
out.x = joints[0];
out.y = joints[1];
out.z = joints[2];
out.a = joints[3];
out.b = joints[4];
out.c = joints[5];
out.u = joints[6];
out.v = joints[7];
out.w = joints[8];
return out;
}
EmcPose to_emc_pose(const CncSimPose &pose) {
EmcPose emc{};
emc.tran.x = pose.x;
emc.tran.y = pose.y;
emc.tran.z = pose.z;
emc.a = pose.a;
emc.b = pose.b;
emc.c = pose.c;
emc.u = pose.u;
emc.v = pose.v;
emc.w = pose.w;
return emc;
}
CncSimPose from_emc_pose(const EmcPose &emc) {
CncSimPose pose{};
pose.x = emc.tran.x;
pose.y = emc.tran.y;
pose.z = emc.tran.z;
pose.a = emc.a;
pose.b = emc.b;
pose.c = emc.c;
pose.u = emc.u;
pose.v = emc.v;
pose.w = emc.w;
return pose;
}
} // namespace
bool linuxcnc_trivkins_source_forward(const LinuxCncAxisJoints &joints, CncSimPose *pose) {
if (!ensure_initialized()) {
return false;
}
double raw_joints[16];
to_joints(joints, raw_joints);
EmcPose out{};
if (cnc_sim_linuxcnc_trivkins_forward(raw_joints, &out) != 0) {
return false;
}
*pose = from_emc_pose(out);
return true;
}
bool linuxcnc_trivkins_source_inverse(const CncSimPose &pose, LinuxCncAxisJoints *joints) {
if (!ensure_initialized()) {
return false;
}
const EmcPose in = to_emc_pose(pose);
double raw_joints[16] = {};
if (cnc_sim_linuxcnc_trivkins_inverse(&in, raw_joints) != 0) {
return false;
}
*joints = from_joints(raw_joints);
return true;
}
int linuxcnc_trivkins_source_kinematics_type() {
if (!ensure_initialized()) {
return 0;
}
return cnc_sim_linuxcnc_trivkins_type();
}

View File

@@ -0,0 +1,7 @@
#pragma once
#include "rtcp_kinematics.h"
bool linuxcnc_trivkins_source_forward(const LinuxCncAxisJoints &joints, CncSimPose *pose);
bool linuxcnc_trivkins_source_inverse(const CncSimPose &pose, LinuxCncAxisJoints *joints);
int linuxcnc_trivkins_source_kinematics_type();

View File

@@ -0,0 +1,207 @@
#include <ctype.h>
#include <math.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define __LINUXCNC_RTAPI_H
#define __LINUXCNC_RTAPI_MATH_H
#define __LINUXCNC_RTAPI_STRING_H
#define __LINUXCNC_RTAPI_CTYPE_H
#define __LINUXCNC_HAL_H
#define __LINUXCNC_EMCMOTCFG_H
#define __LINUXCNC_KINEMATICS_H
#define RTAPI_MSG_ERR 1
#define PM_PI 3.1415926535897932384626433832795029
#define TO_RAD (PM_PI / 180.0)
#define EMCMOT_MAX_JOINTS 16
#define EMCMOT_MAX_AXIS 9
typedef double real_t;
typedef double hal_float_t;
typedef bool hal_bit_t;
typedef enum { HAL_IN = 16, HAL_OUT = 32, HAL_IO = (HAL_IN | HAL_OUT) } hal_pin_dir_t;
typedef struct {
double x;
double y;
double z;
} PmCartesian;
typedef struct EmcPose {
PmCartesian tran;
double a;
double b;
double c;
double u;
double v;
double w;
} EmcPose;
typedef unsigned long int KINEMATICS_FORWARD_FLAGS;
typedef unsigned long int KINEMATICS_INVERSE_FLAGS;
typedef struct kinematics_parms {
char *sparm;
char *kinsname;
char *halprefix;
char *required_coordinates;
int max_joints;
int allow_duplicates;
int fwd_iterates_mask;
int gui_kinstype;
} kparms;
static int cnc_sim_axis_idx_for_jno[EMCMOT_MAX_JOINTS];
static int cnc_sim_max_joints;
#ifdef __cplusplus
extern "C" {
#endif
void rtapi_print(const char *fmt, ...) {
(void)fmt;
}
void rtapi_print_msg(int level, const char *fmt, ...) {
(void)level;
(void)fmt;
}
void *cnc_sim_hal_malloc(long int size) {
return calloc(1, (size_t)size);
}
int hal_pin_float_newf(hal_pin_dir_t dir, hal_float_t **data_ptr_addr, int comp_id, const char *fmt, ...) {
(void)dir;
(void)comp_id;
(void)fmt;
*data_ptr_addr = (hal_float_t *)calloc(1, sizeof(hal_float_t));
return *data_ptr_addr ? 0 : -1;
}
int hal_pin_bit_newf(hal_pin_dir_t dir, hal_bit_t **data_ptr_addr, int comp_id, const char *fmt, ...) {
(void)dir;
(void)comp_id;
(void)fmt;
*data_ptr_addr = (hal_bit_t *)calloc(1, sizeof(hal_bit_t));
return *data_ptr_addr ? 0 : -1;
}
int map_coordinates_to_jnumbers(const char *coordinates,
const int max_joints,
const int allow_duplicates,
int axis_idx_for_jno[]) {
(void)allow_duplicates;
const char *letters = "XYZABCUVW";
int jno = 0;
for (int i = 0; i < EMCMOT_MAX_JOINTS; ++i) {
axis_idx_for_jno[i] = -1;
cnc_sim_axis_idx_for_jno[i] = -1;
}
while (*coordinates) {
const char *found = strchr(letters, toupper((unsigned char)*coordinates));
if (!found || jno >= max_joints) {
return -1;
}
axis_idx_for_jno[jno++] = (int)(found - letters);
++coordinates;
}
cnc_sim_max_joints = jno;
for (int i = 0; i < EMCMOT_MAX_JOINTS; ++i) {
cnc_sim_axis_idx_for_jno[i] = axis_idx_for_jno[i];
}
return 0;
}
int position_to_mapped_joints(const int max_joints, const EmcPose *pos, double *joints) {
for (int jno = 0; jno < max_joints; ++jno) {
switch (cnc_sim_axis_idx_for_jno[jno]) {
case 0: joints[jno] = pos->tran.x; break;
case 1: joints[jno] = pos->tran.y; break;
case 2: joints[jno] = pos->tran.z; break;
case 3: joints[jno] = pos->a; break;
case 4: joints[jno] = pos->b; break;
case 5: joints[jno] = pos->c; break;
case 6: joints[jno] = pos->u; break;
case 7: joints[jno] = pos->v; break;
case 8: joints[jno] = pos->w; break;
default: joints[jno] = 0.0; break;
}
}
return 0;
}
#define hal_malloc(size) ((struct haldata *)cnc_sim_hal_malloc(size))
#include "../../../linuxcnc/src/emc/kinematics/trtfuncs.c"
#undef hal_malloc
void cnc_sim_linuxcnc_trtfuncs_reset_setup_state(void) {
trtfuncs_max_joints = 0;
JX = -1;
JY = -1;
JZ = -1;
JA = -1;
JB = -1;
JC = -1;
JU = -1;
JV = -1;
JW = -1;
haldata = NULL;
cnc_sim_max_joints = 0;
for (int i = 0; i < EMCMOT_MAX_JOINTS; ++i) {
cnc_sim_axis_idx_for_jno[i] = -1;
}
}
int cnc_sim_linuxcnc_trtfuncs_setup_xyzbc(void) {
kparms kp = {0};
static char kinsname[] = "xyzbc-trt-kins";
static char halprefix[] = "xyzbc-trt-kins";
static char required_coordinates[] = "XYZBC";
kp.kinsname = kinsname;
kp.halprefix = halprefix;
kp.required_coordinates = required_coordinates;
kp.max_joints = EMCMOT_MAX_JOINTS;
kp.allow_duplicates = 1;
return trtKinematicsSetup(0, "XYZBC", &kp);
}
int cnc_sim_linuxcnc_trtfuncs_setup_xyzac(void) {
kparms kp = {0};
static char kinsname[] = "xyzac-trt-kins";
static char halprefix[] = "xyzac-trt-kins";
static char required_coordinates[] = "XYZAC";
kp.kinsname = kinsname;
kp.halprefix = halprefix;
kp.required_coordinates = required_coordinates;
kp.max_joints = EMCMOT_MAX_JOINTS;
kp.allow_duplicates = 1;
return trtKinematicsSetup(0, "XYZAC", &kp);
}
void cnc_sim_linuxcnc_trtfuncs_set_pins(double x_rot_point,
double y_rot_point,
double z_rot_point,
double x_offset,
double y_offset,
double z_offset,
double tool_offset,
bool conventional_directions) {
*haldata->x_rot_point = x_rot_point;
*haldata->y_rot_point = y_rot_point;
*haldata->z_rot_point = z_rot_point;
*haldata->x_offset = x_offset;
*haldata->y_offset = y_offset;
*haldata->z_offset = z_offset;
*haldata->tool_offset = tool_offset;
*haldata->conventional_directions = conventional_directions;
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,241 @@
#include "linuxcnc_trtfuncs_adapter.h"
#include <cstring>
extern "C" {
struct PmCartesian {
double x;
double y;
double z;
};
struct EmcPose {
PmCartesian tran;
double a;
double b;
double c;
double u;
double v;
double w;
};
typedef unsigned long int KINEMATICS_FORWARD_FLAGS;
typedef unsigned long int KINEMATICS_INVERSE_FLAGS;
int cnc_sim_linuxcnc_trtfuncs_setup_xyzbc(void);
int cnc_sim_linuxcnc_trtfuncs_setup_xyzac(void);
void cnc_sim_linuxcnc_trtfuncs_set_pins(double x_rot_point,
double y_rot_point,
double z_rot_point,
double x_offset,
double y_offset,
double z_offset,
double tool_offset,
bool conventional_directions);
void cnc_sim_linuxcnc_trtfuncs_reset_setup_state(void);
int xyzbcKinematicsForward(const double *joints,
EmcPose *pos,
const KINEMATICS_FORWARD_FLAGS *fflags,
KINEMATICS_INVERSE_FLAGS *iflags);
int xyzbcKinematicsInverse(const EmcPose *pos,
double *joints,
const KINEMATICS_INVERSE_FLAGS *iflags,
KINEMATICS_FORWARD_FLAGS *fflags);
int xyzacKinematicsForward(const double *joints,
EmcPose *pos,
const KINEMATICS_FORWARD_FLAGS *fflags,
KINEMATICS_INVERSE_FLAGS *iflags);
int xyzacKinematicsInverse(const EmcPose *pos,
double *joints,
const KINEMATICS_INVERSE_FLAGS *iflags,
KINEMATICS_FORWARD_FLAGS *fflags);
}
namespace {
enum class TrtSetup {
None,
Xyzbc,
Xyzac,
};
TrtSetup current_setup = TrtSetup::None;
bool ensure_xyzbc() {
if (current_setup == TrtSetup::Xyzbc) {
return true;
}
cnc_sim_linuxcnc_trtfuncs_reset_setup_state();
if (cnc_sim_linuxcnc_trtfuncs_setup_xyzbc() != 0) {
current_setup = TrtSetup::None;
return false;
}
current_setup = TrtSetup::Xyzbc;
return true;
}
bool ensure_xyzac() {
if (current_setup == TrtSetup::Xyzac) {
return true;
}
cnc_sim_linuxcnc_trtfuncs_reset_setup_state();
if (cnc_sim_linuxcnc_trtfuncs_setup_xyzac() != 0) {
current_setup = TrtSetup::None;
return false;
}
current_setup = TrtSetup::Xyzac;
return true;
}
void apply_parameters(const LinuxCncXyzbcTrtParameters &parameters) {
cnc_sim_linuxcnc_trtfuncs_set_pins(parameters.x_rot_point,
parameters.y_rot_point,
parameters.z_rot_point,
parameters.x_offset,
parameters.y_offset,
parameters.z_offset,
parameters.tool_offset,
parameters.conventional_directions);
}
EmcPose to_emc_pose(const CncSimPose &pose) {
EmcPose emc{};
emc.tran.x = pose.x;
emc.tran.y = pose.y;
emc.tran.z = pose.z;
emc.a = pose.a;
emc.b = pose.b;
emc.c = pose.c;
emc.u = pose.u;
emc.v = pose.v;
emc.w = pose.w;
return emc;
}
CncSimPose from_emc_pose(const EmcPose &emc) {
CncSimPose pose{};
pose.x = emc.tran.x;
pose.y = emc.tran.y;
pose.z = emc.tran.z;
pose.a = emc.a;
pose.b = emc.b;
pose.c = emc.c;
pose.u = emc.u;
pose.v = emc.v;
pose.w = emc.w;
return pose;
}
void to_xyzbc_joints(const LinuxCncFiveAxisJoints &joints, double out[16]) {
std::memset(out, 0, sizeof(double) * 16);
out[0] = joints.x;
out[1] = joints.y;
out[2] = joints.z;
out[3] = joints.b;
out[4] = joints.c;
}
void to_xyzac_joints(const LinuxCncFiveAxisJoints &joints, double out[16]) {
std::memset(out, 0, sizeof(double) * 16);
out[0] = joints.x;
out[1] = joints.y;
out[2] = joints.z;
out[3] = joints.a;
out[4] = joints.c;
}
LinuxCncFiveAxisJoints from_xyzbc_joints(const double joints[16]) {
LinuxCncFiveAxisJoints out{};
out.x = joints[0];
out.y = joints[1];
out.z = joints[2];
out.b = joints[3];
out.c = joints[4];
return out;
}
LinuxCncFiveAxisJoints from_xyzac_joints(const double joints[16]) {
LinuxCncFiveAxisJoints out{};
out.x = joints[0];
out.y = joints[1];
out.z = joints[2];
out.a = joints[3];
out.c = joints[4];
return out;
}
} // namespace
bool linuxcnc_trtfuncs_xyzbc_forward(const LinuxCncFiveAxisJoints &joints,
const LinuxCncXyzbcTrtParameters &parameters,
CncSimPose *pose) {
if (!ensure_xyzbc()) {
return false;
}
apply_parameters(parameters);
double raw_joints[16];
to_xyzbc_joints(joints, raw_joints);
EmcPose out{};
KINEMATICS_FORWARD_FLAGS fflags = 0;
KINEMATICS_INVERSE_FLAGS iflags = 0;
if (xyzbcKinematicsForward(raw_joints, &out, &fflags, &iflags) != 0) {
return false;
}
*pose = from_emc_pose(out);
return true;
}
bool linuxcnc_trtfuncs_xyzbc_inverse(const CncSimPose &pose,
const LinuxCncXyzbcTrtParameters &parameters,
LinuxCncFiveAxisJoints *joints) {
if (!ensure_xyzbc()) {
return false;
}
apply_parameters(parameters);
const EmcPose in = to_emc_pose(pose);
double raw_joints[16] = {};
KINEMATICS_INVERSE_FLAGS iflags = 0;
KINEMATICS_FORWARD_FLAGS fflags = 0;
if (xyzbcKinematicsInverse(&in, raw_joints, &iflags, &fflags) != 0) {
return false;
}
*joints = from_xyzbc_joints(raw_joints);
return true;
}
bool linuxcnc_trtfuncs_xyzac_forward(const LinuxCncFiveAxisJoints &joints,
const LinuxCncXyzbcTrtParameters &parameters,
CncSimPose *pose) {
if (!ensure_xyzac()) {
return false;
}
apply_parameters(parameters);
double raw_joints[16];
to_xyzac_joints(joints, raw_joints);
EmcPose out{};
KINEMATICS_FORWARD_FLAGS fflags = 0;
KINEMATICS_INVERSE_FLAGS iflags = 0;
if (xyzacKinematicsForward(raw_joints, &out, &fflags, &iflags) != 0) {
return false;
}
*pose = from_emc_pose(out);
return true;
}
bool linuxcnc_trtfuncs_xyzac_inverse(const CncSimPose &pose,
const LinuxCncXyzbcTrtParameters &parameters,
LinuxCncFiveAxisJoints *joints) {
if (!ensure_xyzac()) {
return false;
}
apply_parameters(parameters);
const EmcPose in = to_emc_pose(pose);
double raw_joints[16] = {};
KINEMATICS_INVERSE_FLAGS iflags = 0;
KINEMATICS_FORWARD_FLAGS fflags = 0;
if (xyzacKinematicsInverse(&in, raw_joints, &iflags, &fflags) != 0) {
return false;
}
*joints = from_xyzac_joints(raw_joints);
return true;
}

View File

@@ -0,0 +1,16 @@
#pragma once
#include "rtcp_kinematics.h"
bool linuxcnc_trtfuncs_xyzbc_forward(const LinuxCncFiveAxisJoints &joints,
const LinuxCncXyzbcTrtParameters &parameters,
CncSimPose *pose);
bool linuxcnc_trtfuncs_xyzbc_inverse(const CncSimPose &pose,
const LinuxCncXyzbcTrtParameters &parameters,
LinuxCncFiveAxisJoints *joints);
bool linuxcnc_trtfuncs_xyzac_forward(const LinuxCncFiveAxisJoints &joints,
const LinuxCncXyzbcTrtParameters &parameters,
CncSimPose *pose);
bool linuxcnc_trtfuncs_xyzac_inverse(const CncSimPose &pose,
const LinuxCncXyzbcTrtParameters &parameters,
LinuxCncFiveAxisJoints *joints);

View File

@@ -0,0 +1,154 @@
#include <ctype.h>
#include <math.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#define __LINUXCNC_RTAPI_H
#define __LINUXCNC_RTAPI_STRING_H
#define __LINUXCNC_HAL_H
#define __LINUXCNC_EMCMOTCFG_H
#define __LINUXCNC_EMCPOS_H
#define __LINUXCNC_KINEMATICS_H
#define RTAPI_MSG_ERR 1
#define EMCMOT_MAX_JOINTS 16
#define EMCMOT_MAX_AXIS 9
typedef double hal_float_t;
typedef int hal_s32_t;
typedef bool hal_bit_t;
typedef enum { HAL_IN = 16, HAL_OUT = 32, HAL_IO = (HAL_IN | HAL_OUT) } hal_pin_dir_t;
typedef struct {
double x;
double y;
double z;
} PmCartesian;
typedef struct EmcPose {
PmCartesian tran;
double a;
double b;
double c;
double u;
double v;
double w;
} EmcPose;
typedef unsigned long int KINEMATICS_FORWARD_FLAGS;
typedef unsigned long int KINEMATICS_INVERSE_FLAGS;
typedef enum {
KINEMATICS_IDENTITY = 1,
KINEMATICS_FORWARD_ONLY,
KINEMATICS_INVERSE_ONLY,
KINEMATICS_BOTH
} KINEMATICS_TYPE;
typedef struct kinematics_parms {
char *sparm;
char *kinsname;
char *halprefix;
char *required_coordinates;
int max_joints;
int allow_duplicates;
int fwd_iterates_mask;
int gui_kinstype;
} kparms;
#ifdef __cplusplus
extern "C" {
#endif
void cnc_sim_userk_rtapi_print(const char *fmt, ...) {
(void)fmt;
}
void cnc_sim_userk_rtapi_print_msg(int level, const char *fmt, ...) {
(void)level;
(void)fmt;
}
void *cnc_sim_userk_hal_malloc(long int size) {
return calloc(1, (size_t)size);
}
int cnc_sim_userk_hal_pin_s32_new(const char *name,
hal_pin_dir_t dir,
hal_s32_t **data_ptr_addr,
int comp_id) {
(void)name;
(void)dir;
(void)comp_id;
*data_ptr_addr = (hal_s32_t *)calloc(1, sizeof(hal_s32_t));
return *data_ptr_addr ? 0 : -1;
}
KINEMATICS_TYPE cnc_sim_userk_kinematicsType(void) {
return KINEMATICS_BOTH;
}
#define rtapi_print cnc_sim_userk_rtapi_print
#define rtapi_print_msg cnc_sim_userk_rtapi_print_msg
#define kinematicsType cnc_sim_userk_kinematicsType
#define hal_pin_s32_new cnc_sim_userk_hal_pin_s32_new
#define map_coordinates_to_jnumbers cnc_sim_userk_map_coordinates_to_jnumbers
#define mapped_joints_to_position cnc_sim_userk_mapped_joints_to_position
#define position_to_mapped_joints cnc_sim_userk_position_to_mapped_joints
#define identityKinematicsSetup cnc_sim_userk_identityKinematicsSetup
#define identityKinematicsForward cnc_sim_userk_identityKinematicsForward
#define identityKinematicsInverse cnc_sim_userk_identityKinematicsInverse
#define userkKinematicsSetup cnc_sim_userk_userkKinematicsSetup
#define userkKinematicsForward cnc_sim_userk_userkKinematicsForward
#define userkKinematicsInverse cnc_sim_userk_userkKinematicsInverse
#include "../../../linuxcnc/src/emc/kinematics/kins_util.c"
#define hal_malloc(size) ((struct udata *)cnc_sim_userk_hal_malloc(size))
#include "../../../linuxcnc/src/emc/kinematics/userkfuncs.c"
#undef hal_malloc
#undef userkKinematicsInverse
#undef userkKinematicsForward
#undef userkKinematicsSetup
#undef identityKinematicsInverse
#undef identityKinematicsForward
#undef identityKinematicsSetup
#undef position_to_mapped_joints
#undef mapped_joints_to_position
#undef map_coordinates_to_jnumbers
#undef hal_pin_s32_new
#undef kinematicsType
#undef rtapi_print_msg
#undef rtapi_print
int cnc_sim_linuxcnc_userkfuncs_setup(void) {
kparms kp = {0};
static char kinsname[] = "userkfuncs";
static char halprefix[] = "userk";
kp.kinsname = kinsname;
kp.halprefix = halprefix;
kp.max_joints = EMCMOT_MAX_JOINTS;
kp.allow_duplicates = 1;
if (cnc_sim_userk_identityKinematicsSetup(0, "XYZBC", &kp) != 0) {
return -1;
}
return cnc_sim_userk_userkKinematicsSetup(0, "XYZBC", &kp);
}
int cnc_sim_linuxcnc_userkfuncs_forward(const double *joints, EmcPose *pos) {
KINEMATICS_FORWARD_FLAGS fflags = 0;
KINEMATICS_INVERSE_FLAGS iflags = 0;
return cnc_sim_userk_userkKinematicsForward(joints, pos, &fflags, &iflags);
}
int cnc_sim_linuxcnc_userkfuncs_inverse(const EmcPose *pos, double *joints) {
KINEMATICS_INVERSE_FLAGS iflags = 0;
KINEMATICS_FORWARD_FLAGS fflags = 0;
return cnc_sim_userk_userkKinematicsInverse(pos, joints, &iflags, &fflags);
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,113 @@
#include "linuxcnc_userkfuncs_adapter.h"
#include <cstring>
extern "C" {
struct PmCartesian {
double x;
double y;
double z;
};
struct EmcPose {
PmCartesian tran;
double a;
double b;
double c;
double u;
double v;
double w;
};
int cnc_sim_linuxcnc_userkfuncs_setup(void);
int cnc_sim_linuxcnc_userkfuncs_forward(const double *joints, EmcPose *pos);
int cnc_sim_linuxcnc_userkfuncs_inverse(const EmcPose *pos, double *joints);
}
namespace {
bool initialized = false;
bool ensure_initialized() {
if (initialized) {
return true;
}
initialized = cnc_sim_linuxcnc_userkfuncs_setup() == 0;
return initialized;
}
void to_joints(const LinuxCncFiveAxisJoints &joints, double out[16]) {
std::memset(out, 0, sizeof(double) * 16);
out[0] = joints.x;
out[1] = joints.y;
out[2] = joints.z;
out[3] = joints.b;
out[4] = joints.c;
}
LinuxCncFiveAxisJoints from_joints(const double joints[16]) {
LinuxCncFiveAxisJoints out{};
out.x = joints[0];
out.y = joints[1];
out.z = joints[2];
out.b = joints[3];
out.c = joints[4];
return out;
}
EmcPose to_emc_pose(const CncSimPose &pose) {
EmcPose emc{};
emc.tran.x = pose.x;
emc.tran.y = pose.y;
emc.tran.z = pose.z;
emc.a = pose.a;
emc.b = pose.b;
emc.c = pose.c;
emc.u = pose.u;
emc.v = pose.v;
emc.w = pose.w;
return emc;
}
CncSimPose from_emc_pose(const EmcPose &emc) {
CncSimPose pose{};
pose.x = emc.tran.x;
pose.y = emc.tran.y;
pose.z = emc.tran.z;
pose.a = emc.a;
pose.b = emc.b;
pose.c = emc.c;
pose.u = emc.u;
pose.v = emc.v;
pose.w = emc.w;
return pose;
}
} // namespace
bool linuxcnc_userkfuncs_forward(const LinuxCncFiveAxisJoints &joints, CncSimPose *pose) {
if (!ensure_initialized()) {
return false;
}
double raw_joints[16];
to_joints(joints, raw_joints);
EmcPose out{};
if (cnc_sim_linuxcnc_userkfuncs_forward(raw_joints, &out) != 0) {
return false;
}
*pose = from_emc_pose(out);
return true;
}
bool linuxcnc_userkfuncs_inverse(const CncSimPose &pose, LinuxCncFiveAxisJoints *joints) {
if (!ensure_initialized()) {
return false;
}
const EmcPose in = to_emc_pose(pose);
double raw_joints[16] = {};
if (cnc_sim_linuxcnc_userkfuncs_inverse(&in, raw_joints) != 0) {
return false;
}
*joints = from_joints(raw_joints);
return true;
}

View File

@@ -0,0 +1,6 @@
#pragma once
#include "rtcp_kinematics.h"
bool linuxcnc_userkfuncs_forward(const LinuxCncFiveAxisJoints &joints, CncSimPose *pose);
bool linuxcnc_userkfuncs_inverse(const CncSimPose &pose, LinuxCncFiveAxisJoints *joints);

View File

@@ -0,0 +1,241 @@
#include <math.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define __LINUXCNC_RTAPI_H
#define __LINUXCNC_RTAPI_APP_H
#define __LINUXCNC_RTAPI_STRING_H
#define __LINUXCNC_RTAPI_ERRNO_H
#define __LINUXCNC_RTAPI_MATH_H
#define __LINUXCNC_RTAPI_MATH64_H
#define __LINUXCNC_HAL_H
#define __LINUXCNC_KINEMATICS_H
#define MODULE_INFO(...)
#define MODULE_LICENSE(...)
#define EXPORT_SYMBOL(symbol)
#define RTAPI_MP_INT(name, description)
#define RTAPI_MP_STRING(name, description)
#define RTAPI_MSG_ERR 1
#define RTAPI_MSG_INFO 2
#define HAL_NAME_LEN 47
#define EINVAL 22
#define PM_PI 3.1415926535897932384626433832795029
#define TO_RAD (PM_PI / 180.0)
typedef double real_t;
typedef double hal_float_t;
typedef int hal_s32_t;
typedef unsigned int hal_u32_t;
typedef bool hal_bit_t;
typedef enum { HAL_IN = 16, HAL_OUT = 32, HAL_IO = (HAL_IN | HAL_OUT) } hal_pin_dir_t;
typedef struct {
double x;
double y;
double z;
} PmCartesian;
typedef struct EmcPose {
PmCartesian tran;
double a;
double b;
double c;
double u;
double v;
double w;
} EmcPose;
typedef enum {
KINEMATICS_IDENTITY = 1,
KINEMATICS_FORWARD_ONLY,
KINEMATICS_INVERSE_ONLY,
KINEMATICS_BOTH
} KINEMATICS_TYPE;
typedef unsigned long int KINEMATICS_FORWARD_FLAGS;
typedef unsigned long int KINEMATICS_INVERSE_FLAGS;
typedef struct kinematics_parms {
char *sparm;
char *kinsname;
char *halprefix;
char *required_coordinates;
int max_joints;
int allow_duplicates;
int fwd_iterates_mask;
int gui_kinstype;
} kparms;
#ifdef __cplusplus
extern "C" {
#endif
int __attribute__((weak)) rtapi_snprintf(char *str, unsigned long int size, const char *fmt, ...) {
va_list args;
va_start(args, fmt);
const int result = vsnprintf(str, (size_t)size, fmt, args);
va_end(args);
return result;
}
void cnc_sim_xyzab_tdr_rtapi_print(const char *fmt, ...) {
(void)fmt;
}
void cnc_sim_xyzab_tdr_rtapi_print_msg(int level, const char *fmt, ...) {
(void)level;
(void)fmt;
}
void *cnc_sim_xyzab_tdr_hal_malloc(long int size) {
return calloc(1, (size_t)size);
}
int cnc_sim_xyzab_tdr_hal_init(const char *name) {
(void)name;
return 1;
}
void cnc_sim_xyzab_tdr_hal_exit(int comp_id) {
(void)comp_id;
}
int cnc_sim_xyzab_tdr_hal_ready(int comp_id) {
(void)comp_id;
return 0;
}
int cnc_sim_xyzab_tdr_hal_set_unready(int comp_id) {
(void)comp_id;
return 0;
}
int cnc_sim_xyzab_tdr_hal_pin_s32_newf(hal_pin_dir_t dir,
hal_s32_t **data_ptr_addr,
int comp_id,
const char *fmt,
...) {
(void)dir;
(void)comp_id;
(void)fmt;
*data_ptr_addr = (hal_s32_t *)calloc(1, sizeof(hal_s32_t));
return *data_ptr_addr ? 0 : -1;
}
int cnc_sim_xyzab_tdr_hal_pin_float_newf(hal_pin_dir_t dir,
hal_float_t **data_ptr_addr,
int comp_id,
const char *fmt,
...) {
(void)dir;
(void)comp_id;
(void)fmt;
*data_ptr_addr = (hal_float_t *)calloc(1, sizeof(hal_float_t));
return *data_ptr_addr ? 0 : -1;
}
int cnc_sim_xyzab_tdr_hal_pin_bit_new(const char *name,
hal_pin_dir_t dir,
hal_bit_t **data_ptr_addr,
int comp_id) {
(void)name;
(void)dir;
(void)comp_id;
*data_ptr_addr = (hal_bit_t *)calloc(1, sizeof(hal_bit_t));
return *data_ptr_addr ? 0 : -1;
}
#define rtapi_print cnc_sim_xyzab_tdr_rtapi_print
#define rtapi_print_msg cnc_sim_xyzab_tdr_rtapi_print_msg
#define hal_malloc(size) cnc_sim_xyzab_tdr_hal_malloc(size)
#define hal_init cnc_sim_xyzab_tdr_hal_init
#define hal_exit cnc_sim_xyzab_tdr_hal_exit
#define hal_ready cnc_sim_xyzab_tdr_hal_ready
#define hal_set_unready cnc_sim_xyzab_tdr_hal_set_unready
#define hal_pin_s32_newf cnc_sim_xyzab_tdr_hal_pin_s32_newf
#define hal_pin_float_newf cnc_sim_xyzab_tdr_hal_pin_float_newf
#define hal_pin_bit_new cnc_sim_xyzab_tdr_hal_pin_bit_new
#define kinematicsType cnc_sim_xyzab_tdr_kinematicsType
#define kinematicsSwitchable cnc_sim_xyzab_tdr_kinematicsSwitchable
#define kinematicsSwitch cnc_sim_xyzab_tdr_kinematicsSwitch
#define kinematicsForward cnc_sim_xyzab_tdr_kinematicsForward
#define kinematicsInverse cnc_sim_xyzab_tdr_kinematicsInverse
#define rtapi_app_main cnc_sim_xyzab_tdr_rtapi_app_main
#define rtapi_app_exit cnc_sim_xyzab_tdr_rtapi_app_exit
#define export cnc_sim_xyzab_tdr_export
#include "../../../linuxcnc/src/objects/hal/components/xyzab_tdr_kins.c"
#undef export
#undef rtapi_app_exit
#undef rtapi_app_main
#undef kinematicsInverse
#undef kinematicsForward
#undef kinematicsSwitch
#undef kinematicsSwitchable
#undef kinematicsType
#undef hal_pin_bit_new
#undef hal_pin_float_newf
#undef hal_pin_s32_newf
#undef hal_set_unready
#undef hal_ready
#undef hal_exit
#undef hal_init
#undef hal_malloc
#undef rtapi_print_msg
#undef rtapi_print
int cnc_sim_linuxcnc_xyzab_tdr_kins_setup(void) {
return cnc_sim_xyzab_tdr_kinematicsType() == KINEMATICS_BOTH ? 0 : -1;
}
void cnc_sim_linuxcnc_xyzab_tdr_kins_set_parameters(double tool_offset_z,
double x_offset,
double z_offset,
double x_rot_point,
double y_rot_point,
double z_rot_point) {
*haldata->tool_offset_z = tool_offset_z;
*haldata->x_offset = x_offset;
*haldata->z_offset = z_offset;
*haldata->x_rot_point = x_rot_point;
*haldata->y_rot_point = y_rot_point;
*haldata->z_rot_point = z_rot_point;
}
int cnc_sim_linuxcnc_xyzab_tdr_kins_switch(int switchkins_type) {
return cnc_sim_xyzab_tdr_kinematicsSwitch(switchkins_type);
}
int cnc_sim_linuxcnc_xyzab_tdr_kins_switch_state(int *kinstype_is_0, int *kinstype_is_1) {
if (!haldata || !haldata->kinstype_is_0 || !haldata->kinstype_is_1) {
return -1;
}
if (kinstype_is_0) {
*kinstype_is_0 = *haldata->kinstype_is_0 ? 1 : 0;
}
if (kinstype_is_1) {
*kinstype_is_1 = *haldata->kinstype_is_1 ? 1 : 0;
}
return 0;
}
int cnc_sim_linuxcnc_xyzab_tdr_kins_forward(const double *joints, EmcPose *pos) {
KINEMATICS_FORWARD_FLAGS fflags = 0;
KINEMATICS_INVERSE_FLAGS iflags = 0;
return cnc_sim_xyzab_tdr_kinematicsForward(joints, pos, &fflags, &iflags);
}
int cnc_sim_linuxcnc_xyzab_tdr_kins_inverse(const EmcPose *pos, double *joints) {
KINEMATICS_INVERSE_FLAGS iflags = 0;
KINEMATICS_FORWARD_FLAGS fflags = 0;
return cnc_sim_xyzab_tdr_kinematicsInverse(pos, joints, &iflags, &fflags);
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,177 @@
#include "linuxcnc_xyzab_tdr_kins_adapter.h"
#include <cstring>
extern "C" {
struct PmCartesian {
double x;
double y;
double z;
};
struct EmcPose {
PmCartesian tran;
double a;
double b;
double c;
double u;
double v;
double w;
};
int cnc_sim_linuxcnc_xyzab_tdr_kins_setup(void);
void cnc_sim_linuxcnc_xyzab_tdr_kins_set_parameters(double tool_offset_z,
double x_offset,
double z_offset,
double x_rot_point,
double y_rot_point,
double z_rot_point);
int cnc_sim_linuxcnc_xyzab_tdr_kins_switch(int switchkins_type);
int cnc_sim_linuxcnc_xyzab_tdr_kins_switch_state(int *kinstype_is_0, int *kinstype_is_1);
int cnc_sim_linuxcnc_xyzab_tdr_kins_forward(const double *joints, EmcPose *pos);
int cnc_sim_linuxcnc_xyzab_tdr_kins_inverse(const EmcPose *pos, double *joints);
}
namespace {
bool initialized = false;
bool ensure_initialized() {
if (initialized) {
return true;
}
initialized = cnc_sim_linuxcnc_xyzab_tdr_kins_setup() == 0;
return initialized;
}
void apply_parameters(const LinuxCncXyzabTdrParameters &parameters) {
cnc_sim_linuxcnc_xyzab_tdr_kins_set_parameters(parameters.tool_offset_z,
parameters.x_offset,
parameters.z_offset,
parameters.x_rot_point,
parameters.y_rot_point,
parameters.z_rot_point);
}
void to_joints(const LinuxCncAxisJoints &joints, double out[16]) {
std::memset(out, 0, sizeof(double) * 16);
out[0] = joints.x;
out[1] = joints.y;
out[2] = joints.z;
out[3] = joints.a;
out[4] = joints.b;
out[5] = joints.c;
out[6] = joints.u;
out[7] = joints.v;
out[8] = joints.w;
}
LinuxCncAxisJoints from_joints(const double joints[16]) {
LinuxCncAxisJoints out{};
out.x = joints[0];
out.y = joints[1];
out.z = joints[2];
out.a = joints[3];
out.b = joints[4];
out.c = joints[5];
out.u = joints[6];
out.v = joints[7];
out.w = joints[8];
return out;
}
EmcPose to_emc_pose(const CncSimPose &pose) {
EmcPose emc{};
emc.tran.x = pose.x;
emc.tran.y = pose.y;
emc.tran.z = pose.z;
emc.a = pose.a;
emc.b = pose.b;
emc.c = pose.c;
emc.u = pose.u;
emc.v = pose.v;
emc.w = pose.w;
return emc;
}
CncSimPose from_emc_pose(const EmcPose &emc) {
CncSimPose pose{};
pose.x = emc.tran.x;
pose.y = emc.tran.y;
pose.z = emc.tran.z;
pose.a = emc.a;
pose.b = emc.b;
pose.c = emc.c;
pose.u = emc.u;
pose.v = emc.v;
pose.w = emc.w;
return pose;
}
} // namespace
bool linuxcnc_xyzab_tdr_kins_switch(int switchkins_type) {
if (!ensure_initialized()) {
return false;
}
return cnc_sim_linuxcnc_xyzab_tdr_kins_switch(switchkins_type) == 0;
}
bool linuxcnc_xyzab_tdr_kins_switch_state(bool *kinstype_is_0, bool *kinstype_is_1) {
if (!ensure_initialized()) {
return false;
}
int raw_kinstype_is_0 = 0;
int raw_kinstype_is_1 = 0;
if (cnc_sim_linuxcnc_xyzab_tdr_kins_switch_state(&raw_kinstype_is_0, &raw_kinstype_is_1) != 0) {
return false;
}
if (kinstype_is_0) {
*kinstype_is_0 = raw_kinstype_is_0 != 0;
}
if (kinstype_is_1) {
*kinstype_is_1 = raw_kinstype_is_1 != 0;
}
return true;
}
bool linuxcnc_xyzab_tdr_kins_forward(const LinuxCncAxisJoints &joints,
const LinuxCncXyzabTdrParameters &parameters,
int switchkins_type,
CncSimPose *pose) {
if (!ensure_initialized()) {
return false;
}
apply_parameters(parameters);
if (!linuxcnc_xyzab_tdr_kins_switch(switchkins_type)) {
return false;
}
double raw_joints[16];
to_joints(joints, raw_joints);
EmcPose out{};
if (cnc_sim_linuxcnc_xyzab_tdr_kins_forward(raw_joints, &out) != 0) {
return false;
}
*pose = from_emc_pose(out);
return true;
}
bool linuxcnc_xyzab_tdr_kins_inverse(const CncSimPose &pose,
const LinuxCncXyzabTdrParameters &parameters,
int switchkins_type,
LinuxCncAxisJoints *joints) {
if (!ensure_initialized()) {
return false;
}
apply_parameters(parameters);
if (!linuxcnc_xyzab_tdr_kins_switch(switchkins_type)) {
return false;
}
const EmcPose in = to_emc_pose(pose);
double raw_joints[16] = {};
if (cnc_sim_linuxcnc_xyzab_tdr_kins_inverse(&in, raw_joints) != 0) {
return false;
}
*joints = from_joints(raw_joints);
return true;
}

View File

@@ -0,0 +1,14 @@
#pragma once
#include "rtcp_kinematics.h"
bool linuxcnc_xyzab_tdr_kins_switch(int switchkins_type);
bool linuxcnc_xyzab_tdr_kins_switch_state(bool *kinstype_is_0, bool *kinstype_is_1);
bool linuxcnc_xyzab_tdr_kins_forward(const LinuxCncAxisJoints &joints,
const LinuxCncXyzabTdrParameters &parameters,
int switchkins_type,
CncSimPose *pose);
bool linuxcnc_xyzab_tdr_kins_inverse(const CncSimPose &pose,
const LinuxCncXyzabTdrParameters &parameters,
int switchkins_type,
LinuxCncAxisJoints *joints);

File diff suppressed because it is too large Load Diff

View File

@@ -83,12 +83,78 @@ struct LinuxCncScaraJoints {
double j5;
};
struct LinuxCncGenhexJoints {
double strut[6];
};
struct LinuxCncPentakinsJoints {
double strut[5];
};
struct LinuxCncTripodJoints {
double strut[3];
};
struct LinuxCncScorbotJoints {
double j0;
double j1;
double j2;
double j3;
double j4;
};
struct LinuxCncLinearDeltaParameters {
double r;
double l;
};
struct LinuxCncRotaryDeltaParameters {
double platformradius;
double thighlength;
double shinlength;
double footradius;
};
struct LinuxCncMaxkinsParameters {
double pivot_length;
bool conventional_directions;
};
LinuxCncAxisJoints linuxcnc_identity_default_joints();
CncSimPose linuxcnc_identity_forward(const LinuxCncAxisJoints &joints);
LinuxCncAxisJoints linuxcnc_identity_inverse(const CncSimPose &pose);
CncSimPose linuxcnc_corexykins_forward(const LinuxCncAxisJoints &joints);
LinuxCncAxisJoints linuxcnc_corexykins_inverse(const CncSimPose &pose);
CncSimPose linuxcnc_rotatekins_forward(const LinuxCncAxisJoints &joints);
LinuxCncAxisJoints linuxcnc_rotatekins_inverse(const CncSimPose &pose);
LinuxCncGenhexJoints linuxcnc_genhex_inverse(const CncSimPose &pose);
CncSimPose linuxcnc_genhex_forward(const LinuxCncGenhexJoints &joints, const CncSimPose &initial_pose);
LinuxCncPentakinsJoints linuxcnc_pentakins_inverse(const CncSimPose &pose);
CncSimPose linuxcnc_pentakins_forward(const LinuxCncPentakinsJoints &joints,
const CncSimPose &initial_pose);
LinuxCncTripodJoints linuxcnc_tripodkins_inverse(const CncSimPose &pose);
CncSimPose linuxcnc_tripodkins_forward(const LinuxCncTripodJoints &joints);
LinuxCncScorbotJoints linuxcnc_scorbot_kins_inverse(const CncSimPose &pose);
CncSimPose linuxcnc_scorbot_kins_forward(const LinuxCncScorbotJoints &joints);
LinuxCncLinearDeltaParameters linuxcnc_lineardelta_default_parameters();
CncSimPose linuxcnc_lineardelta_forward(const LinuxCncAxisJoints &joints,
const LinuxCncLinearDeltaParameters &parameters);
LinuxCncAxisJoints linuxcnc_lineardelta_inverse(const CncSimPose &pose,
const LinuxCncLinearDeltaParameters &parameters);
LinuxCncRotaryDeltaParameters linuxcnc_rotarydelta_default_parameters();
CncSimPose linuxcnc_rotarydelta_forward(const LinuxCncAxisJoints &joints,
const LinuxCncRotaryDeltaParameters &parameters);
LinuxCncAxisJoints linuxcnc_rotarydelta_inverse(const CncSimPose &pose,
const LinuxCncRotaryDeltaParameters &parameters);
LinuxCncMaxkinsParameters linuxcnc_maxkins_default_parameters();
CncSimPose linuxcnc_maxkins_forward(const LinuxCncAxisJoints &joints,
const LinuxCncMaxkinsParameters &parameters);
LinuxCncAxisJoints linuxcnc_maxkins_inverse(const CncSimPose &pose,
const LinuxCncMaxkinsParameters &parameters);
CncSimPose linuxcnc_rosekins_forward(const LinuxCncAxisJoints &joints);
LinuxCncAxisJoints linuxcnc_rosekins_inverse(const CncSimPose &pose);
CncSimPose linuxcnc_5axis_forward(const LinuxCncFiveAxisJoints &joints, double pivot_length);
LinuxCncFiveAxisJoints linuxcnc_5axis_inverse(const CncSimPose &pose, double pivot_length);
@@ -132,6 +198,7 @@ LinuxCncAxisJoints linuxcnc_puma_inverse(const CncSimPose &pose,
int *fflags);
LinuxCncGenserParameters linuxcnc_genser_puma560_parameters();
LinuxCncGenserParameters linuxcnc_genser_default_parameters(int *max_iterations = nullptr);
CncSimPose linuxcnc_genser_forward(const LinuxCncAxisJoints &joints,
const LinuxCncGenserParameters &parameters);
LinuxCncAxisJoints linuxcnc_genser_inverse(const CncSimPose &pose,
@@ -139,3 +206,9 @@ LinuxCncAxisJoints linuxcnc_genser_inverse(const CncSimPose &pose,
const LinuxCncGenserParameters &parameters,
int *iterations,
int max_iterations = 100);
bool linuxcnc_genser_inverse_checked(const CncSimPose &pose,
const LinuxCncAxisJoints &joint_estimate,
const LinuxCncGenserParameters &parameters,
LinuxCncAxisJoints *joints,
int *iterations,
int max_iterations = 100);

View File

@@ -295,12 +295,25 @@ bool parse_simulator_gcode_control_line(const std::string &line,
return false;
}
void emit_simulator_gcode_control_action(CanonEventSink &sink,
bool can_emit_simulator_gcode_control_action(const CanonEventSink &sink,
const SimulatorGcodeControlAction &action) {
if (action.kind == SimulatorGcodeControlKind::KinematicsSwitch) {
return sink.can_switch_m_code_kinematics(action.m_code);
}
if (action.kind == SimulatorGcodeControlKind::RtcpState) {
return true;
}
return false;
}
bool emit_simulator_gcode_control_action(CanonEventSink &sink,
const SimulatorGcodeControlAction &action,
int line) {
if (action.kind == SimulatorGcodeControlKind::KinematicsSwitch) {
sink.switch_m_code_kinematics(action.m_code, action.value, line);
return sink.switch_m_code_kinematics(action.m_code, action.value, line);
} else if (action.kind == SimulatorGcodeControlKind::RtcpState) {
sink.set_rtcp_state(action.rtcp_enabled, action.h_code, line);
return true;
}
return false;
}

View File

@@ -23,6 +23,8 @@ bool parse_simulator_gcode_control_line(const std::string &line,
bool parse_simulator_gcode_control_line(const std::string &line,
bool block_delete,
std::vector<SimulatorGcodeControlAction> *actions);
void emit_simulator_gcode_control_action(CanonEventSink &sink,
bool can_emit_simulator_gcode_control_action(const CanonEventSink &sink,
const SimulatorGcodeControlAction &action);
bool emit_simulator_gcode_control_action(CanonEventSink &sink,
const SimulatorGcodeControlAction &action,
int line);

View File

@@ -180,6 +180,7 @@ size_t leading_special_word_start(const std::string &line);
bool is_numeric_m98_subprogram_header(const std::string &line);
OwordKind oword_kind(const std::string &line);
bool integer_word_value(const std::unordered_map<char, double> &words, char letter, int *value);
bool smoke_ini_raw_value(const std::string &section, const std::string &key, std::string *value);
bool evaluate_expression(const std::string &text,
const std::vector<CallFrame> &call_stack,
const std::unordered_map<int, double> &parameters,
@@ -444,6 +445,20 @@ bool parse_smoke_hal_named_parameter(const std::string &name, std::string *pin)
}
bool smoke_ini_value(const std::string &section, const std::string &key, double *value) {
std::string raw_value;
if (!smoke_ini_raw_value(section, key, &raw_value)) {
return false;
}
char *end = nullptr;
const double parsed = std::strtod(raw_value.c_str(), &end);
if (end == raw_value.c_str()) {
return false;
}
*value = parsed;
return true;
}
bool smoke_ini_raw_value(const std::string &section, const std::string &key, std::string *value) {
const char *path = std::getenv("INI_FILE_NAME");
if (!path || !*path) {
return false;
@@ -474,18 +489,20 @@ bool smoke_ini_value(const std::string &section, const std::string &key, double
if (ini_lookup_key(text.substr(0, equals)) != key) {
continue;
}
char *end = nullptr;
const std::string raw_value = trim(text.substr(equals + 1));
const double parsed = std::strtod(raw_value.c_str(), &end);
if (end == raw_value.c_str()) {
return false;
}
*value = parsed;
*value = trim(text.substr(equals + 1));
return true;
}
return false;
}
double smoke_metric_machine_value() {
std::string linear_units;
if (!smoke_ini_raw_value("TRAJ", "LINEAR_UNITS", &linear_units)) {
return -1.0;
}
return linear_units == "inch" ? 0.0 : 1.0;
}
bool smoke_hal_value(const std::string &pin, double *value) {
const char *path = std::getenv("HAL_PIN_FILE");
if (path && *path) {
@@ -1735,6 +1752,18 @@ bool smoke_tool_number_exists(int tool_number) {
return tool_number == 0 || tool_number == 1 || tool_number == 4;
}
template <typename ToolTable>
double smoke_pocket_named_parameter_value(const ToolTable &tool_table, int pocket_index, bool selected_pocket) {
const auto it = tool_table.find(pocket_index);
if (it == tool_table.end()) {
return -1.0;
}
if (selected_pocket && it->second.pocketno == 0) {
return -1.0;
}
return static_cast<double>(it->second.pocketno);
}
int supported_linuxcnc_g_modal_group(double value) {
const int code = linuxcnc_g_code_number(value);
if (code < 0 || code >= kLinuxCncGCodeTableSize) {
@@ -2333,13 +2362,7 @@ bool is_smoke_readonly_named_parameter(const std::string &name) {
name == "_ABS_B" ||
name == "_abs_b" ||
name == "_ABS_C" ||
name == "_abs_c" ||
name == "_ABS_U" ||
name == "_abs_u" ||
name == "_ABS_V" ||
name == "_abs_v" ||
name == "_ABS_W" ||
name == "_abs_w";
name == "_abs_c";
}
bool is_smoke_readonly_numbered_parameter(int index) {
@@ -5408,6 +5431,8 @@ int SmokeGcodeParser::parse(const char *program, size_t program_len, std::string
spindle_css_mode_ = false;
spindle_tool_id_ = 0;
selected_tool_id_ = 0;
current_pocket_index_ = 0;
selected_pocket_index_ = 0;
feed_mode_ = 0;
canned_cycle_ = 0;
canned_return_to_initial_ = false;
@@ -5433,13 +5458,16 @@ int SmokeGcodeParser::parse(const char *program, size_t program_len, std::string
oword_value_returned_ = false;
tool_table_.clear();
tool_table_[0] = {};
tool_table_[0].pocketno = 0;
tool_table_[1] = {};
tool_table_[1].pocketno = 1;
tool_table_[1].offset.z = 12.5;
tool_table_[1].diameter = 6.0;
tool_table_[1].frontangle = 12.0;
tool_table_[1].backangle = 34.0;
tool_table_[1].orientation = 5.0;
tool_table_[4] = {};
tool_table_[4].pocketno = 4;
tool_table_[4].offset.z = 0.7;
tool_table_[4].diameter = 1.0;
@@ -5685,9 +5713,13 @@ int SmokeGcodeParser::parse(const char *program, size_t program_len, std::string
named_parameters["_CURRENT_TOOL"] = named_parameters["_current_tool"];
named_parameters["_selected_tool"] = static_cast<double>(selected_tool_id_);
named_parameters["_SELECTED_TOOL"] = named_parameters["_selected_tool"];
named_parameters["_current_pocket"] = static_cast<double>(spindle_tool_id_);
named_parameters["_current_pocket"] = smoke_pocket_named_parameter_value(tool_table_,
current_pocket_index_,
false);
named_parameters["_CURRENT_POCKET"] = named_parameters["_current_pocket"];
named_parameters["_selected_pocket"] = static_cast<double>(selected_tool_id_);
named_parameters["_selected_pocket"] = smoke_pocket_named_parameter_value(tool_table_,
selected_pocket_index_,
true);
named_parameters["_SELECTED_POCKET"] = named_parameters["_selected_pocket"];
named_parameters["_spindle_rpm_mode"] = spindle_css_mode_ ? 0.0 : 1.0;
named_parameters["_SPINDLE_RPM_MODE"] = named_parameters["_spindle_rpm_mode"];
@@ -5707,8 +5739,8 @@ int SmokeGcodeParser::parse(const char *program, size_t program_len, std::string
named_parameters["_VMAJOR"] = 2.10;
named_parameters["_vminor"] = 0.0;
named_parameters["_VMINOR"] = 0.0;
named_parameters["_metric_machine"] = -1.0;
named_parameters["_METRIC_MACHINE"] = -1.0;
named_parameters["_metric_machine"] = smoke_metric_machine_value();
named_parameters["_METRIC_MACHINE"] = named_parameters["_metric_machine"];
named_parameters["_task"] = 0.0;
named_parameters["_TASK"] = 0.0;
const bool has_tool_offset = tool_length_offset.x != 0.0 ||
@@ -5747,18 +5779,12 @@ int SmokeGcodeParser::parse(const char *program, size_t program_len, std::string
named_parameters["_abs_a"] = position.a;
named_parameters["_abs_b"] = position.b;
named_parameters["_abs_c"] = position.c;
named_parameters["_abs_u"] = position.u;
named_parameters["_abs_v"] = position.v;
named_parameters["_abs_w"] = position.w;
named_parameters["_ABS_X"] = position.x;
named_parameters["_ABS_Y"] = position.y;
named_parameters["_ABS_Z"] = position.z;
named_parameters["_ABS_A"] = position.a;
named_parameters["_ABS_B"] = position.b;
named_parameters["_ABS_C"] = position.c;
named_parameters["_ABS_U"] = position.u;
named_parameters["_ABS_V"] = position.v;
named_parameters["_ABS_W"] = position.w;
const CncSimPose &probe_position = sink_.probe_position();
parameters[5061] = probe_position.x;
@@ -5956,14 +5982,34 @@ int SmokeGcodeParser::parse(const char *program, size_t program_len, std::string
if (!has_keyword_oword &&
parse_simulator_gcode_control_line(line, sink_.block_delete(), &simulator_control_actions)) {
bool simulator_only_line = true;
bool all_control_actions_handled = true;
for (const auto &action : simulator_control_actions) {
emit_simulator_gcode_control_action(sink_, action, line_number);
if (!can_emit_simulator_gcode_control_action(sink_, action)) {
all_control_actions_handled = false;
simulator_only_line = false;
}
if (action.kind == SimulatorGcodeControlKind::RtcpState &&
!action.rtcp_enabled) {
simulator_only_line = false;
}
if (stop_if_callback_aborted(sink_, error)) {
return -1;
}
if (!all_control_actions_handled && simulator_control_actions.size() > 1) {
for (const auto &action : simulator_control_actions) {
if (!can_emit_simulator_gcode_control_action(sink_, action) &&
action.kind == SimulatorGcodeControlKind::KinematicsSwitch) {
if (error) {
*error = "M-code greater than 199: M" + std::to_string(action.m_code);
}
return -1;
}
}
}
if (all_control_actions_handled) {
for (const auto &action : simulator_control_actions) {
emit_simulator_gcode_control_action(sink_, action, line_number);
if (stop_if_callback_aborted(sink_, error)) {
return -1;
}
}
}
if (simulator_only_line) {
@@ -7704,6 +7750,15 @@ int SmokeGcodeParser::parse(const char *program, size_t program_len, std::string
}
return -1;
}
for (int m : m_codes) {
if ((m == 428 || m == 429 || m == 430) &&
!sink_.can_switch_m_code_kinematics(m)) {
if (error) {
*error = "M-code greater than 199: M" + std::to_string(m);
}
return -1;
}
}
if (modal_motion_is_threading(modal_motion) && words.count('F')) {
if (error) {
@@ -7764,6 +7819,7 @@ int SmokeGcodeParser::parse(const char *program, size_t program_len, std::string
}
sink_.select_tool(tool_id);
selected_tool_id_ = tool_id;
selected_pocket_index_ = tool_id;
tool_selected_ = true;
}
@@ -7910,6 +7966,10 @@ int SmokeGcodeParser::parse(const char *program, size_t program_len, std::string
if (stop_if_callback_aborted(sink_, error)) {
return -1;
}
if (selected_tool_id_ == 0) {
spindle_tool_id_ = 0;
}
current_pocket_index_ = selected_pocket_index_;
} else if (m == 7) {
sink_.set_mist_on(true);
emit_comment_state(sink_, line_number, 11);
@@ -8058,6 +8118,10 @@ int SmokeGcodeParser::parse(const char *program, size_t program_len, std::string
}
sink_.select_tool(tool_number);
sink_.change_tool(line_number);
if (tool_number == 0) {
spindle_tool_id_ = 0;
}
current_pocket_index_ = tool_number;
if (stop_if_callback_aborted(sink_, error)) {
return -1;
}
@@ -8192,17 +8256,32 @@ int SmokeGcodeParser::parse(const char *program, size_t program_len, std::string
return -1;
}
} else if (m == 428) {
sink_.switch_kinematics(1, line_number);
if (!sink_.switch_m_code_kinematics(428, 1, line_number)) {
if (error) {
*error = "M-code greater than 199: M428";
}
return -1;
}
if (stop_if_callback_aborted(sink_, error)) {
return -1;
}
} else if (m == 429) {
sink_.switch_kinematics(0, line_number);
if (!sink_.switch_m_code_kinematics(429, 0, line_number)) {
if (error) {
*error = "M-code greater than 199: M429";
}
return -1;
}
if (stop_if_callback_aborted(sink_, error)) {
return -1;
}
} else if (m == 430) {
sink_.switch_kinematics(2, line_number);
if (!sink_.switch_m_code_kinematics(430, 2, line_number)) {
if (error) {
*error = "M-code greater than 199: M430";
}
return -1;
}
if (stop_if_callback_aborted(sink_, error)) {
return -1;
}

View File

@@ -14,6 +14,7 @@ public:
private:
struct SmokeToolTableEntry {
int pocketno = 0;
CncSimPose offset{};
double diameter = 0.0;
double frontangle = 0.0;
@@ -64,5 +65,7 @@ private:
double oword_return_value_ = 0.0;
bool oword_value_returned_ = false;
int selected_tool_id_ = 0;
int current_pocket_index_ = 0;
int selected_pocket_index_ = 0;
std::unordered_map<int, SmokeToolTableEntry> tool_table_;
};

View File

@@ -297,6 +297,45 @@ int main() {
}
ok &= expect(saw_fiveaxis_pivot, "expected M428 bridgemill RTCP pivot to use LinuxCNC 5axiskins inverse");
std::vector<CncSimEvent> switchkins_events;
CanonEventSink switchkins_sink;
switchkins_sink.set_callback(collect_event, &switchkins_events);
switchkins_sink.configure_switchkins_remap(0, 1, 2);
switchkins_sink.switch_m_code_kinematics(428, 1, 10);
switchkins_sink.switch_m_code_kinematics(429, 0, 11);
bool saw_scara_m428 = false;
bool saw_scara_m429 = false;
for (const auto &event : switchkins_events) {
saw_scara_m428 = saw_scara_m428 ||
(event.type == CNC_SIM_EVENT_KINEMATICS_SWITCH &&
event.line == 10 &&
event.reserved == 0);
saw_scara_m429 = saw_scara_m429 ||
(event.type == CNC_SIM_EVENT_KINEMATICS_SWITCH &&
event.line == 11 &&
event.reserved == 1);
}
ok &= expect(saw_scara_m428,
"expected M428 scara/bridgemill/melfa remap to select LinuxCNC kinstype 0");
ok &= expect(saw_scara_m429,
"expected M429 scara/bridgemill/melfa remap to select LinuxCNC identity kinstype 1");
std::vector<CncSimEvent> table_dual_events;
CanonEventSink table_dual_sink;
table_dual_sink.set_callback(collect_event, &table_dual_events);
table_dual_sink.configure_switchkins_remap(1, 0, -1);
const bool table_dual_m430_handled = table_dual_sink.switch_m_code_kinematics(430, 2, 12);
bool saw_table_dual_m430 = false;
for (const auto &event : table_dual_events) {
saw_table_dual_m430 = saw_table_dual_m430 ||
(event.type == CNC_SIM_EVENT_KINEMATICS_SWITCH &&
event.line == 12);
}
ok &= expect(!table_dual_m430_handled,
"expected LinuxCNC table-dual-rotary config without 430remap.ngc to leave M430 unhandled");
ok &= expect(!saw_table_dual_m430,
"expected LinuxCNC table-dual-rotary config without 430remap.ngc to skip M430 switch");
events.clear();
sink.configure_rtcp(true, 250.0);
sink.switch_kinematics(0, 3);

View File

@@ -2,6 +2,7 @@
#include <cmath>
#include <iostream>
#include <string>
#include <vector>
namespace {
@@ -55,6 +56,16 @@ bool saw_comment_state(const std::vector<CncSimEvent> &events,
return false;
}
bool saw_any_kinematics_switch(const std::vector<CncSimEvent> &events, int line) {
for (const auto &event : events) {
if (event.type == CNC_SIM_EVENT_KINEMATICS_SWITCH &&
event.line == line) {
return true;
}
}
return false;
}
} // namespace
int main() {
@@ -521,6 +532,109 @@ int main() {
ok &= expect(saw_g49_tool_offset_parameter_before && saw_g49_tool_offset_parameter_after,
"expected LinuxCNC G49 to clear the applied tool offset parameter before the next motion");
const char tool_pocket_named_parameter_program[] =
"G21 G90 G17\n"
"T1\n"
"O10 if [[#<_selected_tool> EQ 1] AND [#<_current_tool> EQ 0] AND [#<_selected_pocket> EQ 1] AND [#<_current_pocket> EQ 0]]\n"
"G1 X1 F100\n"
"O10 endif\n"
"M6\n"
"O20 if [[#<_selected_tool> EQ 1] AND [#<_current_tool> EQ 0] AND [#<_selected_pocket> EQ 1] AND [#<_current_pocket> EQ 1]]\n"
"G1 Y1 F100\n"
"O20 endif\n"
"M30\n";
events.clear();
ok &= expect(cnc_sim_parse_program(sim,
tool_pocket_named_parameter_program,
sizeof(tool_pocket_named_parameter_program) - 1) == 0,
cnc_sim_last_error(sim));
bool saw_tool_pocket_before_change = false;
bool saw_tool_pocket_after_change = false;
for (const auto &event : events) {
saw_tool_pocket_before_change = saw_tool_pocket_before_change ||
(event.type == CNC_SIM_EVENT_LINEAR_FEED &&
event.line == 4 &&
near(event.end.x, 1.0));
saw_tool_pocket_after_change = saw_tool_pocket_after_change ||
(event.type == CNC_SIM_EVENT_LINEAR_FEED &&
event.line == 8 &&
near(event.end.y, 1.0));
}
ok &= expect(saw_tool_pocket_before_change && saw_tool_pocket_after_change,
"expected LinuxCNC tool pocket named parameters to follow selected/current pocket indexes");
const char m61_tool_pocket_named_parameter_program[] =
"G21 G90 G17\n"
"M61 Q1\n"
"O10 if [[#<_selected_tool> EQ 0] AND [#<_current_tool> EQ 0] AND [#<_selected_pocket> EQ -1] AND [#<_current_pocket> EQ 1]]\n"
"G1 X1 F100\n"
"O10 endif\n"
"M30\n";
events.clear();
ok &= expect(cnc_sim_parse_program(sim,
m61_tool_pocket_named_parameter_program,
sizeof(m61_tool_pocket_named_parameter_program) - 1) == 0,
cnc_sim_last_error(sim));
bool saw_m61_tool_pocket_named_parameter = false;
for (const auto &event : events) {
saw_m61_tool_pocket_named_parameter = saw_m61_tool_pocket_named_parameter ||
(event.type == CNC_SIM_EVENT_LINEAR_FEED &&
event.line == 4 &&
near(event.end.x, 1.0));
}
ok &= expect(saw_m61_tool_pocket_named_parameter,
"expected LinuxCNC M61 to publish the current pocket without changing selected/current tool named parameters");
{
ScopedEnv spindle_tool_env("CNC_SIM_TOOL_IN_SPINDLE", "1");
const char m61_unload_spindle_program[] =
"G21 G90 G17\n"
"M61 Q0\n"
"O10 if [#5400 EQ 0]\n"
"G1 X1 F100\n"
"O10 endif\n"
"M30\n";
events.clear();
ok &= expect(cnc_sim_parse_program(sim,
m61_unload_spindle_program,
sizeof(m61_unload_spindle_program) - 1) == 0,
cnc_sim_last_error(sim));
bool saw_m61_unload_spindle = false;
for (const auto &event : events) {
saw_m61_unload_spindle = saw_m61_unload_spindle ||
(event.type == CNC_SIM_EVENT_LINEAR_FEED &&
event.line == 4 &&
near(event.end.x, 1.0));
}
ok &= expect(saw_m61_unload_spindle,
"expected LinuxCNC M61 Q0 to unload the spindle current tool number");
}
{
ScopedEnv spindle_tool_env("CNC_SIM_TOOL_IN_SPINDLE", "1");
const char t0_m6_unload_program[] =
"G21 G90 G17\n"
"T0 M6\n"
"O10 if [#5400 EQ 0]\n"
"G1 X1 F100\n"
"O10 endif\n"
"M30\n";
events.clear();
ok &= expect(cnc_sim_parse_program(sim,
t0_m6_unload_program,
sizeof(t0_m6_unload_program) - 1) == 0,
cnc_sim_last_error(sim));
bool saw_t0_m6_unload = false;
for (const auto &event : events) {
saw_t0_m6_unload = saw_t0_m6_unload ||
(event.type == CNC_SIM_EVENT_LINEAR_FEED &&
event.line == 4 &&
near(event.end.x, 1.0));
}
ok &= expect(saw_t0_m6_unload,
"expected LinuxCNC T0 M6 to unload the spindle current tool number");
}
const char spindle_program[] =
"G21 G90 G17\n"
"S1200 M3\n"
@@ -1443,6 +1557,26 @@ int main() {
ok &= expect(saw_bracket_m428, "expected LinuxCNC source M[428] to execute as M428");
ok &= expect(saw_bracket_g434, "expected LinuxCNC source G[43.4] H[7] to execute as G43.4 H7");
const char table_dual_config[] =
"{\"backend\":\"linuxcnc-rs274\","
"\"config\":\"configs/sim/axis/vismach/5axis/table-dual-rotary/xyzab-tdr.ini\"}";
ok &= expect(cnc_sim_load_config_json(sim, table_dual_config, sizeof(table_dual_config) - 1) == 0,
cnc_sim_last_error(sim));
const char mixed_unremapped_m430_program[] =
"G21 G90\n"
"M428 M430\n";
events.clear();
ok &= expect(cnc_sim_parse_program(sim,
mixed_unremapped_m430_program,
sizeof(mixed_unremapped_m430_program) - 1) != 0,
"expected LinuxCNC source-backed config without 430remap.ngc to reject mixed M428/M430");
ok &= expect(std::string(cnc_sim_last_error(sim)) == "M-code greater than 199: M430",
"expected LinuxCNC source-backed mixed M428/M430 error to name unremapped M430");
ok &= expect(!saw_any_kinematics_switch(events, 2),
"expected LinuxCNC source-backed mixed M428/M430 error to emit no partial switch");
ok &= expect(cnc_sim_load_config_json(sim, config, sizeof(config) - 1) == 0,
cnc_sim_last_error(sim));
const char exponent_m428_control_program[] =
"G21 G90\n"
"M4.28e2\n";

View File

@@ -109,11 +109,92 @@ bool saw_comment_state(const std::vector<CncSimEvent> &events,
return false;
}
bool saw_kinematics_switch(const std::vector<CncSimEvent> &events, int line, int kinstype) {
for (const auto &event : events) {
if (event.type == CNC_SIM_EVENT_KINEMATICS_SWITCH &&
event.line == line &&
event.reserved == kinstype) {
return true;
}
}
return false;
}
bool saw_any_kinematics_switch(const std::vector<CncSimEvent> &events, int line) {
for (const auto &event : events) {
if (event.type == CNC_SIM_EVENT_KINEMATICS_SWITCH &&
event.line == line) {
return true;
}
}
return false;
}
bool expect_switchkins_remap_config(const std::string &json,
int m428_type,
int m429_type,
int m430_type,
const char *message) {
std::vector<CncSimEvent> events;
CncSimHandle *sim = cnc_sim_create();
cnc_sim_set_event_callback(sim, collect_event, &events);
const char supported_program[] =
"M428\n"
"M429\n";
const char full_program[] =
"M428\n"
"M429\n"
"M430\n";
const char *program = m430_type >= 0 ? full_program : supported_program;
const size_t program_len = m430_type >= 0 ? sizeof(full_program) - 1 : sizeof(supported_program) - 1;
bool ok = true;
ok &= expect(cnc_sim_load_config_json(sim, json.c_str(), json.size()) == 0, cnc_sim_last_error(sim));
ok &= expect(cnc_sim_parse_program(sim, program, program_len) == 0, cnc_sim_last_error(sim));
ok &= expect(saw_kinematics_switch(events, 1, m428_type), message);
ok &= expect(saw_kinematics_switch(events, 2, m429_type), message);
if (m430_type >= 0) {
ok &= expect(saw_kinematics_switch(events, 3, m430_type), message);
} else {
events.clear();
ok &= expect(cnc_sim_parse_program(sim, "M430\n", 5) != 0, message);
ok &= expect(std::string(cnc_sim_last_error(sim)) == "M-code greater than 199: M430", message);
ok &= expect(!saw_kinematics_switch(events, 1, 2), message);
std::vector<CncSimEvent> mixed_events;
CncSimHandle *mixed_sim = cnc_sim_create();
cnc_sim_set_event_callback(mixed_sim, collect_event, &mixed_events);
ok &= expect(cnc_sim_load_config_json(mixed_sim, json.c_str(), json.size()) == 0,
cnc_sim_last_error(mixed_sim));
ok &= expect(cnc_sim_parse_program(mixed_sim, "M428 M430\n", 9) != 0, message);
ok &= expect(std::string(cnc_sim_last_error(mixed_sim)) == "M-code greater than 199: M430", message);
ok &= expect(!saw_any_kinematics_switch(mixed_events, 1), message);
cnc_sim_destroy(mixed_sim);
}
cnc_sim_destroy(sim);
return ok;
}
} // namespace
int main() {
ScopedTempDir temp_dir("cnc_sim_api_smoke");
#ifndef CNC_SIM_ENABLE_LINUXCNC_RS274_BACKEND
{
CncSimHandle *default_sim = cnc_sim_create();
const char default_program[] = "G21\nM30\n";
const int default_rc = cnc_sim_parse_program(default_sim,
default_program,
sizeof(default_program) - 1);
const bool default_ok = expect(default_rc != 0,
"default LinuxCNC backend must not fall back to smoke parser");
cnc_sim_destroy(default_sim);
if (!default_ok) {
return 1;
}
}
#endif
const char program[] =
"G21 G90 G17\n"
"T1 M6\n"
@@ -1311,11 +1392,11 @@ int main() {
const char selected_current_tool_named_param_program[] =
"G21 G90 G17\n"
"T1\n"
"O10 if [[#<_selected_tool> EQ 1] AND [#<_current_tool> EQ 0]]\n"
"O10 if [[#<_selected_tool> EQ 1] AND [#<_current_tool> EQ 0] AND [#<_selected_pocket> EQ 1] AND [#<_current_pocket> EQ 0]]\n"
"G1 X1 F100\n"
"O10 endif\n"
"M6\n"
"O20 if [[#<_selected_tool> EQ 1] AND [#<_current_tool> EQ 0]]\n"
"O20 if [[#<_selected_tool> EQ 1] AND [#<_current_tool> EQ 0] AND [#<_selected_pocket> EQ 1] AND [#<_current_pocket> EQ 1]]\n"
"G1 Y1\n"
"O20 endif\n";
events.clear();
@@ -1336,14 +1417,14 @@ int main() {
near(event.end.y, 1.0));
}
ok &= expect(saw_selected_tool_before_change,
"expected LinuxCNC T word to update selected tool before current tool");
"expected LinuxCNC T word to update selected tool/pocket before current tool/pocket");
ok &= expect(saw_current_tool_after_change,
"expected LinuxCNC M6 to keep current tool tied to #5400 in the nonrandom fixture");
"expected LinuxCNC M6 to keep current tool tied to #5400 while updating current pocket in the nonrandom fixture");
const char m61_tool_named_param_program[] =
"G21 G90 G17\n"
"M61 Q1\n"
"O10 if [[#<_selected_tool> EQ 0] AND [#<_current_tool> EQ 0]]\n"
"O10 if [[#<_selected_tool> EQ 0] AND [#<_current_tool> EQ 0] AND [#<_selected_pocket> EQ -1] AND [#<_current_pocket> EQ 1]]\n"
"G1 X1 F100\n"
"O10 endif\n";
events.clear();
@@ -1359,7 +1440,7 @@ int main() {
near(event.end.x, 1.0));
}
ok &= expect(saw_m61_tool_named_params,
"expected LinuxCNC M61 to leave selected/current tool named parameters unchanged in nonrandom fixture");
"expected LinuxCNC M61 to update current pocket while leaving selected/current tool named parameters unchanged in nonrandom fixture");
const char dynamic_tool_length_program[] =
"G21 G90 G17\n"
@@ -5404,7 +5485,7 @@ int main() {
const char spindle_tool_info_parameter_program[] =
"G21 G90 G17\n"
"F100\n"
"O10 if [[#5400 EQ 1] AND [#5410 EQ 6] AND [#5411 EQ 12] AND [#5412 EQ 34] AND [#5413 EQ 5]]\n"
"O10 if [[#5400 EQ 1] AND [#5410 EQ 6] AND [#5411 EQ 12] AND [#5412 EQ 34] AND [#5413 EQ 5] AND [#<_current_pocket> EQ 0] AND [#<_selected_pocket> EQ -1]]\n"
"G1 X1\n"
"O10 endif\n";
events.clear();
@@ -5420,7 +5501,57 @@ int main() {
near(event.end.x, 1.0));
}
ok &= expect(saw_spindle_tool_info_parameter,
"expected LinuxCNC numbered tool info parameters for preloaded spindle tool");
"expected LinuxCNC numbered tool info parameters and pocket named parameters for preloaded spindle tool");
}
{
ScopedEnv spindle_tool_env("CNC_SIM_TOOL_IN_SPINDLE", "1");
const char m61_unload_spindle_program[] =
"G21 G90 G17\n"
"M61 Q0\n"
"O10 if [#5400 EQ 0]\n"
"G1 X1 F100\n"
"O10 endif\n"
"M30\n";
events.clear();
ok &= expect(cnc_sim_parse_program(sim,
m61_unload_spindle_program,
sizeof(m61_unload_spindle_program) - 1) == 0,
cnc_sim_last_error(sim));
bool saw_m61_unload_spindle = false;
for (const auto &event : events) {
saw_m61_unload_spindle = saw_m61_unload_spindle ||
(event.type == CNC_SIM_EVENT_LINEAR_FEED &&
event.line == 4 &&
near(event.end.x, 1.0));
}
ok &= expect(saw_m61_unload_spindle,
"expected LinuxCNC M61 Q0 to unload the spindle current tool number");
}
{
ScopedEnv spindle_tool_env("CNC_SIM_TOOL_IN_SPINDLE", "1");
const char t0_m6_unload_program[] =
"G21 G90 G17\n"
"T0 M6\n"
"O10 if [#5400 EQ 0]\n"
"G1 X1 F100\n"
"O10 endif\n"
"M30\n";
events.clear();
ok &= expect(cnc_sim_parse_program(sim,
t0_m6_unload_program,
sizeof(t0_m6_unload_program) - 1) == 0,
cnc_sim_last_error(sim));
bool saw_t0_m6_unload = false;
for (const auto &event : events) {
saw_t0_m6_unload = saw_t0_m6_unload ||
(event.type == CNC_SIM_EVENT_LINEAR_FEED &&
event.line == 4 &&
near(event.end.x, 1.0));
}
ok &= expect(saw_t0_m6_unload,
"expected LinuxCNC T0 M6 to unload the spindle current tool number");
}
const char g28_g30_numbered_parameter_program[] =
@@ -6210,7 +6341,8 @@ int main() {
const std::string ini_path = temp_dir.file("named_ini.ini");
{
std::ofstream ini(ini_path);
ini << "[SETUP]\nXPOS = 3.25\n";
ini << "[TRAJ]\nLINEAR_UNITS = inch\n"
<< "[SETUP]\nXPOS = 3.25\n";
}
{
ScopedEnv ini_env("INI_FILE_NAME", ini_path.c_str());
@@ -6236,6 +6368,25 @@ int main() {
event.line == 5 &&
event.end.y == 1.0);
}
const char metric_machine_named_parameter_program[] =
"G21 G90\n"
"F100\n"
"G1 X[2 + #<_metric_machine>]\n";
events.clear();
ok &= expect(cnc_sim_parse_program(sim,
metric_machine_named_parameter_program,
sizeof(metric_machine_named_parameter_program) - 1) == 0,
cnc_sim_last_error(sim));
bool saw_inch_metric_machine_named_parameter = false;
for (const auto &event : events) {
saw_inch_metric_machine_named_parameter = saw_inch_metric_machine_named_parameter ||
(event.type == CNC_SIM_EVENT_LINEAR_FEED &&
event.line == 3 &&
near(event.end.x, 2.0));
}
ok &= expect(saw_inch_metric_machine_named_parameter,
"expected #<_metric_machine> to reflect inch INI LINEAR_UNITS");
}
ok &= expect(saw_ini_named_parameter_motion, "expected #<_ini[section]key> named parameter lookup");
ok &= expect(saw_ini_named_parameter_exists_motion, "expected EXISTS for #<_ini[section]key>");
@@ -9881,6 +10032,16 @@ int main() {
sizeof(missing_named_parameter_program) - 1) != 0,
"expected undefined named parameter read to fail");
const char missing_abs_uvw_named_parameter_program[] =
"G21 G90\n"
"F100\n"
"G1 X#<_abs_u>\n";
events.clear();
ok &= expect(cnc_sim_parse_program(sim,
missing_abs_uvw_named_parameter_program,
sizeof(missing_abs_uvw_named_parameter_program) - 1) != 0,
"expected LinuxCNC to reject undefined _abs_u named parameter");
const char indexed_parameter_program[] =
"#2 = 3\n"
"#3 = 11\n"
@@ -10832,6 +10993,407 @@ int main() {
ok &= expect(config_rc == 0, cnc_sim_last_error(sim));
ok &= expect(rc != 0, "expected uncompiled linuxcnc-rs274 backend to fail clearly");
{
std::vector<CncSimEvent> scara_events;
CncSimHandle *scara_sim = cnc_sim_create();
cnc_sim_set_event_callback(scara_sim, collect_event, &scara_events);
const char scara_config[] = "{\"backend\":\"smoke\",\"switchkins\":\"scara\"}";
const char scara_program[] =
"M428\n"
"M429\n"
"M430\n";
ok &= expect(cnc_sim_load_config_json(scara_sim, scara_config, sizeof(scara_config) - 1) == 0,
cnc_sim_last_error(scara_sim));
ok &= expect(cnc_sim_parse_program(scara_sim, scara_program, sizeof(scara_program) - 1) == 0,
cnc_sim_last_error(scara_sim));
bool saw_scara_m428 = false;
bool saw_scara_m429 = false;
bool saw_scara_m430 = false;
for (const auto &event : scara_events) {
saw_scara_m428 = saw_scara_m428 ||
(event.type == CNC_SIM_EVENT_KINEMATICS_SWITCH &&
event.line == 1 &&
event.reserved == 0);
saw_scara_m429 = saw_scara_m429 ||
(event.type == CNC_SIM_EVENT_KINEMATICS_SWITCH &&
event.line == 2 &&
event.reserved == 1);
saw_scara_m430 = saw_scara_m430 ||
(event.type == CNC_SIM_EVENT_KINEMATICS_SWITCH &&
event.line == 3 &&
event.reserved == 2);
}
ok &= expect(saw_scara_m428, "expected scara M428 remap to select kinstype 0");
ok &= expect(saw_scara_m429, "expected scara M429 remap to select kinstype 1");
ok &= expect(saw_scara_m430, "expected scara M430 remap to select kinstype 2");
cnc_sim_destroy(scara_sim);
}
{
std::vector<CncSimEvent> table_dual_events;
CncSimHandle *table_dual_sim = cnc_sim_create();
cnc_sim_set_event_callback(table_dual_sim, collect_event, &table_dual_events);
const char table_dual_config[] = "{\"backend\":\"smoke\",\"switchkins\":\"table-dual-rotary\"}";
const char table_dual_program[] =
"M428\n"
"M429\n";
ok &= expect(cnc_sim_load_config_json(table_dual_sim,
table_dual_config,
sizeof(table_dual_config) - 1) == 0,
cnc_sim_last_error(table_dual_sim));
ok &= expect(cnc_sim_parse_program(table_dual_sim,
table_dual_program,
sizeof(table_dual_program) - 1) == 0,
cnc_sim_last_error(table_dual_sim));
bool saw_table_dual_m428 = false;
bool saw_table_dual_m429 = false;
for (const auto &event : table_dual_events) {
saw_table_dual_m428 = saw_table_dual_m428 ||
(event.type == CNC_SIM_EVENT_KINEMATICS_SWITCH &&
event.line == 1 &&
event.reserved == 1);
saw_table_dual_m429 = saw_table_dual_m429 ||
(event.type == CNC_SIM_EVENT_KINEMATICS_SWITCH &&
event.line == 2 &&
event.reserved == 0);
}
ok &= expect(saw_table_dual_m428, "expected table-dual-rotary M428 remap to select kinstype 1");
ok &= expect(saw_table_dual_m429, "expected table-dual-rotary M429 remap to select kinstype 0");
cnc_sim_destroy(table_dual_sim);
}
{
std::vector<CncSimEvent> xyzab_tdr_events;
CncSimHandle *xyzab_tdr_sim = cnc_sim_create();
cnc_sim_set_event_callback(xyzab_tdr_sim, collect_event, &xyzab_tdr_events);
const char xyzab_tdr_config[] = "{\"backend\":\"smoke\",\"switchkins\":\"sim-xyzab-tdr-kins\"}";
const char xyzab_tdr_program[] =
"M428\n"
"M429\n";
ok &= expect(cnc_sim_load_config_json(xyzab_tdr_sim,
xyzab_tdr_config,
sizeof(xyzab_tdr_config) - 1) == 0,
cnc_sim_last_error(xyzab_tdr_sim));
ok &= expect(cnc_sim_parse_program(xyzab_tdr_sim,
xyzab_tdr_program,
sizeof(xyzab_tdr_program) - 1) == 0,
cnc_sim_last_error(xyzab_tdr_sim));
bool saw_xyzab_tdr_m428 = false;
bool saw_xyzab_tdr_m429 = false;
for (const auto &event : xyzab_tdr_events) {
saw_xyzab_tdr_m428 = saw_xyzab_tdr_m428 ||
(event.type == CNC_SIM_EVENT_KINEMATICS_SWITCH &&
event.line == 1 &&
event.reserved == 1);
saw_xyzab_tdr_m429 = saw_xyzab_tdr_m429 ||
(event.type == CNC_SIM_EVENT_KINEMATICS_SWITCH &&
event.line == 2 &&
event.reserved == 0);
}
ok &= expect(saw_xyzab_tdr_m428, "expected sim-xyzab-tdr-kins M428 remap to select kinstype 1");
ok &= expect(saw_xyzab_tdr_m429, "expected sim-xyzab-tdr-kins M429 remap to select kinstype 0");
cnc_sim_destroy(xyzab_tdr_sim);
}
{
std::vector<CncSimEvent> puma_events;
CncSimHandle *puma_sim = cnc_sim_create();
cnc_sim_set_event_callback(puma_sim, collect_event, &puma_events);
const char puma_config[] = "{\"backend\":\"smoke\",\"switchkins\":\"puma\"}";
const char puma_program[] =
"M428\n"
"M429\n"
"M430\n";
ok &= expect(cnc_sim_load_config_json(puma_sim, puma_config, sizeof(puma_config) - 1) == 0,
cnc_sim_last_error(puma_sim));
ok &= expect(cnc_sim_parse_program(puma_sim, puma_program, sizeof(puma_program) - 1) == 0,
cnc_sim_last_error(puma_sim));
bool saw_puma_m428 = false;
bool saw_puma_m429 = false;
bool saw_puma_m430 = false;
for (const auto &event : puma_events) {
saw_puma_m428 = saw_puma_m428 ||
(event.type == CNC_SIM_EVENT_KINEMATICS_SWITCH &&
event.line == 1 &&
event.reserved == 0);
saw_puma_m429 = saw_puma_m429 ||
(event.type == CNC_SIM_EVENT_KINEMATICS_SWITCH &&
event.line == 2 &&
event.reserved == 1);
saw_puma_m430 = saw_puma_m430 ||
(event.type == CNC_SIM_EVENT_KINEMATICS_SWITCH &&
event.line == 3 &&
event.reserved == 2);
}
ok &= expect(saw_puma_m428, "expected puma M428 remap to select kinstype 0");
ok &= expect(saw_puma_m429, "expected puma M429 remap to select kinstype 1");
ok &= expect(saw_puma_m430, "expected puma M430 remap to select kinstype 2");
cnc_sim_destroy(puma_sim);
}
{
std::vector<CncSimEvent> melfa_events;
CncSimHandle *melfa_sim = cnc_sim_create();
cnc_sim_set_event_callback(melfa_sim, collect_event, &melfa_events);
const char melfa_config[] = "{\"backend\":\"smoke\",\"switchkins\":\"melfa-sim\"}";
const char melfa_program[] =
"M428\n"
"M429\n"
"M430\n";
ok &= expect(cnc_sim_load_config_json(melfa_sim, melfa_config, sizeof(melfa_config) - 1) == 0,
cnc_sim_last_error(melfa_sim));
ok &= expect(cnc_sim_parse_program(melfa_sim, melfa_program, sizeof(melfa_program) - 1) == 0,
cnc_sim_last_error(melfa_sim));
bool saw_melfa_m428 = false;
bool saw_melfa_m429 = false;
bool saw_melfa_m430 = false;
for (const auto &event : melfa_events) {
saw_melfa_m428 = saw_melfa_m428 ||
(event.type == CNC_SIM_EVENT_KINEMATICS_SWITCH &&
event.line == 1 &&
event.reserved == 0);
saw_melfa_m429 = saw_melfa_m429 ||
(event.type == CNC_SIM_EVENT_KINEMATICS_SWITCH &&
event.line == 2 &&
event.reserved == 1);
saw_melfa_m430 = saw_melfa_m430 ||
(event.type == CNC_SIM_EVENT_KINEMATICS_SWITCH &&
event.line == 3 &&
event.reserved == 2);
}
ok &= expect(saw_melfa_m428, "expected melfa-sim M428 remap to select kinstype 0");
ok &= expect(saw_melfa_m429, "expected melfa-sim M429 remap to select kinstype 1");
ok &= expect(saw_melfa_m430, "expected melfa-sim M430 remap to select kinstype 2");
cnc_sim_destroy(melfa_sim);
}
{
std::vector<CncSimEvent> hexapod_events;
CncSimHandle *hexapod_sim = cnc_sim_create();
cnc_sim_set_event_callback(hexapod_sim, collect_event, &hexapod_events);
const char hexapod_config[] = "{\"backend\":\"smoke\",\"remap\":\"hexapod-sim\"}";
const char hexapod_program[] =
"M428\n"
"M429\n"
"M430\n";
ok &= expect(cnc_sim_load_config_json(hexapod_sim, hexapod_config, sizeof(hexapod_config) - 1) == 0,
cnc_sim_last_error(hexapod_sim));
ok &= expect(cnc_sim_parse_program(hexapod_sim, hexapod_program, sizeof(hexapod_program) - 1) == 0,
cnc_sim_last_error(hexapod_sim));
bool saw_hexapod_m428 = false;
bool saw_hexapod_m429 = false;
bool saw_hexapod_m430 = false;
for (const auto &event : hexapod_events) {
saw_hexapod_m428 = saw_hexapod_m428 ||
(event.type == CNC_SIM_EVENT_KINEMATICS_SWITCH &&
event.line == 1 &&
event.reserved == 0);
saw_hexapod_m429 = saw_hexapod_m429 ||
(event.type == CNC_SIM_EVENT_KINEMATICS_SWITCH &&
event.line == 2 &&
event.reserved == 1);
saw_hexapod_m430 = saw_hexapod_m430 ||
(event.type == CNC_SIM_EVENT_KINEMATICS_SWITCH &&
event.line == 3 &&
event.reserved == 2);
}
ok &= expect(saw_hexapod_m428, "expected hexapod-sim M428 remap to select kinstype 0");
ok &= expect(saw_hexapod_m429, "expected hexapod-sim M429 remap to select kinstype 1");
ok &= expect(saw_hexapod_m430, "expected hexapod-sim M430 remap to select kinstype 2");
cnc_sim_destroy(hexapod_sim);
}
{
std::vector<CncSimEvent> trsrn_events;
CncSimHandle *trsrn_sim = cnc_sim_create();
cnc_sim_set_event_callback(trsrn_sim, collect_event, &trsrn_events);
const char trsrn_config[] = "{\"backend\":\"smoke\",\"switchkins\":\"xyzacb-trsrn\"}";
const char trsrn_program[] =
"M428\n"
"M429\n"
"M430\n";
ok &= expect(cnc_sim_load_config_json(trsrn_sim, trsrn_config, sizeof(trsrn_config) - 1) == 0,
cnc_sim_last_error(trsrn_sim));
ok &= expect(cnc_sim_parse_program(trsrn_sim, trsrn_program, sizeof(trsrn_program) - 1) == 0,
cnc_sim_last_error(trsrn_sim));
bool saw_trsrn_m428 = false;
bool saw_trsrn_m429 = false;
bool saw_trsrn_m430 = false;
for (const auto &event : trsrn_events) {
saw_trsrn_m428 = saw_trsrn_m428 ||
(event.type == CNC_SIM_EVENT_KINEMATICS_SWITCH &&
event.line == 1 &&
event.reserved == 0);
saw_trsrn_m429 = saw_trsrn_m429 ||
(event.type == CNC_SIM_EVENT_KINEMATICS_SWITCH &&
event.line == 2 &&
event.reserved == 1);
saw_trsrn_m430 = saw_trsrn_m430 ||
(event.type == CNC_SIM_EVENT_KINEMATICS_SWITCH &&
event.line == 3 &&
event.reserved == 2);
}
ok &= expect(saw_trsrn_m428, "expected xyzacb-trsrn M428 remap to select kinstype 0");
ok &= expect(saw_trsrn_m429, "expected xyzacb-trsrn M429 remap to select kinstype 1");
ok &= expect(saw_trsrn_m430, "expected xyzacb-trsrn M430 remap to select kinstype 2");
cnc_sim_destroy(trsrn_sim);
}
{
std::vector<CncSimEvent> machine_events;
CncSimHandle *machine_sim = cnc_sim_create();
cnc_sim_set_event_callback(machine_sim, collect_event, &machine_events);
const char machine_config[] = "{\"backend\":\"smoke\",\"machine\":\"sim-xyzac-trt-kins (switchkins)\"}";
const char machine_program[] =
"M428\n"
"M429\n"
"M430\n";
ok &= expect(cnc_sim_load_config_json(machine_sim, machine_config, sizeof(machine_config) - 1) == 0,
cnc_sim_last_error(machine_sim));
ok &= expect(cnc_sim_parse_program(machine_sim, machine_program, sizeof(machine_program) - 1) == 0,
cnc_sim_last_error(machine_sim));
ok &= expect(saw_kinematics_switch(machine_events, 1, 1),
"expected LinuxCNC xyzac-trt MACHINE config M428 remap to select kinstype 1");
ok &= expect(saw_kinematics_switch(machine_events, 2, 0),
"expected LinuxCNC xyzac-trt MACHINE config M429 remap to select kinstype 0");
ok &= expect(saw_kinematics_switch(machine_events, 3, 2),
"expected LinuxCNC xyzac-trt MACHINE config M430 remap to select kinstype 2");
cnc_sim_destroy(machine_sim);
}
{
std::vector<CncSimEvent> kinematics_events;
CncSimHandle *kinematics_sim = cnc_sim_create();
cnc_sim_set_event_callback(kinematics_sim, collect_event, &kinematics_events);
const char kinematics_config[] = "{\"backend\":\"smoke\",\"kinematics\":\"genhexkins\"}";
const char kinematics_program[] =
"M428\n"
"M429\n"
"M430\n";
ok &= expect(cnc_sim_load_config_json(kinematics_sim,
kinematics_config,
sizeof(kinematics_config) - 1) == 0,
cnc_sim_last_error(kinematics_sim));
ok &= expect(cnc_sim_parse_program(kinematics_sim,
kinematics_program,
sizeof(kinematics_program) - 1) == 0,
cnc_sim_last_error(kinematics_sim));
ok &= expect(saw_kinematics_switch(kinematics_events, 1, 0),
"expected LinuxCNC genhexkins KINEMATICS config M428 remap to select kinstype 0");
ok &= expect(saw_kinematics_switch(kinematics_events, 2, 1),
"expected LinuxCNC genhexkins KINEMATICS config M429 remap to select kinstype 1");
ok &= expect(saw_kinematics_switch(kinematics_events, 3, 2),
"expected LinuxCNC genhexkins KINEMATICS config M430 remap to select kinstype 2");
cnc_sim_destroy(kinematics_sim);
}
{
std::vector<CncSimEvent> config_path_events;
CncSimHandle *config_path_sim = cnc_sim_create();
cnc_sim_set_event_callback(config_path_sim, collect_event, &config_path_events);
const char config_path_config[] =
"{\"backend\":\"smoke\","
"\"config\":\"configs/sim/axis/vismach/5axis/table-dual-rotary/xyzab-tdr.ini\"}";
const char config_path_program[] =
"M428\n"
"M429\n";
ok &= expect(cnc_sim_load_config_json(config_path_sim,
config_path_config,
sizeof(config_path_config) - 1) == 0,
cnc_sim_last_error(config_path_sim));
ok &= expect(cnc_sim_parse_program(config_path_sim,
config_path_program,
sizeof(config_path_program) - 1) == 0,
cnc_sim_last_error(config_path_sim));
ok &= expect(saw_kinematics_switch(config_path_events, 1, 1),
"expected LinuxCNC xyzab-tdr config path M428 remap to select kinstype 1");
ok &= expect(saw_kinematics_switch(config_path_events, 2, 0),
"expected LinuxCNC xyzab-tdr config path M429 remap to select kinstype 0");
cnc_sim_destroy(config_path_sim);
}
{
struct SourceBackedConfigCase {
const char *field;
const char *value;
int m428_type;
int m429_type;
int m430_type;
};
const SourceBackedConfigCase source_cases[] = {
{"config", "configs/sim/axis/vismach/5axis/bridgemill/5axis.ini", 0, 1, 2},
{"config", "configs/sim/axis/vismach/5axis/table-dual-rotary/xyzab-tdr.ini", 1, 0, -1},
{"config", "configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzac-trt.ini", 1, 0, 2},
{"config", "configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzbc-trt.ini", 1, 0, 2},
{"config",
"configs/sim/axis/vismach/5axis/table-rotary_spindle-rotary-nutating/xyzacb-trsrn_twp/xyzacb-trsrn.ini",
0,
1,
2},
{"config",
"configs/sim/axis/vismach/5axis/table-rotary_spindle-rotary-nutating/xyzbca-trsrn_twp/xyzbca-trsrn.ini",
0,
1,
2},
{"config", "configs/sim/axis/vismach/hexapod-sim/hexapod.ini", 0, 1, 2},
{"config", "configs/sim/axis/vismach/melfa-sim/melfa.ini", 0, 1, 2},
{"config", "configs/sim/axis/vismach/millturn/millturn.ini", 0, 1, -1},
{"config", "configs/sim/axis/vismach/puma/puma.ini", 0, 1, 2},
{"config", "configs/sim/axis/vismach/puma/puma_cube.ini", 0, 1, 2},
{"config", "configs/sim/axis/vismach/puma/puma560.ini", 0, 1, 2},
{"config", "configs/sim/axis/vismach/puma/puma560_uvw.ini", 0, 1, 2},
{"config", "configs/sim/axis/vismach/scara/scara.ini", 0, 1, 2},
{"config", "configs/sim/qtaxis/non-trivial/scara/scara.ini", 0, 1, 2},
{"config", "configs/sim/qtvcp_screens/non-trivial/scara/scara.ini", 0, 1, 2},
{"machine", "Sim-5Axis Bridge Mill (xyzbcw)", 0, 1, 2},
{"machine", "sim-xyzab-tdr-kins (switchkins)", 1, 0, -1},
{"machine", "sim-xyzac-trt-kins (switchkins)", 1, 0, 2},
{"machine", "sim-xyzbc-trt-kins (switchkins)", 1, 0, 2},
{"machine", "xyzacb-trsrn (switchkins)", 0, 1, 2},
{"machine", "xyzbca-trsrn (switchkins)", 0, 1, 2},
{"machine", "hexapod (switchkins)", 0, 1, 2},
{"machine", "melfa (mm)", 0, 1, 2},
{"machine", "millturn (mm)", 0, 1, -1},
{"machine", "PUMA (pumakins,switchkins)", 0, 1, 2},
{"machine", "puma_cube.ini (pumakins)", 0, 1, 2},
{"machine", "puma560 (switchkins) (inch)", 0, 1, 2},
{"machine", "SCARA (genserkins,switchkins)", 0, 1, 2},
{"kinematics", "5axiskins", 0, 1, 2},
{"kinematics", "xyzab_tdr_kins", 1, 0, -1},
{"kinematics", "xyzac-trt-kins sparm=identityfirst", 1, 0, 2},
{"kinematics", "xyzbc-trt-kins sparm=identityfirst", 1, 0, 2},
{"kinematics", "xyzacb_trsrn", 0, 1, 2},
{"kinematics", "xyzbca_trsrn", 0, 1, 2},
{"kinematics", "genhexkins", 0, 1, 2},
{"kinematics", "genserkins", 0, 1, 2},
{"kinematics", "millturn", 0, 1, -1},
{"kinematics", "pumakins", 0, 1, 2},
{"kinematics", "scarakins coordinates=xyzcab", 0, 1, 2},
{"halfile", "5axisgui.hal", 0, 1, 2},
{"halfile", "5axisgui", 0, 1, 2},
{"halfile", "kinematics.hal", 0, 1, 2},
{"hal_file", "melfa_dh.hal", 0, 1, 2},
{"hal_file", "melfa_dh", 0, 1, 2},
{"hal_file", "millturn.hal", 0, 1, -1},
{"halfile", "puma_dh.hal", 0, 1, 2},
{"halfile", "puma_dh", 0, 1, 2},
{"halfile", "puma560_dh.hal", 0, 1, 2},
{"halfile", "puma560_dh", 0, 1, 2},
};
for (const SourceBackedConfigCase &source_case : source_cases) {
const std::string json = std::string("{\"backend\":\"smoke\",\"") +
source_case.field +
"\":\"" +
source_case.value +
"\"}";
ok &= expect_switchkins_remap_config(json,
source_case.m428_type,
source_case.m429_type,
source_case.m430_type,
"expected LinuxCNC source-backed switchkins remap config");
}
}
cnc_sim_destroy(sim);
return ok ? 0 : 1;
}

View File

@@ -1,5 +1,8 @@
#include "rtcp_kinematics.h"
#include "linuxcnc_cubic_adapter.h"
#include "linuxcnc_xyzab_tdr_kins_adapter.h"
#include <cmath>
#include <iostream>
@@ -63,6 +66,48 @@ bool expect_axis_joints_near(const LinuxCncAxisJoints &actual,
return ok;
}
bool expect_genhex_joints_near(const LinuxCncGenhexJoints &actual,
const LinuxCncGenhexJoints &expected,
const char *message) {
bool ok = true;
for (int i = 0; i < 6; ++i) {
ok &= expect_near_eps(actual.strut[i], expected.strut[i], 1e-6, message);
}
return ok;
}
bool expect_pentakins_joints_near(const LinuxCncPentakinsJoints &actual,
const LinuxCncPentakinsJoints &expected,
const char *message) {
bool ok = true;
for (int i = 0; i < 5; ++i) {
ok &= expect_near_eps(actual.strut[i], expected.strut[i], 1e-6, message);
}
return ok;
}
bool expect_tripod_joints_near(const LinuxCncTripodJoints &actual,
const LinuxCncTripodJoints &expected,
const char *message) {
bool ok = true;
for (int i = 0; i < 3; ++i) {
ok &= expect_near_eps(actual.strut[i], expected.strut[i], 1e-9, message);
}
return ok;
}
bool expect_scorbot_joints_near(const LinuxCncScorbotJoints &actual,
const LinuxCncScorbotJoints &expected,
const char *message) {
bool ok = true;
ok &= expect_near_eps(actual.j0, expected.j0, 1e-9, message);
ok &= expect_near_eps(actual.j1, expected.j1, 1e-9, message);
ok &= expect_near_eps(actual.j2, expected.j2, 1e-9, message);
ok &= expect_near_eps(actual.j3, expected.j3, 1e-9, message);
ok &= expect_near_eps(actual.j4, expected.j4, 1e-9, message);
return ok;
}
} // namespace
int main() {
@@ -86,6 +131,46 @@ int main() {
axis_joints,
"identity/trivkins forward/inverse roundtrip");
LinuxCncCubicSample cubic_samples[4]{};
ok &= expect(linuxcnc_cubic_source_second_segment_samples(cubic_samples, 4),
"expected LinuxCNC cubic.c second segment sample generation");
ok &= expect_near(cubic_samples[0].x, 0.0, "cubic second segment sample0 x");
ok &= expect_near(cubic_samples[0].v, 0.0, "cubic second segment sample0 v");
ok &= expect_near(cubic_samples[0].a, 0.0, "cubic second segment sample0 a");
ok &= expect_near(cubic_samples[0].j, 10.0, "cubic second segment sample0 j");
ok &= expect_near_eps(cubic_samples[1].x, 0.026041666666666668, 1e-12, "cubic second segment sample1 x");
ok &= expect_near(cubic_samples[1].v, 0.3125, "cubic second segment sample1 v");
ok &= expect_near(cubic_samples[1].a, 2.5, "cubic second segment sample1 a");
ok &= expect_near(cubic_samples[1].j, 10.0, "cubic second segment sample1 j");
ok &= expect_near_eps(cubic_samples[2].x, 0.20833333333333334, 1e-12, "cubic second segment sample2 x");
ok &= expect_near(cubic_samples[2].v, 1.25, "cubic second segment sample2 v");
ok &= expect_near(cubic_samples[2].a, 5.0, "cubic second segment sample2 a");
ok &= expect_near_eps(cubic_samples[3].x, 0.703125, 1e-12, "cubic second segment sample3 x");
ok &= expect_near(cubic_samples[3].v, 2.8125, "cubic second segment sample3 v");
ok &= expect_near(cubic_samples[3].a, 7.5, "cubic second segment sample3 a");
ok &= expect(linuxcnc_cubic_source_rejects_invalid_configuration(),
"expected LinuxCNC cubic.c to reject invalid configuration");
axis_joints = {};
axis_joints.x = 12.0;
axis_joints.y = 4.0;
axis_joints.z = 3.0;
axis_joints.a = 10.0;
axis_joints.b = 20.0;
axis_joints.c = 30.0;
axis_joints.u = 7.0;
axis_joints.v = 8.0;
axis_joints.w = 9.0;
CncSimPose corexy_pose = linuxcnc_corexykins_forward(axis_joints);
ok &= expect_near(corexy_pose.x, 8.0, "corexykins forward x");
ok &= expect_near(corexy_pose.y, 4.0, "corexykins forward y");
ok &= expect_near(corexy_pose.z, 3.0, "corexykins forward z");
ok &= expect_near(corexy_pose.a, 10.0, "corexykins forward a");
ok &= expect_near(corexy_pose.w, 9.0, "corexykins forward w");
ok &= expect_axis_joints_near(linuxcnc_corexykins_inverse(corexy_pose),
axis_joints,
"corexykins forward/inverse roundtrip");
axis_joints = {};
axis_joints.x = 10.0;
axis_joints.y = 0.0;
@@ -104,6 +189,173 @@ int main() {
axis_joints,
"rotatekins forward/inverse roundtrip");
CncSimPose genhex_pose{};
genhex_pose.x = 1.25;
genhex_pose.y = -2.5;
genhex_pose.z = 3.75;
genhex_pose.a = 4.0;
genhex_pose.b = -5.0;
genhex_pose.c = 6.0;
const LinuxCncGenhexJoints genhex_joints = linuxcnc_genhex_inverse(genhex_pose);
CncSimPose genhex_roundtrip_pose = linuxcnc_genhex_forward(genhex_joints, genhex_pose);
ok &= expect_near_eps(genhex_roundtrip_pose.x, genhex_pose.x, 1e-6, "genhexkins forward/inverse roundtrip x");
ok &= expect_near_eps(genhex_roundtrip_pose.y, genhex_pose.y, 1e-6, "genhexkins forward/inverse roundtrip y");
ok &= expect_near_eps(genhex_roundtrip_pose.z, genhex_pose.z, 1e-6, "genhexkins forward/inverse roundtrip z");
ok &= expect_near_eps(genhex_roundtrip_pose.a, genhex_pose.a, 1e-6, "genhexkins forward/inverse roundtrip a");
ok &= expect_near_eps(genhex_roundtrip_pose.b, genhex_pose.b, 1e-6, "genhexkins forward/inverse roundtrip b");
ok &= expect_near_eps(genhex_roundtrip_pose.c, genhex_pose.c, 1e-6, "genhexkins forward/inverse roundtrip c");
ok &= expect_genhex_joints_near(linuxcnc_genhex_inverse(genhex_roundtrip_pose),
genhex_joints,
"genhexkins inverse deterministic strut lengths");
CncSimPose penta_pose{};
penta_pose.x = 1.25;
penta_pose.y = -2.5;
penta_pose.z = 3.75;
penta_pose.a = 4.0;
penta_pose.b = -5.0;
const LinuxCncPentakinsJoints penta_joints = linuxcnc_pentakins_inverse(penta_pose);
CncSimPose penta_roundtrip_pose = linuxcnc_pentakins_forward(penta_joints, penta_pose);
ok &= expect_near_eps(penta_roundtrip_pose.x, penta_pose.x, 1e-6, "pentakins forward/inverse roundtrip x");
ok &= expect_near_eps(penta_roundtrip_pose.y, penta_pose.y, 1e-6, "pentakins forward/inverse roundtrip y");
ok &= expect_near_eps(penta_roundtrip_pose.z, penta_pose.z, 1e-6, "pentakins forward/inverse roundtrip z");
ok &= expect_near_eps(penta_roundtrip_pose.a, penta_pose.a, 1e-6, "pentakins forward/inverse roundtrip a");
ok &= expect_near_eps(penta_roundtrip_pose.b, penta_pose.b, 1e-6, "pentakins forward/inverse roundtrip b");
ok &= expect_pentakins_joints_near(linuxcnc_pentakins_inverse(penta_roundtrip_pose),
penta_joints,
"pentakins inverse deterministic strut lengths");
CncSimPose tripod_pose{};
tripod_pose.x = 0.2;
tripod_pose.y = 0.3;
tripod_pose.z = 0.4;
const LinuxCncTripodJoints tripod_joints = linuxcnc_tripodkins_inverse(tripod_pose);
const CncSimPose tripod_roundtrip_pose = linuxcnc_tripodkins_forward(tripod_joints);
ok &= expect_near_eps(tripod_roundtrip_pose.x, tripod_pose.x, 1e-12, "tripodkins forward/inverse roundtrip x");
ok &= expect_near_eps(tripod_roundtrip_pose.y, tripod_pose.y, 1e-12, "tripodkins forward/inverse roundtrip y");
ok &= expect_near_eps(tripod_roundtrip_pose.z, tripod_pose.z, 1e-12, "tripodkins forward/inverse roundtrip z");
ok &= expect_near(tripod_roundtrip_pose.a, 0.0, "tripodkins forward clears a");
ok &= expect_tripod_joints_near(linuxcnc_tripodkins_inverse(tripod_roundtrip_pose),
tripod_joints,
"tripodkins inverse deterministic strut lengths");
LinuxCncScorbotJoints scorbot_joints{};
scorbot_joints.j0 = 30.0;
scorbot_joints.j1 = 20.0;
scorbot_joints.j2 = -10.0;
scorbot_joints.j3 = 7.0;
scorbot_joints.j4 = -8.0;
const CncSimPose scorbot_pose = linuxcnc_scorbot_kins_forward(scorbot_joints);
ok &= expect_near_eps(scorbot_pose.x, 382.1896396002526, 1e-9, "scorbot-kins forward x");
ok &= expect_near_eps(scorbot_pose.y, 220.65729130469182, 1e-9, "scorbot-kins forward y");
ok &= expect_near_eps(scorbot_pose.z, 177.2102044105812, 1e-9, "scorbot-kins forward z");
ok &= expect_near(scorbot_pose.a, scorbot_joints.j3, "scorbot-kins forward wrist roll");
ok &= expect_near(scorbot_pose.b, scorbot_joints.j4, "scorbot-kins forward wrist pitch");
ok &= expect_scorbot_joints_near(linuxcnc_scorbot_kins_inverse(scorbot_pose),
scorbot_joints,
"scorbot-kins forward/inverse roundtrip");
const LinuxCncLinearDeltaParameters lineardelta_parameters = linuxcnc_lineardelta_default_parameters();
ok &= expect_near(lineardelta_parameters.r, 130.25, "lineardeltakins default R");
ok &= expect_near(lineardelta_parameters.l, 269.0, "lineardeltakins default L");
CncSimPose lineardelta_pose{};
lineardelta_pose.x = 1.25;
lineardelta_pose.y = -2.5;
lineardelta_pose.z = -20.0;
lineardelta_pose.a = 4.0;
lineardelta_pose.b = 5.0;
lineardelta_pose.c = 6.0;
lineardelta_pose.u = 7.0;
lineardelta_pose.v = 8.0;
lineardelta_pose.w = 9.0;
const LinuxCncAxisJoints lineardelta_joints =
linuxcnc_lineardelta_inverse(lineardelta_pose, lineardelta_parameters);
const CncSimPose lineardelta_roundtrip_pose =
linuxcnc_lineardelta_forward(lineardelta_joints, lineardelta_parameters);
ok &= expect_near_eps(lineardelta_roundtrip_pose.x,
lineardelta_pose.x,
1e-6,
"lineardeltakins forward/inverse roundtrip x");
ok &= expect_near_eps(lineardelta_roundtrip_pose.y,
lineardelta_pose.y,
1e-6,
"lineardeltakins forward/inverse roundtrip y");
ok &= expect_near_eps(lineardelta_roundtrip_pose.z,
lineardelta_pose.z,
1e-6,
"lineardeltakins forward/inverse roundtrip z");
ok &= expect_near(lineardelta_roundtrip_pose.a, lineardelta_pose.a, "lineardeltakins pass-through a");
ok &= expect_near(lineardelta_roundtrip_pose.w, lineardelta_pose.w, "lineardeltakins pass-through w");
const LinuxCncRotaryDeltaParameters rotarydelta_parameters = linuxcnc_rotarydelta_default_parameters();
ok &= expect_near(rotarydelta_parameters.platformradius, 10.0, "rotarydeltakins default platformradius");
ok &= expect_near(rotarydelta_parameters.thighlength, 10.0, "rotarydeltakins default thighlength");
ok &= expect_near(rotarydelta_parameters.shinlength, 14.0, "rotarydeltakins default shinlength");
ok &= expect_near(rotarydelta_parameters.footradius, 6.0, "rotarydeltakins default footradius");
LinuxCncAxisJoints rotarydelta_joints{};
rotarydelta_joints.x = 20.0;
rotarydelta_joints.y = 25.0;
rotarydelta_joints.z = 30.0;
rotarydelta_joints.a = 4.0;
rotarydelta_joints.b = 5.0;
rotarydelta_joints.c = 6.0;
rotarydelta_joints.u = 7.0;
rotarydelta_joints.v = 8.0;
rotarydelta_joints.w = 9.0;
const CncSimPose rotarydelta_pose =
linuxcnc_rotarydelta_forward(rotarydelta_joints, rotarydelta_parameters);
const LinuxCncAxisJoints rotarydelta_roundtrip_joints =
linuxcnc_rotarydelta_inverse(rotarydelta_pose, rotarydelta_parameters);
const CncSimPose rotarydelta_roundtrip_pose =
linuxcnc_rotarydelta_forward(rotarydelta_roundtrip_joints, rotarydelta_parameters);
ok &= expect_near_eps(rotarydelta_roundtrip_pose.x,
rotarydelta_pose.x,
1e-6,
"rotarydeltakins forward/inverse roundtrip x");
ok &= expect_near_eps(rotarydelta_roundtrip_pose.y,
rotarydelta_pose.y,
1e-6,
"rotarydeltakins forward/inverse roundtrip y");
ok &= expect_near_eps(rotarydelta_roundtrip_pose.z,
rotarydelta_pose.z,
1e-6,
"rotarydeltakins forward/inverse roundtrip z");
ok &= expect_near(rotarydelta_roundtrip_pose.a, rotarydelta_pose.a, "rotarydeltakins pass-through a");
ok &= expect_near(rotarydelta_roundtrip_pose.w, rotarydelta_pose.w, "rotarydeltakins pass-through w");
const LinuxCncMaxkinsParameters maxkins_parameters = linuxcnc_maxkins_default_parameters();
ok &= expect_near(maxkins_parameters.pivot_length, 0.666, "maxkins default pivot-length");
ok &= expect(!maxkins_parameters.conventional_directions, "maxkins default unconventional directions");
LinuxCncAxisJoints maxkins_joints{};
maxkins_joints.x = 10.0;
maxkins_joints.y = 4.0;
maxkins_joints.z = 3.0;
maxkins_joints.a = 1.0;
maxkins_joints.b = 0.0;
maxkins_joints.c = 30.0;
maxkins_joints.u = 0.0;
maxkins_joints.v = 0.0;
maxkins_joints.w = 0.0;
const CncSimPose maxkins_pose = linuxcnc_maxkins_forward(maxkins_joints, maxkins_parameters);
const LinuxCncAxisJoints maxkins_roundtrip_joints =
linuxcnc_maxkins_inverse(maxkins_pose, maxkins_parameters);
ok &= expect_axis_joints_near(maxkins_roundtrip_joints,
maxkins_joints,
"maxkins forward/inverse roundtrip");
LinuxCncAxisJoints rosekins_joints{};
rosekins_joints.x = 5.0;
rosekins_joints.y = 2.0;
rosekins_joints.z = 45.0;
const CncSimPose rosekins_pose = linuxcnc_rosekins_forward(rosekins_joints);
ok &= expect_near_eps(rosekins_pose.x, 3.53553390593274, 1e-12, "rosekins forward x");
ok &= expect_near_eps(rosekins_pose.y, 3.53553390593274, 1e-12, "rosekins forward y");
ok &= expect_near(rosekins_pose.z, 2.0, "rosekins forward z");
const LinuxCncAxisJoints rosekins_roundtrip_joints = linuxcnc_rosekins_inverse(rosekins_pose);
ok &= expect_near_eps(rosekins_roundtrip_joints.x, rosekins_joints.x, 1e-9, "rosekins inverse radius");
ok &= expect_near(rosekins_roundtrip_joints.y, rosekins_joints.y, "rosekins inverse z joint");
ok &= expect_near_eps(rosekins_roundtrip_joints.z, rosekins_joints.z, 1e-9, "rosekins inverse theta");
LinuxCncFiveAxisJoints joints{};
joints.x = 10.0;
joints.y = 20.0;
@@ -257,6 +509,24 @@ int main() {
ok &= expect_near(xyzac_roundtrip_joints.b, 0.0, "xyzac-trt inverse drops unconfigured B");
ok &= expect_near(xyzac_roundtrip_joints.w, 0.0, "xyzac-trt inverse drops unconfigured W");
xyzac_pose = linuxcnc_xyzac_trt_forward(joints, trt_parameters);
ok &= expect_near(xyzac_pose.a, joints.a, "xyzac-trt forward keeps configured A after xyzbc setup");
ok &= expect_near(xyzac_pose.b, 0.0, "xyzac-trt forward drops unconfigured B after xyzbc setup");
trt_parameters = linuxcnc_xyzbc_trt_default_parameters(250.0);
joints = {};
joints.x = 10.0;
joints.y = 20.0;
joints.z = 30.0;
joints.b = 90.0;
joints.c = 0.0;
pose = linuxcnc_xyzbc_trt_forward(joints, trt_parameters);
ok &= expect_near(pose.x, 185.0, "xyzbc-trt B90 C0 forward x after xyzac setup");
ok &= expect_near(pose.y, 20.0, "xyzbc-trt B90 C0 forward y after xyzac setup");
ok &= expect_near(pose.z, 265.0, "xyzbc-trt B90 C0 forward z after xyzac setup");
ok &= expect_near(pose.a, 0.0, "xyzbc-trt forward drops unconfigured A after xyzac setup");
ok &= expect_near(pose.b, 90.0, "xyzbc-trt forward keeps configured B after xyzac setup");
LinuxCncScaraParameters scara_parameters = linuxcnc_scara_default_parameters();
LinuxCncScaraJoints scara_joints{};
scara_joints.j0 = 0.0;
@@ -355,6 +625,32 @@ int main() {
ok &= expect_near(xyzab_tcp_roundtrip.z, axis_joints.z, "xyzab-tdr type1 roundtrip z");
ok &= expect_near(xyzab_tcp_roundtrip.a, axis_joints.a, "xyzab-tdr type1 roundtrip a");
ok &= expect_near(xyzab_tcp_roundtrip.b, axis_joints.b, "xyzab-tdr type1 roundtrip b");
ok &= expect(!linuxcnc_xyzab_tdr_kins_switch(2),
"xyzab-tdr LinuxCNC kinematicsSwitch rejects invalid switchkins type");
bool xyzab_kinstype_is_0 = true;
bool xyzab_kinstype_is_1 = true;
ok &= expect(linuxcnc_xyzab_tdr_kins_switch_state(&xyzab_kinstype_is_0, &xyzab_kinstype_is_1),
"xyzab-tdr LinuxCNC switch state is readable after invalid switchkins type");
ok &= expect(!xyzab_kinstype_is_0,
"xyzab-tdr LinuxCNC invalid switch clears kinstype.is-0");
ok &= expect(!xyzab_kinstype_is_1,
"xyzab-tdr LinuxCNC invalid switch clears kinstype.is-1");
ok &= expect(linuxcnc_xyzab_tdr_kins_switch(1),
"xyzab-tdr LinuxCNC kinematicsSwitch restores valid switchkins type");
ok &= expect(linuxcnc_xyzab_tdr_kins_switch_state(&xyzab_kinstype_is_0, &xyzab_kinstype_is_1),
"xyzab-tdr LinuxCNC switch state is readable after type1 switch");
ok &= expect(!xyzab_kinstype_is_0,
"xyzab-tdr LinuxCNC type1 switch clears kinstype.is-0");
ok &= expect(xyzab_kinstype_is_1,
"xyzab-tdr LinuxCNC type1 switch sets kinstype.is-1");
ok &= expect(linuxcnc_xyzab_tdr_kins_switch(0),
"xyzab-tdr LinuxCNC kinematicsSwitch accepts type0 switch");
ok &= expect(linuxcnc_xyzab_tdr_kins_switch_state(&xyzab_kinstype_is_0, &xyzab_kinstype_is_1),
"xyzab-tdr LinuxCNC switch state is readable after type0 switch");
ok &= expect(xyzab_kinstype_is_0,
"xyzab-tdr LinuxCNC type0 switch sets kinstype.is-0");
ok &= expect(!xyzab_kinstype_is_1,
"xyzab-tdr LinuxCNC type0 switch clears kinstype.is-1");
LinuxCncPumaParameters puma_parameters = linuxcnc_puma_default_parameters();
LinuxCncAxisJoints puma_joints{};
@@ -377,6 +673,31 @@ int main() {
ok &= expect_near(puma_roundtrip.c, puma_joints.c, "pumakins roundtrip j5");
ok &= expect_near(puma_fflags, 0, "pumakins non-singular inverse flags");
int genser_default_iterations = 0;
LinuxCncGenserParameters genser_default_parameters =
linuxcnc_genser_default_parameters(&genser_default_iterations);
ok &= expect_near(genser_default_iterations, 100, "genserkins LinuxCNC default max iterations");
ok &= expect_near(genser_default_parameters.a[2], 300.0, "genserkins LinuxCNC default A3");
ok &= expect_near(genser_default_parameters.a[3], 50.0, "genserkins LinuxCNC default A4");
ok &= expect_near_eps(genser_default_parameters.alpha[1],
-1.5707963267948966,
1e-12,
"genserkins LinuxCNC default ALPHA2");
ok &= expect_near_eps(genser_default_parameters.alpha[3],
-1.5707963267948966,
1e-12,
"genserkins LinuxCNC default ALPHA4");
ok &= expect_near_eps(genser_default_parameters.alpha[4],
1.5707963267948966,
1e-12,
"genserkins LinuxCNC default ALPHA5");
ok &= expect_near_eps(genser_default_parameters.alpha[5],
-1.5707963267948966,
1e-12,
"genserkins LinuxCNC default ALPHA6");
ok &= expect_near(genser_default_parameters.d[2], 70.0, "genserkins LinuxCNC default D3");
ok &= expect_near(genser_default_parameters.d[3], 400.0, "genserkins LinuxCNC default D4");
LinuxCncGenserParameters genser_parameters = linuxcnc_genser_puma560_parameters();
LinuxCncAxisJoints genser_joints{};
CncSimPose genser_pose = linuxcnc_genser_forward(genser_joints, genser_parameters);
@@ -441,5 +762,16 @@ int main() {
"genserkins puma560 iterative inverse c");
ok &= expect(genser_iterations > 0, "genserkins puma560 inverse should iterate from perturbed estimate");
LinuxCncAxisJoints limited_genser_inverse{};
genser_iterations = -1;
const bool limited_genser_ok = linuxcnc_genser_inverse_checked(genser_pose,
genser_estimate,
genser_parameters,
&limited_genser_inverse,
&genser_iterations,
1);
ok &= expect(!limited_genser_ok, "genserkins puma560 inverse fails when max_iterations is too low");
ok &= expect_near(genser_iterations, 1, "genserkins failed inverse reports LinuxCNC iteration count");
return ok ? 0 : 1;
}

View File

@@ -107,6 +107,8 @@ int main(int argc, char **argv) {
CncSimHandle *sim = cnc_sim_create();
bool first = true;
cnc_sim_set_event_callback(sim, print_event, &first);
const char smoke_config[] = "{\"backend\":\"smoke\"}";
cnc_sim_load_config_json(sim, smoke_config, sizeof(smoke_config) - 1);
std::cout << "[\n";
const int rc = cnc_sim_parse_program(sim, program.c_str(), program.size());

View File

@@ -143,7 +143,10 @@ bool execute_line(InterpBase *interp,
if (parse_simulator_gcode_control_line(line, &control_actions)) {
bool simulator_only_line = true;
for (const auto &action : control_actions) {
emit_simulator_gcode_control_action(sink, action, line_number);
const bool handled = emit_simulator_gcode_control_action(sink, action, line_number);
if (!handled) {
simulator_only_line = false;
}
if (action.kind == SimulatorGcodeControlKind::RtcpState &&
!action.rtcp_enabled) {
simulator_only_line = false;

3
core/wasm_shims/Python.h Normal file
View File

@@ -0,0 +1,3 @@
#pragma once
#include "boost/python/object.hpp"

View File

@@ -0,0 +1,18 @@
#ifndef CNC_SIM_WASM_SHIMS_BOOST_NONCOPYABLE_HPP
#define CNC_SIM_WASM_SHIMS_BOOST_NONCOPYABLE_HPP
namespace boost {
class noncopyable {
protected:
noncopyable() = default;
~noncopyable() = default;
private:
noncopyable(const noncopyable &) = delete;
noncopyable &operator=(const noncopyable &) = delete;
};
} // namespace boost
#endif // CNC_SIM_WASM_SHIMS_BOOST_NONCOPYABLE_HPP

View File

@@ -0,0 +1,10 @@
#pragma once
#include <boost/call_traits.hpp>
#include <boost/config.hpp>
#ifndef BOOST_DEDUCED_TYPENAME
#define BOOST_DEDUCED_TYPENAME typename
#endif
#include "boost/python/object.hpp"

View File

@@ -0,0 +1,3 @@
#pragma once
#include "boost/python/object.hpp"

View File

@@ -0,0 +1,13 @@
#pragma once
#include "boost/python/object.hpp"
namespace boost {
namespace python {
template <typename... Args>
void def(Args &&...) {
}
} // namespace python
} // namespace boost

View File

@@ -0,0 +1,3 @@
#pragma once
#include "boost/python/object.hpp"

View File

@@ -0,0 +1,25 @@
#pragma once
#include "boost/python/object.hpp"
namespace boost {
namespace python {
template <typename T>
class enum_ {
public:
explicit enum_(const char *) {
}
template <typename Value>
enum_ &value(const char *, Value) {
return *this;
}
enum_ &export_values() {
return *this;
}
};
} // namespace python
} // namespace boost

View File

@@ -0,0 +1,13 @@
#pragma once
#include "boost/python/object.hpp"
namespace boost {
namespace python {
template <typename Exception, typename Translator>
void register_exception_translator(Translator) {
}
} // namespace python
} // namespace boost

View File

@@ -0,0 +1,5 @@
#pragma once
#include "boost/python/object.hpp"
#define BOOST_PYTHON_MODULE(name) extern "C" void init_##name()

View File

@@ -1,24 +1,126 @@
#pragma once
#include <cstddef>
#include <cstdarg>
#include <sstream>
#include <stdexcept>
#include <string>
#include "boost/noncopyable.hpp"
extern "C" {
using Py_ssize_t = std::ptrdiff_t;
struct _object;
using PyObject = _object;
struct _typeobject {
const char *tp_name;
std::size_t tp_basicsize;
std::size_t tp_itemsize;
void *tp_dealloc;
void *tp_print;
void *tp_getattr;
void *tp_setattr;
void *tp_compare;
void *tp_repr;
void *tp_as_number;
void *tp_as_sequence;
void *tp_as_mapping;
void *tp_hash;
void *tp_call;
void *tp_str;
void *tp_getattro;
void *tp_setattro;
void *tp_as_buffer;
unsigned long tp_flags;
const char *tp_doc;
void *tp_traverse;
void *tp_clear;
void *tp_richcompare;
Py_ssize_t tp_weaklistoffset;
void *tp_iter;
void *tp_iternext;
void *tp_methods;
void *tp_members;
void *tp_getset;
struct _typeobject *tp_base;
void *tp_dict;
void *tp_descr_get;
void *tp_descr_set;
Py_ssize_t tp_dictoffset;
void *tp_init;
void *tp_alloc;
PyObject *(*tp_new)(struct _typeobject *, PyObject *, PyObject *);
void *tp_free;
void *tp_is_gc;
void *tp_bases;
void *tp_mro;
void *tp_cache;
void *tp_subclasses;
void *tp_weaklink;
void *tp_del;
unsigned int tp_version_tag;
void *tp_finalize;
#if PY_VERSION_HEX >= 0x030800f0
void *tp_vectorcall;
#if PY_VERSION_HEX >= 0x030c00f0
void *tp_watched;
#if PY_VERSION_HEX >= 0x030d00f0
void *tp_versions_used;
#endif
#endif
#endif
};
using PyTypeObject = _typeobject;
struct _object {
PyTypeObject *ob_type;
};
using PyObject = _object;
struct _inittab {
const char *name;
PyObject *(*initfunc)(void);
};
using PyCFunction = PyObject *(*)(PyObject *, PyObject *);
using getter = PyObject *(*)(PyObject *, void *);
using setter = int (*)(PyObject *, PyObject *, void *);
struct PyGetSetDef {
char *name;
getter get;
setter set;
char *doc;
void *closure;
};
struct PyMemberDef {
char *name;
int type;
Py_ssize_t offset;
int flags;
char *doc;
};
struct PyMethodDef {
const char *ml_name;
PyCFunction ml_meth;
int ml_flags;
const char *ml_doc;
};
struct PyModuleDef {
void *m_base;
const char *m_name;
const char *m_doc;
Py_ssize_t m_size;
PyMethodDef *m_methods;
void *m_slots;
void *m_traverse;
void *m_clear;
void *m_free;
};
int Py_IsInitialized(void);
PyObject *PyErr_Occurred(void);
void PyErr_Clear(void);
@@ -31,21 +133,66 @@ int PyUnicode_Check(PyObject *);
int PyLong_Check(PyObject *);
int PyFloat_Check(PyObject *);
int PyGen_Check(PyObject *);
int PyObject_IsInstance(PyObject *, PyObject *);
PyObject *PyObject_Str(PyObject *);
const char *PyUnicode_AsUTF8(PyObject *);
PyObject *PyUnicode_FromString(const char *);
void PyErr_SetObject(PyObject *, PyObject *);
PyObject *PyErr_Format(PyObject *, const char *, ...);
void Py_DecRef(PyObject *);
int PyArg_ParseTuple(PyObject *, const char *, ...);
int PyArg_VaParse(PyObject *, const char *, va_list);
PyObject *PyObject_CallMethod(PyObject *, char *, char *, ...);
PyObject *PyObject_GetAttrString(PyObject *, const char *);
int PyObject_SetAttrString(PyObject *, const char *, PyObject *);
int PyObject_IsTrue(PyObject *);
PyObject *PyLong_FromLong(long);
long PyLong_AsLong(PyObject *);
double PyFloat_AsDouble(PyObject *);
PyObject *PyTuple_New(Py_ssize_t);
PyObject *PyTuple_GetItem(PyObject *, Py_ssize_t);
Py_ssize_t PyTuple_Size(PyObject *);
int PyTuple_SetItem(PyObject *, Py_ssize_t, PyObject *);
PyObject *PyList_New(Py_ssize_t);
PyObject *PyList_GetItem(PyObject *, Py_ssize_t);
Py_ssize_t PyList_Size(PyObject *);
int PyList_SetItem(PyObject *, Py_ssize_t, PyObject *);
PyObject *PySequence_GetItem(PyObject *, Py_ssize_t);
Py_ssize_t PySequence_Length(PyObject *);
PyObject *Py_BuildValue(const char *, ...);
PyObject *PyModule_Create(PyModuleDef *);
int PyModule_AddObject(PyObject *, const char *, PyObject *);
int PyType_Ready(PyTypeObject *);
PyObject *PyType_GenericNew(PyTypeObject *, PyObject *, PyObject *);
void *PyObject_NewShim(std::size_t, PyTypeObject *);
extern PyObject *PyExc_KeyError;
extern PyObject *PyExc_KeyboardInterrupt;
extern PyObject *PyExc_RuntimeError;
extern PyObject *PyExc_StopIteration;
extern PyObject *PyExc_TypeError;
extern PyObject *_Py_NoneStructPtr;
extern PyTypeObject PyString_Type;
extern PyTypeObject PyInt_Type;
extern PyTypeObject PyList_Type;
#define PyObject_HEAD PyObject ob_base;
#define PyVarObject_HEAD_INIT(type, size)
#define PyModuleDef_HEAD_INIT nullptr
#define Py_TPFLAGS_DEFAULT 0
#define PyMODINIT_FUNC extern "C" PyObject *
#define METH_VARARGS 0x0001
#define Py_None (_Py_NoneStructPtr)
#define Py_TYPE(ob) ((ob)->ob_type)
#define Py_DECREF(ob) Py_DecRef(reinterpret_cast<PyObject *>(ob))
#define Py_XDECREF(ob) \
do { \
if (ob) { \
Py_DecRef(ob); \
Py_DecRef(reinterpret_cast<PyObject *>(ob)); \
} \
} while (0)
#define PyTuple_SET_ITEM(op, i, v) PyTuple_SetItem((op), (i), (v))
#define PyList_SET_ITEM(op, i, v) PyList_SetItem((op), (i), (v))
#define PyObject_New(type, typeobj) reinterpret_cast<type *>(PyObject_NewShim(sizeof(type), (typeobj)))
}
@@ -106,6 +253,93 @@ public:
}
};
struct no_init_t {};
inline constexpr no_init_t no_init{};
struct default_call_policies {};
struct reference_existing_object {};
template <typename T>
struct return_value_policy {
};
template <int, int>
struct with_custodian_and_ward_postcall {
};
template <typename... Args>
struct init {
};
class arg {
public:
explicit arg(const char *) {
}
};
template <typename T = void>
struct type_info {
};
template <typename T>
type_info<T> type_id() {
return {};
}
template <typename... Args>
object make_getter(Args &&...) {
return {};
}
template <typename... Args>
object make_setter(Args &&...) {
return {};
}
template <typename... Args>
object make_function(Args &&...) {
return {};
}
template <typename T, typename Bases = void>
class class_ {
public:
explicit class_(const char *) {
}
class_(const char *, no_init_t) {
}
class_(const char *, const char *) {
}
class_(const char *, const char *, no_init_t) {
}
template <typename Arg>
class_(const char *, Arg) {
}
template <typename... Args>
class_ &def(Args &&...) {
return *this;
}
template <typename... Args>
class_ &def_readwrite(Args &&...) {
return *this;
}
template <typename... Args>
class_ &add_property(Args &&...) {
return *this;
}
PyObject *ptr() const {
return nullptr;
}
};
inline object getattr(const object &, const char *) {
return {};
}
@@ -115,6 +349,10 @@ public:
template <typename T>
void append(const T &) {
}
template <typename T>
void extend(const T &) {
}
};
class dict : public object {
@@ -131,8 +369,35 @@ public:
}
};
template <typename... Args>
tuple make_tuple(Args &&...) {
return {};
}
inline object operator%(const char *, const tuple &) {
return {};
}
inline object operator%(const object &, const tuple &) {
return {};
}
inline object operator+(const object &, const object &) {
return {};
}
inline object operator+(const object &, const char *) {
return {};
}
inline object operator+(const char *, const object &) {
return {};
}
class scope {
public:
scope() = default;
explicit scope(const object &) {
}
@@ -187,6 +452,8 @@ allow_null_result<T> allow_null(T *value) {
template <typename T = void>
class handle {
public:
handle() = default;
template <typename U>
explicit handle(const U &) {
}
@@ -194,6 +461,10 @@ public:
explicit operator bool() const {
return false;
}
void *get() const {
return nullptr;
}
};
class str : public object {

View File

@@ -0,0 +1,16 @@
#pragma once
#include "boost/python/object.hpp"
namespace boost {
namespace python {
namespace objects {
template <typename T>
void *registered_class_object(T) {
return nullptr;
}
} // namespace objects
} // namespace python
} // namespace boost

View File

@@ -0,0 +1,13 @@
#pragma once
#include "boost/python/object.hpp"
namespace boost {
namespace python {
template <int Owner = 1, typename BasePolicy = default_call_policies>
struct return_internal_reference : BasePolicy {
};
} // namespace python
} // namespace boost

View File

@@ -0,0 +1,11 @@
#pragma once
namespace boost {
namespace python {
template <typename Map>
class map_indexing_suite {
};
} // namespace python
} // namespace boost

View File

@@ -0,0 +1,99 @@
#include "cnc_sim_api.h"
#include <cmath>
#include <cstdlib>
#include <cstring>
#include <string>
#include <vector>
#include <wordexp.h>
namespace {
int collect_event(const CncSimEvent *event, void *user_data) {
auto *events = static_cast<std::vector<CncSimEvent> *>(user_data);
events->push_back(*event);
return 0;
}
bool near(double lhs, double rhs) {
return std::fabs(lhs - rhs) < 0.000001;
}
bool wordexp_expands_home() {
const char *home = std::getenv("HOME");
if (!home || !home[0]) {
return true;
}
wordexp_t expanded{};
if (wordexp("~/cnc_sim_wordexp_probe", &expanded, 0) != 0) {
return false;
}
const std::string expected = std::string(home) + "/cnc_sim_wordexp_probe";
const bool ok = expanded.we_wordc == 1 &&
expanded.we_wordv &&
expanded.we_wordv[0] &&
std::strcmp(expanded.we_wordv[0], expected.c_str()) == 0;
wordfree(&expanded);
return ok;
}
bool wordexp_expands_environment_variables() {
setenv("CNC_SIM_WORDEXP_PROBE", "linuxcnc-wordexp", 1);
wordexp_t expanded{};
if (wordexp("$CNC_SIM_WORDEXP_PROBE/path", &expanded, 0) != 0) {
return false;
}
const bool ok = expanded.we_wordc == 1 &&
expanded.we_wordv &&
expanded.we_wordv[0] &&
std::strcmp(expanded.we_wordv[0], "linuxcnc-wordexp/path") == 0;
wordfree(&expanded);
return ok;
}
} // namespace
int main() {
if (!wordexp_expands_home()) {
return 5;
}
if (!wordexp_expands_environment_variables()) {
return 6;
}
std::vector<CncSimEvent> events;
CncSimHandle *sim = cnc_sim_create();
if (!sim) {
return 1;
}
if (cnc_sim_set_event_callback(sim, collect_event, &events) != 0) {
cnc_sim_destroy(sim);
return 2;
}
const char program[] =
"G21 G90 G17\n"
"G0 X1\n"
"M30\n";
if (cnc_sim_parse_program(sim, program, sizeof(program) - 1) != 0) {
cnc_sim_destroy(sim);
return 3;
}
bool saw_linuxcnc_rapid = false;
bool saw_program_end = false;
for (const auto &event : events) {
saw_linuxcnc_rapid = saw_linuxcnc_rapid ||
(event.type == CNC_SIM_EVENT_RAPID &&
event.line == 2 &&
near(event.end.x, 1.0));
saw_program_end = saw_program_end || event.type == CNC_SIM_EVENT_PROGRAM_END;
}
cnc_sim_destroy(sim);
return saw_linuxcnc_rapid && saw_program_end ? 0 : 4;
}

20
core/wasm_shims/libgen.h Normal file
View File

@@ -0,0 +1,20 @@
#ifndef CNC_SIM_WASM_SHIMS_LIBGEN_H
#define CNC_SIM_WASM_SHIMS_LIBGEN_H
#ifdef __cplusplus
extern "C" {
#endif
char *dirname(char *);
char *basename(char *);
#ifdef __cplusplus
}
inline char *basename(const char *path)
{
return basename(const_cast<char *>(path));
}
#endif
#endif // CNC_SIM_WASM_SHIMS_LIBGEN_H

View File

@@ -1,6 +1,12 @@
#include "boost/python/object.hpp"
#include "hal.h"
#include <cctype>
#include <cstdlib>
#include <cstring>
#include <string>
#include <wordexp.h>
int _task = 0;
extern "C" PyObject *PyInit_interpreter(void) {
@@ -11,6 +17,10 @@ extern "C" PyObject *PyInit_emccanon(void) {
return nullptr;
}
extern "C" PyObject *PyInit_gcode(void) {
return nullptr;
}
extern "C" {
struct _inittab builtin_modules[] = {
{"interpreter", PyInit_interpreter},
@@ -70,3 +80,119 @@ extern "C" int hal_get_param_value_by_name(const char *,
}
return -1;
}
namespace {
std::string expand_home_directory(const char *words) {
std::string expanded(words);
if (expanded.empty() || expanded[0] != '~') {
return expanded;
}
if (expanded.size() > 1 && expanded[1] != '/') {
return expanded;
}
const char *home = std::getenv("HOME");
if (!home || !home[0]) {
return expanded;
}
expanded.replace(0, 1, home);
return expanded;
}
bool variable_start(char value) {
const unsigned char ch = static_cast<unsigned char>(value);
return std::isalpha(ch) || value == '_';
}
bool variable_char(char value) {
const unsigned char ch = static_cast<unsigned char>(value);
return std::isalnum(ch) || value == '_';
}
std::string expand_environment_variables(const std::string &words) {
std::string expanded;
expanded.reserve(words.size());
for (size_t index = 0; index < words.size();) {
if (words[index] != '$' || index + 1 >= words.size()) {
expanded.push_back(words[index++]);
continue;
}
if (words[index + 1] == '{') {
const size_t end = words.find('}', index + 2);
if (end == std::string::npos || end == index + 2) {
expanded.push_back(words[index++]);
continue;
}
const std::string name = words.substr(index + 2, end - index - 2);
if (const char *value = std::getenv(name.c_str())) {
expanded += value;
}
index = end + 1;
continue;
}
if (!variable_start(words[index + 1])) {
expanded.push_back(words[index++]);
continue;
}
size_t end = index + 2;
while (end < words.size() && variable_char(words[end])) {
++end;
}
const std::string name = words.substr(index + 1, end - index - 1);
if (const char *value = std::getenv(name.c_str())) {
expanded += value;
}
index = end;
}
return expanded;
}
std::string expand_path_word(const char *words) {
return expand_environment_variables(expand_home_directory(words));
}
} // namespace
extern "C" int wordexp(const char *words, wordexp_t *pwordexp, int) {
if (!words || !pwordexp) {
return WRDE_BADVAL;
}
const std::string expanded = expand_path_word(words);
char **wordv = static_cast<char **>(std::calloc(2, sizeof(char *)));
if (!wordv) {
return WRDE_NOSPACE;
}
wordv[0] = static_cast<char *>(std::malloc(expanded.size() + 1));
if (!wordv[0]) {
std::free(wordv);
return WRDE_NOSPACE;
}
std::strcpy(wordv[0], expanded.c_str());
pwordexp->we_wordc = 1;
pwordexp->we_wordv = wordv;
pwordexp->we_offs = 0;
return 0;
}
extern "C" void wordfree(wordexp_t *pwordexp) {
if (!pwordexp || !pwordexp->we_wordv) {
return;
}
for (size_t index = 0; index < pwordexp->we_wordc; ++index) {
std::free(pwordexp->we_wordv[index]);
}
std::free(pwordexp->we_wordv);
pwordexp->we_wordc = 0;
pwordexp->we_wordv = nullptr;
pwordexp->we_offs = 0;
}

View File

@@ -1,13 +1,21 @@
#include "boost/python/object.hpp"
#include <cstdlib>
extern "C" {
static PyTypeObject none_type = {"NoneType"};
static PyObject none_object = {&none_type};
PyObject *PyExc_KeyError = reinterpret_cast<PyObject *>(1);
PyObject *PyExc_StopIteration = reinterpret_cast<PyObject *>(2);
PyObject *PyExc_KeyboardInterrupt = reinterpret_cast<PyObject *>(2);
PyObject *PyExc_RuntimeError = reinterpret_cast<PyObject *>(3);
PyObject *PyExc_StopIteration = reinterpret_cast<PyObject *>(4);
PyObject *PyExc_TypeError = reinterpret_cast<PyObject *>(5);
PyObject *_Py_NoneStructPtr = &none_object;
PyTypeObject PyString_Type = {"str"};
PyTypeObject PyInt_Type = {"int"};
PyTypeObject PyList_Type = {"list"};
int Py_IsInitialized(void) {
return 1;
@@ -62,6 +70,10 @@ int PyGen_Check(PyObject *) {
return 0;
}
int PyObject_IsInstance(PyObject *, PyObject *) {
return 0;
}
PyObject *PyObject_Str(PyObject *) {
return &none_object;
}
@@ -70,7 +82,122 @@ const char *PyUnicode_AsUTF8(PyObject *) {
return "";
}
PyObject *PyUnicode_FromString(const char *) {
return &none_object;
}
void PyErr_SetObject(PyObject *, PyObject *) {
}
PyObject *PyErr_Format(PyObject *, const char *, ...) {
return nullptr;
}
void Py_DecRef(PyObject *) {
}
int PyArg_ParseTuple(PyObject *, const char *, ...) {
return 0;
}
int PyArg_VaParse(PyObject *, const char *, va_list) {
return 0;
}
PyObject *PyObject_CallMethod(PyObject *, char *, char *, ...) {
return &none_object;
}
PyObject *PyObject_GetAttrString(PyObject *, const char *) {
return &none_object;
}
int PyObject_SetAttrString(PyObject *, const char *, PyObject *) {
return 0;
}
int PyObject_IsTrue(PyObject *) {
return 0;
}
PyObject *PyLong_FromLong(long) {
return &none_object;
}
long PyLong_AsLong(PyObject *) {
return 0;
}
double PyFloat_AsDouble(PyObject *) {
return 0.0;
}
PyObject *PyTuple_New(Py_ssize_t) {
return &none_object;
}
PyObject *PyTuple_GetItem(PyObject *, Py_ssize_t) {
return &none_object;
}
Py_ssize_t PyTuple_Size(PyObject *) {
return 0;
}
int PyTuple_SetItem(PyObject *, Py_ssize_t, PyObject *) {
return 0;
}
PyObject *PyList_New(Py_ssize_t) {
return &none_object;
}
PyObject *PyList_GetItem(PyObject *, Py_ssize_t) {
return &none_object;
}
Py_ssize_t PyList_Size(PyObject *) {
return 0;
}
int PyList_SetItem(PyObject *, Py_ssize_t, PyObject *) {
return 0;
}
PyObject *PySequence_GetItem(PyObject *, Py_ssize_t) {
return &none_object;
}
Py_ssize_t PySequence_Length(PyObject *) {
return 0;
}
PyObject *Py_BuildValue(const char *, ...) {
return &none_object;
}
PyObject *PyModule_Create(PyModuleDef *) {
return &none_object;
}
int PyModule_AddObject(PyObject *, const char *, PyObject *) {
return 0;
}
int PyType_Ready(PyTypeObject *) {
return 0;
}
PyObject *PyType_GenericNew(PyTypeObject *, PyObject *, PyObject *) {
return &none_object;
}
void *PyObject_NewShim(std::size_t size, PyTypeObject *type) {
auto *object = static_cast<PyObject *>(std::calloc(1, size));
if (object) {
object->ob_type = type;
}
return object;
}
}

View File

@@ -1,5 +1,8 @@
#include "pythonplugin/python_plugin.hh"
#include <cstdio>
#include <cstdlib>
__attribute__((weak)) std::string handle_pyerror() {
return "python disabled in wasm-safe probe";
}
@@ -13,7 +16,30 @@ PythonPlugin *PythonPlugin::instantiate(struct _inittab *) {
return python_plugin;
}
int PythonPlugin::configure(const char *, const char *) {
int PythonPlugin::configure(const char *iniFilename, const char *section) {
if (!section) {
error_msg = "no section";
status = PLUGIN_NO_SECTION;
return status;
}
if (!iniFilename) {
iniFilename = std::getenv("INI_FILE_NAME");
if (!iniFilename) {
error_msg = "no inifile";
status = PLUGIN_NO_INIFILE;
return status;
}
}
FILE *file = std::fopen(iniFilename, "r");
if (!file) {
error_msg = "bad inifile";
status = PLUGIN_BAD_INIFILE;
return status;
}
std::fclose(file);
status = PLUGIN_OK;
return status;
}
@@ -23,12 +49,17 @@ bool PythonPlugin::is_callable(const char *, const char *) {
}
int PythonPlugin::call(const char *,
const char *,
const char *callable,
boost::python::object,
boost::python::object,
boost::python::object &retval) {
if (!callable) {
return PLUGIN_NO_CALLABLE;
}
retval = boost::python::object();
status = PLUGIN_NO_CALLABLE;
exception_msg = handle_pyerror();
status = PLUGIN_EXCEPTION;
return status;
}

View File

@@ -8,10 +8,34 @@ int main() {
if (!plugin->usable()) {
return 2;
}
if (plugin->configure(nullptr, nullptr) != PLUGIN_NO_SECTION) {
return 6;
}
if (plugin->configure("/tmp/cnc_sim_missing_python_plugin_probe.ini", "PYTHON") != PLUGIN_BAD_INIFILE) {
return 7;
}
boost::python::object retval;
if (plugin->run_string("noop", retval, false) != PLUGIN_OK) {
return 3;
}
if (plugin->call(nullptr, nullptr, boost::python::object(), boost::python::object(), retval) != PLUGIN_NO_CALLABLE) {
return 8;
}
if (plugin->plugin_status() != PLUGIN_OK) {
return 9;
}
if (plugin->call(nullptr, "noop", boost::python::object(), boost::python::object(), retval) != PLUGIN_EXCEPTION) {
return 10;
}
if (plugin->plugin_status() != PLUGIN_EXCEPTION) {
return 11;
}
if (plugin->last_exception().empty()) {
return 12;
}
if (plugin->run_string("noop", retval, false) != PLUGIN_OK) {
return 13;
}
if (plugin->is_callable(nullptr, "noop")) {
return 4;
}
@@ -20,4 +44,3 @@ int main() {
}
return 0;
}

View File

@@ -0,0 +1,7 @@
#pragma once
#include "boost/python/object.hpp"
#define T_INT 1
#define T_DOUBLE 2
#define READONLY 1

View File

@@ -19,6 +19,7 @@ extern "C" {
toolidx_t tooldata_put(CANON_TOOL_TABLE tdata, int idx) {
if (!mmap_created) {
std::fprintf(stderr, "%5d tooldata_put() no tool_mmap_base\n", getpid());
return IDX_FAIL;
}
if (idx < 0 || idx >= CANON_POCKETS_MAX) {
@@ -110,7 +111,11 @@ int tool_mmap_creator(EMC_TOOL_STAT const *ptr, int random_toolchanger) {
}
int tool_mmap_user(void) {
return mmap_created ? 0 : -1;
if (!mmap_created) {
std::fprintf(stderr, "tool_mmap_user(): tool mmap not available\n");
return -1;
}
return 0;
}
void tool_mmap_close(void) {