Harden LinuxCNC wasm and native probe workflows
This commit is contained in:
@@ -3,7 +3,13 @@ project(cnc_sim_wasm_core LANGUAGES 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)
|
||||
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"
|
||||
CACHE FILEPATH
|
||||
"Manifest that partitions LinuxCNC rs274 sources into wasm-safe core and blocked groups"
|
||||
)
|
||||
|
||||
set(cnc_sim_core_sources
|
||||
src/canon_event_sink.cpp
|
||||
@@ -28,6 +34,137 @@ if(CNC_SIM_ENABLE_LINUXCNC_RS274_BACKEND)
|
||||
)
|
||||
endif()
|
||||
|
||||
if(CNC_SIM_ENABLE_LINUXCNC_WASM_SAFE_PROBE)
|
||||
if(NOT CNC_SIM_LINUXCNC_ROOT)
|
||||
message(FATAL_ERROR "Set CNC_SIM_LINUXCNC_ROOT to the LinuxCNC source root")
|
||||
endif()
|
||||
get_filename_component(CNC_SIM_LINUXCNC_ROOT_ABS
|
||||
"${CNC_SIM_LINUXCNC_ROOT}"
|
||||
ABSOLUTE
|
||||
BASE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/.."
|
||||
)
|
||||
if(NOT IS_DIRECTORY "${CNC_SIM_LINUXCNC_ROOT_ABS}")
|
||||
message(FATAL_ERROR "LinuxCNC source root does not exist: ${CNC_SIM_LINUXCNC_ROOT_ABS}")
|
||||
endif()
|
||||
if(NOT EXISTS "${CNC_SIM_LINUXCNC_WASM_SOURCE_MANIFEST}")
|
||||
message(FATAL_ERROR "Missing LinuxCNC wasm source manifest: ${CNC_SIM_LINUXCNC_WASM_SOURCE_MANIFEST}")
|
||||
endif()
|
||||
if(IS_DIRECTORY "${CNC_SIM_LINUXCNC_WASM_SOURCE_MANIFEST}")
|
||||
message(FATAL_ERROR "LinuxCNC wasm source manifest is not a file: ${CNC_SIM_LINUXCNC_WASM_SOURCE_MANIFEST}")
|
||||
endif()
|
||||
|
||||
set(linuxcnc_wasm_safe_probe_sources)
|
||||
set(linuxcnc_wasm_blocked_sources)
|
||||
file(STRINGS "${CNC_SIM_LINUXCNC_WASM_SOURCE_MANIFEST}" linuxcnc_wasm_manifest_lines)
|
||||
foreach(manifest_line IN LISTS linuxcnc_wasm_manifest_lines)
|
||||
string(STRIP "${manifest_line}" manifest_line)
|
||||
if(manifest_line STREQUAL "" OR manifest_line MATCHES "^#")
|
||||
continue()
|
||||
endif()
|
||||
if(NOT manifest_line MATCHES "^([^:]+):([^:]+):(.*)$")
|
||||
message(FATAL_ERROR "Bad LinuxCNC wasm source manifest line: ${manifest_line}")
|
||||
endif()
|
||||
|
||||
set(manifest_group "${CMAKE_MATCH_1}")
|
||||
set(manifest_path "${CMAKE_MATCH_2}")
|
||||
if(NOT manifest_group STREQUAL "core" AND NOT manifest_group STREQUAL "blocked")
|
||||
message(FATAL_ERROR "Unknown LinuxCNC wasm source manifest group: ${manifest_group}")
|
||||
endif()
|
||||
|
||||
set(manifest_source "${CNC_SIM_LINUXCNC_ROOT_ABS}/${manifest_path}")
|
||||
if(NOT EXISTS "${manifest_source}")
|
||||
message(FATAL_ERROR "LinuxCNC wasm manifest source does not exist: ${manifest_source}")
|
||||
endif()
|
||||
if(IS_DIRECTORY "${manifest_source}")
|
||||
message(FATAL_ERROR "LinuxCNC wasm manifest source is not a file: ${manifest_source}")
|
||||
endif()
|
||||
|
||||
if(manifest_group STREQUAL "core")
|
||||
list(APPEND linuxcnc_wasm_safe_probe_sources "${manifest_source}")
|
||||
else()
|
||||
list(APPEND linuxcnc_wasm_blocked_sources "${manifest_source}")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
list(LENGTH linuxcnc_wasm_safe_probe_sources linuxcnc_wasm_safe_probe_source_count)
|
||||
list(LENGTH linuxcnc_wasm_blocked_sources linuxcnc_wasm_blocked_source_count)
|
||||
if(linuxcnc_wasm_safe_probe_source_count EQUAL 0)
|
||||
message(FATAL_ERROR "LinuxCNC wasm source manifest has no core entries")
|
||||
endif()
|
||||
if(linuxcnc_wasm_blocked_source_count EQUAL 0)
|
||||
message(FATAL_ERROR "LinuxCNC wasm source manifest has no blocked entries")
|
||||
endif()
|
||||
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(linuxcnc_wasm_safe_probe_shims
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/wasm_shims/dlfcn.cc
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/wasm_shims/emc_status_shim.cc
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/wasm_shims/gettext_shim.cc
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/wasm_shims/linuxcnc_runtime_shim.cc
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/wasm_shims/python_c_api_shim.cc
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/wasm_shims/rtapi_compat.cc
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/wasm_shims/tooldata/tooldata_mmap_backend.cc
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/wasm_shims/tooldata/tooldata_runtime_stubs.cc
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/wasm_shims/pythonplugin/python_plugin.cc
|
||||
)
|
||||
|
||||
add_library(linuxcnc_rs274_wasm_safe_probe_objects OBJECT
|
||||
${linuxcnc_wasm_safe_probe_shims}
|
||||
${linuxcnc_wasm_safe_probe_sources}
|
||||
)
|
||||
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_include_directories(linuxcnc_rs274_wasm_safe_probe_objects
|
||||
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
|
||||
)
|
||||
|
||||
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_tooldata_fixture.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/rtcp_kinematics.cpp
|
||||
)
|
||||
|
||||
add_executable(linuxcnc_rs274_wasm_safe_probe EXCLUDE_FROM_ALL
|
||||
$<TARGET_OBJECTS:linuxcnc_rs274_wasm_safe_probe_objects>
|
||||
${linuxcnc_rs274_wasm_safe_probe_project_sources}
|
||||
${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_include_directories(linuxcnc_rs274_wasm_safe_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
|
||||
)
|
||||
target_link_libraries(linuxcnc_rs274_wasm_safe_probe PRIVATE fmt)
|
||||
|
||||
if(linuxcnc_wasm_blocked_sources)
|
||||
add_custom_target(linuxcnc_rs274_wasm_blocked_sources
|
||||
SOURCES ${linuxcnc_wasm_blocked_sources}
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
add_library(cnc_sim_objects OBJECT
|
||||
${cnc_sim_core_sources}
|
||||
)
|
||||
|
||||
@@ -39,6 +39,8 @@ void CanonEventSink::reset() {
|
||||
feed_hold_ = false;
|
||||
mist_on_ = false;
|
||||
flood_on_ = false;
|
||||
has_pending_motion_start_ = false;
|
||||
pending_motion_start_ = {};
|
||||
}
|
||||
|
||||
void CanonEventSink::set_callback(CncSimEventCallback callback, void *user_data) {
|
||||
@@ -55,6 +57,10 @@ bool CanonEventSink::callback_aborted() const {
|
||||
return callback_status_ != 0;
|
||||
}
|
||||
|
||||
void CanonEventSink::set_block_delete(bool enabled) {
|
||||
block_delete_ = enabled;
|
||||
}
|
||||
|
||||
void CanonEventSink::configure_rtcp(bool enabled, double tool_length) {
|
||||
rtcp_enabled_ = enabled;
|
||||
default_rtcp_tool_length_ = tool_length;
|
||||
@@ -80,6 +86,10 @@ void CanonEventSink::set_tool_length_offset(const CncSimPose &offset) {
|
||||
}
|
||||
|
||||
void CanonEventSink::apply_tool_length_offset(const CncSimPose &offset) {
|
||||
if (!has_pending_motion_start_) {
|
||||
pending_motion_start_ = position_;
|
||||
has_pending_motion_start_ = true;
|
||||
}
|
||||
double dx = tool_length_offset_.x - offset.x;
|
||||
double dy = tool_length_offset_.y - offset.y;
|
||||
rotate_xy(&dx, &dy, -xy_rotation_degrees_);
|
||||
@@ -305,41 +315,45 @@ void CanonEventSink::change_tool(int line) {
|
||||
|
||||
void CanonEventSink::straight_traverse(int line, const CncSimPose &end) {
|
||||
CncSimEvent event = base_event(CNC_SIM_EVENT_RAPID, line);
|
||||
event.start = position_;
|
||||
event.start = has_pending_motion_start_ ? pending_motion_start_ : position_;
|
||||
event.end = end;
|
||||
emit(event);
|
||||
emit_rtcp_pivot(line, position_, end);
|
||||
emit_rtcp_pivot(line, event.start, end);
|
||||
has_pending_motion_start_ = false;
|
||||
position_ = end;
|
||||
}
|
||||
|
||||
void CanonEventSink::straight_feed(int line, const CncSimPose &end) {
|
||||
CncSimEvent event = base_event(CNC_SIM_EVENT_LINEAR_FEED, line);
|
||||
event.start = position_;
|
||||
event.start = has_pending_motion_start_ ? pending_motion_start_ : position_;
|
||||
event.end = end;
|
||||
emit(event);
|
||||
emit_rtcp_pivot(line, position_, end);
|
||||
emit_rtcp_pivot(line, event.start, end);
|
||||
has_pending_motion_start_ = false;
|
||||
position_ = end;
|
||||
}
|
||||
|
||||
void CanonEventSink::arc_feed(int line, const CncSimPose &end, const CncSimPose ¢er, int turns) {
|
||||
CncSimEvent event = base_event(CNC_SIM_EVENT_ARC_FEED, line);
|
||||
event.start = position_;
|
||||
event.start = has_pending_motion_start_ ? pending_motion_start_ : position_;
|
||||
event.end = end;
|
||||
event.center = center;
|
||||
event.arc_turns = turns;
|
||||
emit(event);
|
||||
emit_rtcp_pivot(line, position_, end);
|
||||
emit_rtcp_pivot(line, event.start, end);
|
||||
has_pending_motion_start_ = false;
|
||||
position_ = end;
|
||||
}
|
||||
|
||||
void CanonEventSink::straight_probe(int line, const CncSimPose &end, int probe_type) {
|
||||
CncSimEvent event = base_event(CNC_SIM_EVENT_PROBE, line);
|
||||
event.start = position_;
|
||||
event.start = has_pending_motion_start_ ? pending_motion_start_ : position_;
|
||||
event.end = end;
|
||||
event.reserved = probe_type;
|
||||
emit(event);
|
||||
probe_position_ = end;
|
||||
probe_tripped_ = (probe_type & 2) == 0;
|
||||
has_pending_motion_start_ = false;
|
||||
position_ = end;
|
||||
}
|
||||
|
||||
@@ -446,6 +460,10 @@ bool CanonEventSink::flood_on() const {
|
||||
return flood_on_;
|
||||
}
|
||||
|
||||
bool CanonEventSink::block_delete() const {
|
||||
return block_delete_;
|
||||
}
|
||||
|
||||
void CanonEventSink::set_mist_on(bool enabled) {
|
||||
mist_on_ = enabled;
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ public:
|
||||
void set_callback(CncSimEventCallback callback, void *user_data);
|
||||
void clear_callback_status();
|
||||
bool callback_aborted() const;
|
||||
void set_block_delete(bool enabled);
|
||||
void configure_rtcp(bool enabled, double tool_length);
|
||||
void set_tool_length(int h_code, double tool_length);
|
||||
void set_tool_length_offset(const CncSimPose &offset);
|
||||
@@ -70,6 +71,7 @@ public:
|
||||
bool feed_hold() const;
|
||||
bool mist_on() const;
|
||||
bool flood_on() const;
|
||||
bool block_delete() const;
|
||||
void set_mist_on(bool enabled);
|
||||
void set_flood_on(bool enabled);
|
||||
|
||||
@@ -104,5 +106,8 @@ private:
|
||||
bool feed_hold_ = false;
|
||||
bool mist_on_ = false;
|
||||
bool flood_on_ = false;
|
||||
bool block_delete_ = false;
|
||||
std::unordered_map<int, double> tool_lengths_;
|
||||
bool has_pending_motion_start_ = false;
|
||||
CncSimPose pending_motion_start_{};
|
||||
};
|
||||
|
||||
@@ -152,6 +152,11 @@ int apply_config(CncSimHandle *handle, const std::string &json) {
|
||||
if (has_rtcp_enabled || has_tool_length) {
|
||||
handle->sink.configure_rtcp(rtcp_enabled, tool_length);
|
||||
}
|
||||
bool block_delete = false;
|
||||
if (contains_bool_value(compact, "blockdelete", &block_delete) ||
|
||||
contains_bool_value(compact, "block_delete", &block_delete)) {
|
||||
handle->sink.set_block_delete(block_delete);
|
||||
}
|
||||
apply_tool_length_table(handle->sink, compact);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -77,8 +77,12 @@ bool write_temp_program(const char *program,
|
||||
size_t program_len,
|
||||
std::string *path,
|
||||
std::string *error) {
|
||||
char tmpl[] = "/tmp/cnc_sim_api_XXXXXX.ngc";
|
||||
const int fd = mkstemps(tmpl, 4);
|
||||
const char *tmpdir = std::getenv("TMPDIR");
|
||||
std::string tmpl = std::string(tmpdir ? tmpdir : "/tmp") + "/cnc_sim_api_XXXXXX.ngc";
|
||||
std::vector<char> tmpl_buffer(tmpl.begin(), tmpl.end());
|
||||
tmpl_buffer.push_back('\0');
|
||||
|
||||
const int fd = mkstemps(tmpl_buffer.data(), 4);
|
||||
if (fd < 0) {
|
||||
if (error) {
|
||||
*error = "failed to create temporary ngc file";
|
||||
@@ -100,13 +104,13 @@ bool write_temp_program(const char *program,
|
||||
ok = false;
|
||||
}
|
||||
if (!ok) {
|
||||
unlink(tmpl);
|
||||
unlink(tmpl_buffer.data());
|
||||
if (error) {
|
||||
*error = "failed to write temporary ngc file";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
*path = tmpl;
|
||||
*path = tmpl_buffer.data();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -185,6 +189,7 @@ int parse_linuxcnc_rs274_backend(CanonEventSink &sink,
|
||||
cnc_sim_linuxcnc_set_canon_sink(nullptr);
|
||||
return -1;
|
||||
}
|
||||
SET_BLOCK_DELETE(sink.block_delete());
|
||||
|
||||
if (file_mode_enabled()) {
|
||||
std::string temp_path;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -3,6 +3,7 @@
|
||||
#include "canon_event_sink.h"
|
||||
|
||||
#include <cstddef>
|
||||
#include <unordered_map>
|
||||
#include <string>
|
||||
|
||||
class SmokeGcodeParser {
|
||||
@@ -12,6 +13,14 @@ public:
|
||||
int parse(const char *program, size_t program_len, std::string *error);
|
||||
|
||||
private:
|
||||
struct SmokeToolTableEntry {
|
||||
CncSimPose offset{};
|
||||
double diameter = 0.0;
|
||||
double frontangle = 0.0;
|
||||
double backangle = 0.0;
|
||||
double orientation = 0.0;
|
||||
};
|
||||
|
||||
CanonEventSink &sink_;
|
||||
bool absolute_ = true;
|
||||
bool arc_absolute_ = false;
|
||||
@@ -55,4 +64,5 @@ private:
|
||||
double oword_return_value_ = 0.0;
|
||||
bool oword_value_returned_ = false;
|
||||
int selected_tool_id_ = 0;
|
||||
std::unordered_map<int, SmokeToolTableEntry> tool_table_;
|
||||
};
|
||||
|
||||
@@ -1200,6 +1200,47 @@ int main() {
|
||||
ok &= expect(saw_g52_restore, "expected LinuxCNC G52/G92 shared offset to restore with G92.3");
|
||||
ok &= expect(saw_g52_end_line, "expected LinuxCNC G52 program end line number");
|
||||
|
||||
const char block_delete_program[] =
|
||||
"G21 G90 G17 F100\n"
|
||||
" /N10 G1 X5\n"
|
||||
"G1 X2\n"
|
||||
"M30\n";
|
||||
const char block_delete_on_config[] = "{\"backend\":\"linuxcnc-rs274\",\"blockDelete\":true}";
|
||||
events.clear();
|
||||
ok &= expect(cnc_sim_load_config_json(sim, block_delete_on_config, sizeof(block_delete_on_config) - 1) == 0,
|
||||
cnc_sim_last_error(sim));
|
||||
ok &= expect(cnc_sim_parse_program(sim, block_delete_program, sizeof(block_delete_program) - 1) == 0,
|
||||
cnc_sim_last_error(sim));
|
||||
bool saw_block_delete_skipped_line = false;
|
||||
bool saw_block_delete_followup_line = false;
|
||||
for (const auto &event : events) {
|
||||
saw_block_delete_skipped_line = saw_block_delete_skipped_line ||
|
||||
(event.type == CNC_SIM_EVENT_LINEAR_FEED &&
|
||||
event.line == 2 &&
|
||||
event.end.x == 5.0);
|
||||
saw_block_delete_followup_line = saw_block_delete_followup_line ||
|
||||
(event.type == CNC_SIM_EVENT_LINEAR_FEED &&
|
||||
event.line == 3 &&
|
||||
event.end.x == 2.0);
|
||||
}
|
||||
ok &= expect(!saw_block_delete_skipped_line, "expected LinuxCNC block-delete line to be skipped");
|
||||
ok &= expect(saw_block_delete_followup_line, "expected LinuxCNC block-delete followup line to execute");
|
||||
|
||||
const char block_delete_off_config[] = "{\"backend\":\"linuxcnc-rs274\",\"blockDelete\":false}";
|
||||
events.clear();
|
||||
ok &= expect(cnc_sim_load_config_json(sim, block_delete_off_config, sizeof(block_delete_off_config) - 1) == 0,
|
||||
cnc_sim_last_error(sim));
|
||||
ok &= expect(cnc_sim_parse_program(sim, block_delete_program, sizeof(block_delete_program) - 1) == 0,
|
||||
cnc_sim_last_error(sim));
|
||||
bool saw_block_delete_disabled_line = false;
|
||||
for (const auto &event : events) {
|
||||
saw_block_delete_disabled_line = saw_block_delete_disabled_line ||
|
||||
(event.type == CNC_SIM_EVENT_LINEAR_FEED &&
|
||||
event.line == 2 &&
|
||||
event.end.x == 5.0);
|
||||
}
|
||||
ok &= expect(saw_block_delete_disabled_line, "expected LinuxCNC disabled block-delete line to execute");
|
||||
|
||||
cnc_sim_destroy(sim);
|
||||
|
||||
int abort_count = 0;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -128,6 +128,11 @@ bool trace_enabled() {
|
||||
return std::getenv("CNC_SIM_TRACE_RS274") != nullptr;
|
||||
}
|
||||
|
||||
bool block_delete_enabled() {
|
||||
const char *value = std::getenv("CNC_SIM_BLOCK_DELETE");
|
||||
return value && std::string(value) != "0" && std::string(value) != "false";
|
||||
}
|
||||
|
||||
bool execute_line(InterpBase *interp,
|
||||
CanonEventSink &sink,
|
||||
const std::string &line,
|
||||
@@ -251,6 +256,7 @@ int main(int argc, char **argv) {
|
||||
cnc_sim_init_minimal_linuxcnc_tooldata();
|
||||
|
||||
CanonEventSink sink;
|
||||
sink.set_block_delete(block_delete_enabled());
|
||||
bool first = true;
|
||||
sink.set_callback(print_event, &first);
|
||||
cnc_sim_linuxcnc_set_canon_sink(&sink);
|
||||
@@ -271,6 +277,7 @@ int main(int argc, char **argv) {
|
||||
if (trace_enabled()) {
|
||||
std::cerr << "rs274:init done\n";
|
||||
}
|
||||
SET_BLOCK_DELETE(sink.block_delete());
|
||||
|
||||
bool ok = true;
|
||||
if (use_file_mode) {
|
||||
|
||||
4
core/wasm_shims/boost/python/dict.hpp
Normal file
4
core/wasm_shims/boost/python/dict.hpp
Normal file
@@ -0,0 +1,4 @@
|
||||
#pragma once
|
||||
|
||||
#include "boost/python/object.hpp"
|
||||
|
||||
4
core/wasm_shims/boost/python/extract.hpp
Normal file
4
core/wasm_shims/boost/python/extract.hpp
Normal file
@@ -0,0 +1,4 @@
|
||||
#pragma once
|
||||
|
||||
#include "boost/python/object.hpp"
|
||||
|
||||
4
core/wasm_shims/boost/python/import.hpp
Normal file
4
core/wasm_shims/boost/python/import.hpp
Normal file
@@ -0,0 +1,4 @@
|
||||
#pragma once
|
||||
|
||||
#include "boost/python/object.hpp"
|
||||
|
||||
4
core/wasm_shims/boost/python/list.hpp
Normal file
4
core/wasm_shims/boost/python/list.hpp
Normal file
@@ -0,0 +1,4 @@
|
||||
#pragma once
|
||||
|
||||
#include "boost/python/object.hpp"
|
||||
|
||||
211
core/wasm_shims/boost/python/object.hpp
Normal file
211
core/wasm_shims/boost/python/object.hpp
Normal file
@@ -0,0 +1,211 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
extern "C" {
|
||||
|
||||
struct _typeobject {
|
||||
const char *tp_name;
|
||||
};
|
||||
using PyTypeObject = _typeobject;
|
||||
|
||||
struct _object {
|
||||
PyTypeObject *ob_type;
|
||||
};
|
||||
using PyObject = _object;
|
||||
|
||||
struct _inittab {
|
||||
const char *name;
|
||||
PyObject *(*initfunc)(void);
|
||||
};
|
||||
|
||||
int Py_IsInitialized(void);
|
||||
PyObject *PyErr_Occurred(void);
|
||||
void PyErr_Clear(void);
|
||||
int PyErr_ExceptionMatches(PyObject *);
|
||||
int PyCallable_Check(PyObject *);
|
||||
void PyErr_Fetch(PyObject **, PyObject **, PyObject **);
|
||||
void PyErr_NormalizeException(PyObject **, PyObject **, PyObject **);
|
||||
void PyErr_Print(void);
|
||||
int PyUnicode_Check(PyObject *);
|
||||
int PyLong_Check(PyObject *);
|
||||
int PyFloat_Check(PyObject *);
|
||||
int PyGen_Check(PyObject *);
|
||||
PyObject *PyObject_Str(PyObject *);
|
||||
const char *PyUnicode_AsUTF8(PyObject *);
|
||||
void Py_DecRef(PyObject *);
|
||||
extern PyObject *PyExc_KeyError;
|
||||
extern PyObject *PyExc_StopIteration;
|
||||
extern PyObject *_Py_NoneStructPtr;
|
||||
|
||||
#define Py_None (_Py_NoneStructPtr)
|
||||
#define Py_TYPE(ob) ((ob)->ob_type)
|
||||
#define Py_XDECREF(ob) \
|
||||
do { \
|
||||
if (ob) { \
|
||||
Py_DecRef(ob); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
}
|
||||
|
||||
namespace boost {
|
||||
|
||||
template <typename T>
|
||||
const T &cref(const T &value) {
|
||||
return value;
|
||||
}
|
||||
|
||||
namespace python {
|
||||
|
||||
class error_already_set {};
|
||||
|
||||
class object {
|
||||
public:
|
||||
object() = default;
|
||||
template <typename T>
|
||||
object(const T &) {
|
||||
}
|
||||
~object() = default;
|
||||
|
||||
class attr_proxy {
|
||||
public:
|
||||
template <typename T>
|
||||
attr_proxy &operator=(const T &) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
operator object() const {
|
||||
return object();
|
||||
}
|
||||
};
|
||||
|
||||
attr_proxy attr(const char *) const {
|
||||
return {};
|
||||
}
|
||||
|
||||
object operator[](const char *) const {
|
||||
return {};
|
||||
}
|
||||
|
||||
object operator[](const std::string &) const {
|
||||
return {};
|
||||
}
|
||||
|
||||
object operator[](int) const {
|
||||
return {};
|
||||
}
|
||||
|
||||
PyObject *ptr() const {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
object operator()(Args &&...) const {
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
||||
inline object getattr(const object &, const char *) {
|
||||
return {};
|
||||
}
|
||||
|
||||
class list : public object {
|
||||
public:
|
||||
template <typename T>
|
||||
void append(const T &) {
|
||||
}
|
||||
};
|
||||
|
||||
class dict : public object {
|
||||
public:
|
||||
list keys() const {
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
||||
class tuple : public object {
|
||||
public:
|
||||
tuple() = default;
|
||||
tuple(const list &) {
|
||||
}
|
||||
};
|
||||
|
||||
class scope {
|
||||
public:
|
||||
explicit scope(const object &) {
|
||||
}
|
||||
|
||||
object::attr_proxy attr(const char *) const {
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct extract {
|
||||
explicit extract(const object &) {
|
||||
}
|
||||
|
||||
operator T() const {
|
||||
return T();
|
||||
}
|
||||
};
|
||||
|
||||
inline object import(const char *) {
|
||||
return {};
|
||||
}
|
||||
|
||||
inline int len(const list &) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline void handle_exception() {
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
struct borrowed_result {
|
||||
explicit borrowed_result(T *) {
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct allow_null_result {
|
||||
explicit allow_null_result(T *) {
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
borrowed_result<T> borrowed(T *value) {
|
||||
return borrowed_result<T>(value);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
allow_null_result<T> allow_null(T *value) {
|
||||
return allow_null_result<T>(value);
|
||||
}
|
||||
|
||||
template <typename T = void>
|
||||
class handle {
|
||||
public:
|
||||
template <typename U>
|
||||
explicit handle(const U &) {
|
||||
}
|
||||
|
||||
explicit operator bool() const {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
class str : public object {
|
||||
public:
|
||||
template <typename T>
|
||||
explicit str(const T &) {
|
||||
}
|
||||
|
||||
object join(const object &) const {
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace python
|
||||
} // namespace boost
|
||||
10
core/wasm_shims/boost/python/object_fwd.hpp
Normal file
10
core/wasm_shims/boost/python/object_fwd.hpp
Normal file
@@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
namespace boost {
|
||||
namespace python {
|
||||
|
||||
class object;
|
||||
|
||||
} // namespace python
|
||||
} // namespace boost
|
||||
|
||||
4
core/wasm_shims/boost/python/scope.hpp
Normal file
4
core/wasm_shims/boost/python/scope.hpp
Normal file
@@ -0,0 +1,4 @@
|
||||
#pragma once
|
||||
|
||||
#include "boost/python/object.hpp"
|
||||
|
||||
3
core/wasm_shims/boost/python/str.hpp
Normal file
3
core/wasm_shims/boost/python/str.hpp
Normal file
@@ -0,0 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
#include "boost/python/object.hpp"
|
||||
3
core/wasm_shims/boost/python/tuple.hpp
Normal file
3
core/wasm_shims/boost/python/tuple.hpp
Normal file
@@ -0,0 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
#include "boost/python/object.hpp"
|
||||
30
core/wasm_shims/dlfcn.cc
Normal file
30
core/wasm_shims/dlfcn.cc
Normal file
@@ -0,0 +1,30 @@
|
||||
#include "dlfcn.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
namespace {
|
||||
|
||||
thread_local char last_error[128] = "dynamic loading is unavailable in wasm-safe probe";
|
||||
|
||||
} // namespace
|
||||
|
||||
extern "C" {
|
||||
|
||||
void *dlopen(const char *, int) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void *dlsym(void *, const char *) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
char *dlerror(void) {
|
||||
return last_error;
|
||||
}
|
||||
|
||||
int dlclose(void *) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
|
||||
18
core/wasm_shims/dlfcn.h
Normal file
18
core/wasm_shims/dlfcn.h
Normal file
@@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define RTLD_GLOBAL 0x00100
|
||||
#define RTLD_NOW 0x00002
|
||||
|
||||
void *dlopen(const char *filename, int flags);
|
||||
void *dlsym(void *handle, const char *symbol);
|
||||
char *dlerror(void);
|
||||
int dlclose(void *handle);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
4
core/wasm_shims/emc_status_shim.cc
Normal file
4
core/wasm_shims/emc_status_shim.cc
Normal file
@@ -0,0 +1,4 @@
|
||||
#include "nml_intf/emc_nml.hh"
|
||||
|
||||
EMC_STAT *emcStatus = nullptr;
|
||||
|
||||
6
core/wasm_shims/gettext_shim.cc
Normal file
6
core/wasm_shims/gettext_shim.cc
Normal file
@@ -0,0 +1,6 @@
|
||||
#include <cstddef>
|
||||
|
||||
extern "C" char *gettext(const char *msgid) {
|
||||
return const_cast<char *>(msgid ? msgid : "");
|
||||
}
|
||||
|
||||
7
core/wasm_shims/interp_base_probe_main.cc
Normal file
7
core/wasm_shims/interp_base_probe_main.cc
Normal file
@@ -0,0 +1,7 @@
|
||||
#include "interp_base.hh"
|
||||
|
||||
int main() {
|
||||
InterpBase *interp = interp_from_shlib("nonexistent-interpreter.so");
|
||||
return interp == nullptr ? 0 : 1;
|
||||
}
|
||||
|
||||
40
core/wasm_shims/interp_find_probe_main.cc
Normal file
40
core/wasm_shims/interp_find_probe_main.cc
Normal file
@@ -0,0 +1,40 @@
|
||||
#include "tooldata/tooldata.hh"
|
||||
#include "rs274ngc/rs274ngc_interp.hh"
|
||||
|
||||
int main() {
|
||||
if (tool_mmap_creator(nullptr, 1) != 0) {
|
||||
return 7;
|
||||
}
|
||||
tooldata_reset();
|
||||
|
||||
CANON_TOOL_TABLE spindle = tooldata_entry_init();
|
||||
spindle.toolno = 0;
|
||||
spindle.pocketno = 0;
|
||||
if (tooldata_put(spindle, 0) != IDX_OK) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
CANON_TOOL_TABLE tool = tooldata_entry_init();
|
||||
tool.toolno = 7;
|
||||
tool.pocketno = 12;
|
||||
if (tooldata_put(tool, 12) != IDX_NEW) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
int idx = -1;
|
||||
int pocket = -1;
|
||||
auto *interp = reinterpret_cast<Interp *>(0x1);
|
||||
if (interp->find_tool_index(nullptr, 7, &idx) != INTERP_OK) {
|
||||
return 3;
|
||||
}
|
||||
if (idx != 12) {
|
||||
return 4;
|
||||
}
|
||||
if (interp->find_tool_pocket(nullptr, 7, &pocket) != INTERP_OK) {
|
||||
return 5;
|
||||
}
|
||||
if (pocket != 12) {
|
||||
return 6;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
7
core/wasm_shims/interp_find_probe_stubs.cc
Normal file
7
core/wasm_shims/interp_find_probe_stubs.cc
Normal file
@@ -0,0 +1,7 @@
|
||||
#include "rs274ngc/rs274ngc_interp.hh"
|
||||
|
||||
#include <cstdarg>
|
||||
|
||||
void Interp::setError(const char *, ...) {
|
||||
}
|
||||
|
||||
72
core/wasm_shims/linuxcnc_runtime_shim.cc
Normal file
72
core/wasm_shims/linuxcnc_runtime_shim.cc
Normal file
@@ -0,0 +1,72 @@
|
||||
#include "boost/python/object.hpp"
|
||||
#include "hal.h"
|
||||
|
||||
int _task = 0;
|
||||
|
||||
extern "C" PyObject *PyInit_interpreter(void) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
extern "C" PyObject *PyInit_emccanon(void) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
struct _inittab builtin_modules[] = {
|
||||
{"interpreter", PyInit_interpreter},
|
||||
{"emccanon", PyInit_emccanon},
|
||||
{nullptr, nullptr},
|
||||
};
|
||||
}
|
||||
|
||||
extern "C" int hal_init(const char *) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
extern "C" int hal_ready(int) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern "C" int hal_get_pin_value_by_name(const char *,
|
||||
hal_type_t *type,
|
||||
hal_data_u **data,
|
||||
bool *connected) {
|
||||
if (type) {
|
||||
*type = HAL_TYPE_UNINITIALIZED;
|
||||
}
|
||||
if (data) {
|
||||
*data = nullptr;
|
||||
}
|
||||
if (connected) {
|
||||
*connected = false;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
extern "C" int hal_get_signal_value_by_name(const char *,
|
||||
hal_type_t *type,
|
||||
hal_data_u **data,
|
||||
bool *has_writers) {
|
||||
if (type) {
|
||||
*type = HAL_TYPE_UNINITIALIZED;
|
||||
}
|
||||
if (data) {
|
||||
*data = nullptr;
|
||||
}
|
||||
if (has_writers) {
|
||||
*has_writers = false;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
extern "C" int hal_get_param_value_by_name(const char *,
|
||||
hal_type_t *type,
|
||||
hal_data_u **data) {
|
||||
if (type) {
|
||||
*type = HAL_TYPE_UNINITIALIZED;
|
||||
}
|
||||
if (data) {
|
||||
*data = nullptr;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
76
core/wasm_shims/python_c_api_shim.cc
Normal file
76
core/wasm_shims/python_c_api_shim.cc
Normal file
@@ -0,0 +1,76 @@
|
||||
#include "boost/python/object.hpp"
|
||||
|
||||
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 *_Py_NoneStructPtr = &none_object;
|
||||
|
||||
int Py_IsInitialized(void) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
PyObject *PyErr_Occurred(void) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void PyErr_Clear(void) {
|
||||
}
|
||||
|
||||
int PyErr_ExceptionMatches(PyObject *) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int PyCallable_Check(PyObject *) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void PyErr_Fetch(PyObject **exc, PyObject **val, PyObject **tb) {
|
||||
if (exc) {
|
||||
*exc = nullptr;
|
||||
}
|
||||
if (val) {
|
||||
*val = nullptr;
|
||||
}
|
||||
if (tb) {
|
||||
*tb = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void PyErr_NormalizeException(PyObject **, PyObject **, PyObject **) {
|
||||
}
|
||||
|
||||
void PyErr_Print(void) {
|
||||
}
|
||||
|
||||
int PyUnicode_Check(PyObject *) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int PyLong_Check(PyObject *) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int PyFloat_Check(PyObject *) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int PyGen_Check(PyObject *) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
PyObject *PyObject_Str(PyObject *) {
|
||||
return &none_object;
|
||||
}
|
||||
|
||||
const char *PyUnicode_AsUTF8(PyObject *) {
|
||||
return "";
|
||||
}
|
||||
|
||||
void Py_DecRef(PyObject *) {
|
||||
}
|
||||
|
||||
}
|
||||
50
core/wasm_shims/pythonplugin/python_plugin.cc
Normal file
50
core/wasm_shims/pythonplugin/python_plugin.cc
Normal file
@@ -0,0 +1,50 @@
|
||||
#include "pythonplugin/python_plugin.hh"
|
||||
|
||||
__attribute__((weak)) std::string handle_pyerror() {
|
||||
return "python disabled in wasm-safe probe";
|
||||
}
|
||||
|
||||
PythonPlugin *python_plugin = nullptr;
|
||||
|
||||
PythonPlugin *PythonPlugin::instantiate(struct _inittab *) {
|
||||
static PythonPlugin plugin;
|
||||
python_plugin = &plugin;
|
||||
python_plugin->status = PLUGIN_OK;
|
||||
return python_plugin;
|
||||
}
|
||||
|
||||
int PythonPlugin::configure(const char *, const char *) {
|
||||
status = PLUGIN_OK;
|
||||
return status;
|
||||
}
|
||||
|
||||
bool PythonPlugin::is_callable(const char *, const char *) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int PythonPlugin::call(const char *,
|
||||
const char *,
|
||||
boost::python::object,
|
||||
boost::python::object,
|
||||
boost::python::object &retval) {
|
||||
retval = boost::python::object();
|
||||
status = PLUGIN_NO_CALLABLE;
|
||||
return status;
|
||||
}
|
||||
|
||||
int PythonPlugin::run_string(const char *, boost::python::object &retval, bool) {
|
||||
retval = boost::python::object();
|
||||
status = PLUGIN_OK;
|
||||
return status;
|
||||
}
|
||||
|
||||
int PythonPlugin::call_method(boost::python::object, boost::python::object &retval) {
|
||||
retval = boost::python::object();
|
||||
status = PLUGIN_OK;
|
||||
return status;
|
||||
}
|
||||
|
||||
int PythonPlugin::initialize() {
|
||||
status = PLUGIN_OK;
|
||||
return status;
|
||||
}
|
||||
60
core/wasm_shims/pythonplugin/python_plugin.hh
Normal file
60
core/wasm_shims/pythonplugin/python_plugin.hh
Normal file
@@ -0,0 +1,60 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "boost/python/object.hpp"
|
||||
|
||||
extern std::string handle_pyerror();
|
||||
|
||||
enum pp_status {
|
||||
PLUGIN_NO_SECTION = -1,
|
||||
PLUGIN_NO_INIFILE = -2,
|
||||
PLUGIN_BAD_INIFILE = -3,
|
||||
PLUGIN_NO_TOPLEVEL = -4,
|
||||
PLUGIN_BAD_PATH = -5,
|
||||
PLUGIN_STAT_FAILED = -6,
|
||||
PLUGIN_INITTAB_FAILED = -7,
|
||||
PLUGIN_PYTHON_ALREADY_INITIALIZED = -8,
|
||||
PLUGIN_EXCEPTION_DURING_PATH_PREPEND = -9,
|
||||
PLUGIN_EXCEPTION_DURING_PATH_APPEND = -10,
|
||||
PLUGIN_INIT_EXCEPTION = -11,
|
||||
PLUGIN_PYTHON_NOT_INITIALIZED = -12,
|
||||
PLUGIN_PATH_TOO_LONG = -13,
|
||||
PLUGIN_OK = 0,
|
||||
PLUGIN_NO_CALLABLE = 1,
|
||||
PLUGIN_EXCEPTION = 2
|
||||
};
|
||||
|
||||
class PythonPlugin {
|
||||
public:
|
||||
static PythonPlugin *instantiate(struct _inittab *inittab = nullptr);
|
||||
int configure(const char *iniFilename = nullptr, const char *section = nullptr);
|
||||
bool is_callable(const char *module, const char *funcname);
|
||||
int call(const char *module,
|
||||
const char *callable,
|
||||
boost::python::object tupleargs,
|
||||
boost::python::object kwargs,
|
||||
boost::python::object &retval);
|
||||
int run_string(const char *cmd, boost::python::object &retval, bool as_file = false);
|
||||
int call_method(boost::python::object method, boost::python::object &retval);
|
||||
|
||||
int plugin_status() { return status; }
|
||||
bool usable() { return status >= PLUGIN_OK; }
|
||||
int initialize();
|
||||
const std::string &last_exception() { return exception_msg; }
|
||||
const std::string &last_errmsg() { return error_msg; }
|
||||
boost::python::object main_namespace;
|
||||
|
||||
private:
|
||||
PythonPlugin() = default;
|
||||
|
||||
int status = PLUGIN_OK;
|
||||
std::string exception_msg;
|
||||
std::string error_msg;
|
||||
int log_level = 0;
|
||||
};
|
||||
|
||||
extern PythonPlugin *python_plugin;
|
||||
|
||||
23
core/wasm_shims/pythonplugin/python_plugin_probe_main.cc
Normal file
23
core/wasm_shims/pythonplugin/python_plugin_probe_main.cc
Normal file
@@ -0,0 +1,23 @@
|
||||
#include "pythonplugin/python_plugin.hh"
|
||||
|
||||
int main() {
|
||||
auto *plugin = PythonPlugin::instantiate(nullptr);
|
||||
if (!plugin) {
|
||||
return 1;
|
||||
}
|
||||
if (!plugin->usable()) {
|
||||
return 2;
|
||||
}
|
||||
boost::python::object retval;
|
||||
if (plugin->run_string("noop", retval, false) != PLUGIN_OK) {
|
||||
return 3;
|
||||
}
|
||||
if (plugin->is_callable(nullptr, "noop")) {
|
||||
return 4;
|
||||
}
|
||||
if (handle_pyerror().empty()) {
|
||||
return 5;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
33
core/wasm_shims/rs274ngc_pre_probe_main.cc
Normal file
33
core/wasm_shims/rs274ngc_pre_probe_main.cc
Normal file
@@ -0,0 +1,33 @@
|
||||
#include "canon_event_sink.h"
|
||||
#include "linuxcnc_canon_bridge.h"
|
||||
#include "linuxcnc_tooldata_fixture.h"
|
||||
#include "rs274ngc_interp.hh"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
int main() {
|
||||
cnc_sim_init_minimal_linuxcnc_tooldata();
|
||||
|
||||
CanonEventSink sink;
|
||||
cnc_sim_linuxcnc_set_canon_sink(&sink);
|
||||
|
||||
Interp interp;
|
||||
if (interp.init() != INTERP_OK) {
|
||||
return 1;
|
||||
}
|
||||
if (interp.sequence_number() != 0) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
const double start_x = sink.position().x;
|
||||
cnc_sim_linuxcnc_set_current_line(1);
|
||||
const int read_rc = interp.read("G91 G0 X1");
|
||||
if (read_rc != INTERP_OK) {
|
||||
return 3;
|
||||
}
|
||||
const int execute_rc = interp.execute();
|
||||
if (execute_rc != INTERP_OK && execute_rc != INTERP_EXECUTE_FINISH) {
|
||||
return 4;
|
||||
}
|
||||
return std::fabs(sink.position().x - (start_x + 1.0)) < 1e-9 ? 0 : 5;
|
||||
}
|
||||
11
core/wasm_shims/rtapi_compat.cc
Normal file
11
core/wasm_shims/rtapi_compat.cc
Normal file
@@ -0,0 +1,11 @@
|
||||
#include <cstdarg>
|
||||
#include <cstdio>
|
||||
|
||||
extern "C" int rtapi_snprintf(char *buf, unsigned long size, const char *fmt, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
const int rc = std::vsnprintf(buf, static_cast<std::size_t>(size), fmt, ap);
|
||||
va_end(ap);
|
||||
return rc;
|
||||
}
|
||||
|
||||
58
core/wasm_shims/tooldata/tooldata.hh
Normal file
58
core/wasm_shims/tooldata/tooldata.hh
Normal file
@@ -0,0 +1,58 @@
|
||||
#pragma once
|
||||
|
||||
#include "nml_intf/canon.hh"
|
||||
#include "nml_intf/emc_nml.hh"
|
||||
|
||||
extern "C" {
|
||||
|
||||
typedef enum {
|
||||
IDX_OK = 0,
|
||||
IDX_NEW,
|
||||
IDX_FAIL,
|
||||
} toolidx_t;
|
||||
|
||||
typedef enum {
|
||||
DB_NOTUSED = 0,
|
||||
DB_ACTIVE,
|
||||
} tooldb_t;
|
||||
|
||||
typedef enum {
|
||||
SPINDLE_LOAD,
|
||||
SPINDLE_UNLOAD,
|
||||
TOOL_OFFSET,
|
||||
} tool_notify_t;
|
||||
|
||||
struct CANON_TOOL_TABLE tooldata_entry_init(void);
|
||||
toolidx_t tooldata_put(struct CANON_TOOL_TABLE tdata, int idx);
|
||||
toolidx_t tooldata_get(CANON_TOOL_TABLE *pdata, int idx);
|
||||
|
||||
void tooldata_init(bool random_tool_changer);
|
||||
void tooldata_reset(void);
|
||||
void tooldata_last_index_set(int idx);
|
||||
int tooldata_last_index_get(void);
|
||||
int tooldata_find_index_for_tool(int toolno);
|
||||
|
||||
void tooldata_format_toolline(int idx,
|
||||
bool ignore_zero_values,
|
||||
CANON_TOOL_TABLE tdata,
|
||||
char formatted_line[CANON_TOOL_ENTRY_LEN]);
|
||||
|
||||
void tooldata_add_init(int nonrandom_start_idx);
|
||||
int tooldata_read_entry(const char *input_line);
|
||||
|
||||
void tooldata_set_db(tooldb_t mode);
|
||||
int tooldata_load(const char *filename);
|
||||
int tooldata_save(const char *filename);
|
||||
int tool_mmap_creator(EMC_TOOL_STAT const *ptr, int random_toolchanger);
|
||||
int tool_mmap_user(void);
|
||||
void tool_mmap_close(void);
|
||||
bool tool_mmap_is_random_toolchanger(void);
|
||||
int tool_nml_register(CANON_TOOL_TABLE *tblptr);
|
||||
int tooldata_db_init(char progname_plus_args[], int random_toolchanger);
|
||||
int tooldata_db_notify(tool_notify_t ntype,
|
||||
int toolno,
|
||||
int pocketno,
|
||||
CANON_TOOL_TABLE tdata);
|
||||
int tooldata_db_getall(void);
|
||||
|
||||
} // extern "C"
|
||||
101
core/wasm_shims/tooldata/tooldata_common_probe_main.cc
Normal file
101
core/wasm_shims/tooldata/tooldata_common_probe_main.cc
Normal file
@@ -0,0 +1,101 @@
|
||||
#include "tooldata.hh"
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <unistd.h>
|
||||
|
||||
namespace {
|
||||
|
||||
std::string make_temp_template(const char *name) {
|
||||
const char *tmpdir = std::getenv("TMPDIR");
|
||||
std::string tmpl = std::string(tmpdir ? tmpdir : "/tmp") + "/" + name;
|
||||
return tmpl;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int main() {
|
||||
if (tool_mmap_user() != -1) {
|
||||
return 11;
|
||||
}
|
||||
if (tool_mmap_creator(nullptr, 1) != 0) {
|
||||
return 12;
|
||||
}
|
||||
if (tool_mmap_user() != 0) {
|
||||
return 13;
|
||||
}
|
||||
if (!tool_mmap_is_random_toolchanger()) {
|
||||
return 14;
|
||||
}
|
||||
|
||||
tooldata_init(true);
|
||||
tooldata_reset();
|
||||
tooldata_add_init(0);
|
||||
|
||||
if (tooldata_read_entry("T7 P12 Z3.5 D8 ;probe\n") != 12) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
CANON_TOOL_TABLE loaded = tooldata_entry_init();
|
||||
if (tooldata_get(&loaded, 12) != IDX_OK) {
|
||||
return 2;
|
||||
}
|
||||
if (loaded.toolno != 7 || loaded.pocketno != 12 ||
|
||||
loaded.offset.tran.z != 3.5 || loaded.diameter != 8.0 ||
|
||||
std::strcmp(loaded.comment, "probe") != 0) {
|
||||
return 3;
|
||||
}
|
||||
|
||||
char line[CANON_TOOL_ENTRY_LEN] = {};
|
||||
tooldata_format_toolline(12, true, loaded, line);
|
||||
if (!std::strstr(line, "T7") || !std::strstr(line, "P12") ||
|
||||
!std::strstr(line, "D+8.000000") || !std::strstr(line, ";probe")) {
|
||||
return 4;
|
||||
}
|
||||
|
||||
std::string path_template = make_temp_template("cnc_tooldata_common_probe_XXXXXX");
|
||||
std::vector<char> path(path_template.begin(), path_template.end());
|
||||
path.push_back('\0');
|
||||
const int fd = mkstemp(path.data());
|
||||
if (fd < 0) {
|
||||
return 5;
|
||||
}
|
||||
close(fd);
|
||||
|
||||
if (tooldata_save(path.data()) != 0) {
|
||||
std::remove(path.data());
|
||||
return 6;
|
||||
}
|
||||
|
||||
tooldata_reset();
|
||||
if (tooldata_find_index_for_tool(7) != -1) {
|
||||
std::remove(path.data());
|
||||
return 7;
|
||||
}
|
||||
if (tooldata_load(path.data()) != 0) {
|
||||
std::remove(path.data());
|
||||
return 8;
|
||||
}
|
||||
std::remove(path.data());
|
||||
|
||||
if (tooldata_get(&loaded, 12) != IDX_OK || loaded.toolno != 7 ||
|
||||
loaded.pocketno != 12 || loaded.offset.tran.z != 3.5 ||
|
||||
loaded.diameter != 8.0) {
|
||||
return 9;
|
||||
}
|
||||
|
||||
tooldata_set_db(DB_ACTIVE);
|
||||
if (tooldata_load(path.data()) != -1) {
|
||||
return 10;
|
||||
}
|
||||
|
||||
tool_mmap_close();
|
||||
if (tool_mmap_user() != -1) {
|
||||
return 15;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
127
core/wasm_shims/tooldata/tooldata_mmap_backend.cc
Normal file
127
core/wasm_shims/tooldata/tooldata_mmap_backend.cc
Normal file
@@ -0,0 +1,127 @@
|
||||
#include "tooldata.hh"
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstdio>
|
||||
#include <unistd.h>
|
||||
|
||||
namespace {
|
||||
|
||||
CANON_TOOL_TABLE tool_table[CANON_POCKETS_MAX];
|
||||
EMC_TOOL_STAT const *toolstat = nullptr;
|
||||
int last_index = 0;
|
||||
bool mmap_created = false;
|
||||
bool mmap_random_toolchanger = false;
|
||||
bool mmap_creator_called = false;
|
||||
|
||||
} // namespace
|
||||
|
||||
extern "C" {
|
||||
|
||||
toolidx_t tooldata_put(CANON_TOOL_TABLE tdata, int idx) {
|
||||
if (!mmap_created) {
|
||||
return IDX_FAIL;
|
||||
}
|
||||
if (idx < 0 || idx >= CANON_POCKETS_MAX) {
|
||||
return IDX_FAIL;
|
||||
}
|
||||
|
||||
const toolidx_t result = idx > last_index ? IDX_NEW : IDX_OK;
|
||||
tool_table[idx] = tdata;
|
||||
if (idx > last_index) {
|
||||
last_index = idx;
|
||||
}
|
||||
if (idx == 0 && toolstat) {
|
||||
*(CANON_TOOL_TABLE *)(&toolstat->toolTableCurrent) = tdata;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
toolidx_t tooldata_get(CANON_TOOL_TABLE *pdata, int idx) {
|
||||
if (!mmap_created) {
|
||||
std::fprintf(stderr, "%5d tooldata_get() not mmapped BYE\n", getpid());
|
||||
std::exit(EXIT_FAILURE);
|
||||
}
|
||||
if (!pdata || idx < 0 || idx >= CANON_POCKETS_MAX) {
|
||||
return IDX_FAIL;
|
||||
}
|
||||
*pdata = tool_table[idx];
|
||||
return IDX_OK;
|
||||
}
|
||||
|
||||
void tooldata_reset(void) {
|
||||
if (!mmap_created) {
|
||||
return;
|
||||
}
|
||||
|
||||
const CANON_TOOL_TABLE empty = tooldata_entry_init();
|
||||
for (int idx = 0; idx < CANON_POCKETS_MAX; ++idx) {
|
||||
tool_table[idx] = empty;
|
||||
}
|
||||
}
|
||||
|
||||
void tooldata_last_index_set(int idx) {
|
||||
if (!mmap_created) {
|
||||
return;
|
||||
}
|
||||
if (idx < 0 || idx >= CANON_POCKETS_MAX) {
|
||||
idx = 0;
|
||||
}
|
||||
last_index = idx;
|
||||
}
|
||||
|
||||
int tooldata_last_index_get(void) {
|
||||
if (!mmap_created) {
|
||||
return -1;
|
||||
}
|
||||
return last_index;
|
||||
}
|
||||
|
||||
int tooldata_find_index_for_tool(int toolno) {
|
||||
if (!mmap_created || toolno == -1) {
|
||||
return -1;
|
||||
}
|
||||
if (!mmap_random_toolchanger && toolno == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int found = -1;
|
||||
for (int idx = 0; idx <= last_index && idx < CANON_POCKETS_MAX; ++idx) {
|
||||
if (tool_table[idx].toolno == toolno) {
|
||||
found = idx;
|
||||
if (idx != 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
int tool_mmap_creator(EMC_TOOL_STAT const *ptr, int random_toolchanger) {
|
||||
if (mmap_creator_called) {
|
||||
std::fprintf(stderr, "Error: tool_mmap_creator already called BYE\n");
|
||||
std::exit(EXIT_FAILURE);
|
||||
}
|
||||
toolstat = ptr;
|
||||
mmap_creator_called = true;
|
||||
mmap_created = true;
|
||||
mmap_random_toolchanger = random_toolchanger;
|
||||
last_index = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tool_mmap_user(void) {
|
||||
return mmap_created ? 0 : -1;
|
||||
}
|
||||
|
||||
void tool_mmap_close(void) {
|
||||
mmap_created = false;
|
||||
mmap_random_toolchanger = false;
|
||||
toolstat = nullptr;
|
||||
last_index = 0;
|
||||
}
|
||||
|
||||
bool tool_mmap_is_random_toolchanger(void) {
|
||||
return mmap_random_toolchanger;
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
340
core/wasm_shims/tooldata/tooldata_probe_main.cc
Normal file
340
core/wasm_shims/tooldata/tooldata_probe_main.cc
Normal file
@@ -0,0 +1,340 @@
|
||||
#include "tooldata/tooldata.hh"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
#include <vector>
|
||||
|
||||
namespace {
|
||||
|
||||
std::string make_temp_path(const char *name) {
|
||||
const char *tmpdir = std::getenv("TMPDIR");
|
||||
return std::string(tmpdir ? tmpdir : "/tmp") + "/" + name;
|
||||
}
|
||||
|
||||
class ScopedTempWorkdir {
|
||||
public:
|
||||
explicit ScopedTempWorkdir(const char *name_template) {
|
||||
cwd_fd_ = open(".", O_RDONLY);
|
||||
if (cwd_fd_ < 0) {
|
||||
return;
|
||||
}
|
||||
std::string path_template = make_temp_path(name_template);
|
||||
dir_buffer_.assign(path_template.begin(), path_template.end());
|
||||
dir_buffer_.push_back('\0');
|
||||
dir_ = mkdtemp(dir_buffer_.data());
|
||||
if (!dir_) {
|
||||
return;
|
||||
}
|
||||
if (chdir(dir_) != 0) {
|
||||
dir_ = nullptr;
|
||||
return;
|
||||
}
|
||||
ok_ = true;
|
||||
}
|
||||
|
||||
~ScopedTempWorkdir() {
|
||||
if (cwd_fd_ >= 0) {
|
||||
if (ok_) {
|
||||
fchdir(cwd_fd_);
|
||||
}
|
||||
close(cwd_fd_);
|
||||
}
|
||||
if (dir_) {
|
||||
rmdir(dir_);
|
||||
}
|
||||
}
|
||||
|
||||
bool ok() const {
|
||||
return ok_;
|
||||
}
|
||||
|
||||
private:
|
||||
int cwd_fd_ = -1;
|
||||
std::vector<char> dir_buffer_;
|
||||
char *dir_ = nullptr;
|
||||
bool ok_ = false;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
int main() {
|
||||
const pid_t creator_child = fork();
|
||||
if (creator_child < 0) {
|
||||
return 41;
|
||||
}
|
||||
if (creator_child == 0) {
|
||||
if (tool_mmap_creator(nullptr, 1) != 0) {
|
||||
_exit(42);
|
||||
}
|
||||
tool_mmap_creator(nullptr, 0);
|
||||
_exit(43);
|
||||
}
|
||||
int creator_status = 0;
|
||||
if (waitpid(creator_child, &creator_status, 0) != creator_child) {
|
||||
return 44;
|
||||
}
|
||||
if (!WIFEXITED(creator_status) || WEXITSTATUS(creator_status) == 0) {
|
||||
return 45;
|
||||
}
|
||||
|
||||
if (tool_mmap_user() != -1) {
|
||||
return 25;
|
||||
}
|
||||
CANON_TOOL_TABLE uncreated_tool = tooldata_entry_init();
|
||||
if (tooldata_put(uncreated_tool, 0) != IDX_FAIL) {
|
||||
return 27;
|
||||
}
|
||||
|
||||
const pid_t get_child = fork();
|
||||
if (get_child < 0) {
|
||||
return 46;
|
||||
}
|
||||
if (get_child == 0) {
|
||||
tooldata_get(&uncreated_tool, 0);
|
||||
_exit(47);
|
||||
}
|
||||
int get_status = 0;
|
||||
if (waitpid(get_child, &get_status, 0) != get_child) {
|
||||
return 48;
|
||||
}
|
||||
if (!WIFEXITED(get_status) || WEXITSTATUS(get_status) == 0) {
|
||||
return 38;
|
||||
}
|
||||
if (tooldata_last_index_get() != -1) {
|
||||
return 40;
|
||||
}
|
||||
if (tooldata_db_getall() != -1) {
|
||||
return 28;
|
||||
}
|
||||
std::string missing_db_program_with_arg_string =
|
||||
make_temp_path("cnc_tooldata_probe_missing_db_program arg");
|
||||
std::vector<char> missing_db_program_with_arg(
|
||||
missing_db_program_with_arg_string.begin(),
|
||||
missing_db_program_with_arg_string.end());
|
||||
missing_db_program_with_arg.push_back('\0');
|
||||
if (tooldata_db_init(missing_db_program_with_arg.data(), 1) != -1) {
|
||||
return 55;
|
||||
}
|
||||
const auto separator = missing_db_program_with_arg_string.find(' ');
|
||||
if (separator == std::string::npos || missing_db_program_with_arg[separator] != 0) {
|
||||
return 56;
|
||||
}
|
||||
std::string missing_db_program_string = make_temp_path("cnc_tooldata_probe_missing_db_program");
|
||||
std::vector<char> missing_db_program(
|
||||
missing_db_program_string.begin(),
|
||||
missing_db_program_string.end());
|
||||
missing_db_program.push_back('\0');
|
||||
if (tooldata_db_init(missing_db_program.data(), 1) != -1) {
|
||||
return 31;
|
||||
}
|
||||
char too_many_db_args[] = "/bin/true a b c d e f g h i";
|
||||
if (tooldata_db_init(too_many_db_args, 1) != -1) {
|
||||
return 32;
|
||||
}
|
||||
char non_db_program[] = "/bin/true";
|
||||
if (tooldata_db_init(non_db_program, 1) != -1) {
|
||||
return 33;
|
||||
}
|
||||
if (tool_nml_register(nullptr) != -1) {
|
||||
return 29;
|
||||
}
|
||||
alignas(EMC_TOOL_STAT) unsigned char toolstat_storage[sizeof(EMC_TOOL_STAT)] = {};
|
||||
auto *toolstat = reinterpret_cast<EMC_TOOL_STAT *>(toolstat_storage);
|
||||
if (tool_mmap_creator(toolstat, 1) != 0) {
|
||||
return 15;
|
||||
}
|
||||
if (tool_mmap_user() != 0) {
|
||||
return 26;
|
||||
}
|
||||
if (!tool_mmap_is_random_toolchanger()) {
|
||||
return 16;
|
||||
}
|
||||
tooldata_set_db(DB_ACTIVE);
|
||||
const std::string unavailable_db_path = make_temp_path("cnc_tooldata_probe_db_unavailable.tbl");
|
||||
if (tooldata_load(unavailable_db_path.c_str()) != -1) {
|
||||
return 30;
|
||||
}
|
||||
tooldata_set_db(DB_ACTIVE);
|
||||
tooldata_init(false);
|
||||
if (tooldata_save(nullptr) != 0) {
|
||||
return 34;
|
||||
}
|
||||
tooldata_set_db(DB_NOTUSED);
|
||||
tooldata_init(true);
|
||||
tooldata_reset();
|
||||
|
||||
CANON_TOOL_TABLE spindle = tooldata_entry_init();
|
||||
spindle.toolno = 0;
|
||||
spindle.pocketno = 0;
|
||||
if (tooldata_put(spindle, 0) != IDX_OK) {
|
||||
return 1;
|
||||
}
|
||||
if (toolstat->toolTableCurrent.toolno != 0 || toolstat->toolTableCurrent.pocketno != 0) {
|
||||
return 49;
|
||||
}
|
||||
|
||||
CANON_TOOL_TABLE tool = tooldata_entry_init();
|
||||
tool.toolno = 7;
|
||||
tool.pocketno = 12;
|
||||
tool.offset.tran.z = 3.5;
|
||||
tool.diameter = 8.0;
|
||||
std::strncpy(tool.comment, "probe", CANON_TOOL_COMMENT_SIZE - 1);
|
||||
if (tooldata_put(tool, 12) != IDX_NEW) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
CANON_TOOL_TABLE loaded = tooldata_entry_init();
|
||||
if (tooldata_get(&loaded, 12) != IDX_OK) {
|
||||
return 3;
|
||||
}
|
||||
if (loaded.toolno != 7 || loaded.pocketno != 12 || loaded.offset.tran.z != 3.5 || loaded.diameter != 8.0) {
|
||||
return 4;
|
||||
}
|
||||
char db_spindle_line[CANON_TOOL_ENTRY_LEN] = {};
|
||||
{
|
||||
ScopedTempWorkdir db_spindle_workdir("cnc_tooldata_probe_workdir.XXXXXX");
|
||||
if (!db_spindle_workdir.ok()) {
|
||||
return 35;
|
||||
}
|
||||
std::remove("./db_spindle.tbl");
|
||||
tooldata_set_db(DB_ACTIVE);
|
||||
if (tooldata_save(nullptr) != 0) {
|
||||
return 36;
|
||||
}
|
||||
FILE *db_spindle_fp = std::fopen("./db_spindle.tbl", "r");
|
||||
if (!db_spindle_fp) {
|
||||
return 37;
|
||||
}
|
||||
std::fread(db_spindle_line, 1, sizeof(db_spindle_line) - 1, db_spindle_fp);
|
||||
std::fclose(db_spindle_fp);
|
||||
std::remove("./db_spindle.tbl");
|
||||
tooldata_set_db(DB_NOTUSED);
|
||||
}
|
||||
if (!std::strstr(db_spindle_line, "T0") || std::strstr(db_spindle_line, "T7")) {
|
||||
return 38;
|
||||
}
|
||||
if (tooldata_find_index_for_tool(7) != 12) {
|
||||
return 5;
|
||||
}
|
||||
if (tooldata_find_index_for_tool(0) != 0) {
|
||||
return 6;
|
||||
}
|
||||
if (tooldata_find_index_for_tool(-1) != -1) {
|
||||
return 17;
|
||||
}
|
||||
|
||||
tooldata_init(false);
|
||||
if (tooldata_find_index_for_tool(0) != 0) {
|
||||
return 18;
|
||||
}
|
||||
tooldata_init(true);
|
||||
|
||||
tooldata_last_index_set(12);
|
||||
if (tooldata_last_index_get() != 12) {
|
||||
return 7;
|
||||
}
|
||||
if (tooldata_put(tool, -1) != IDX_FAIL) {
|
||||
return 50;
|
||||
}
|
||||
if (tooldata_put(tool, CANON_POCKETS_MAX) != IDX_FAIL) {
|
||||
return 51;
|
||||
}
|
||||
if (tooldata_last_index_get() != 12) {
|
||||
return 52;
|
||||
}
|
||||
if (tooldata_get(&loaded, -1) != IDX_FAIL) {
|
||||
return 53;
|
||||
}
|
||||
if (tooldata_get(&loaded, CANON_POCKETS_MAX) != IDX_FAIL) {
|
||||
return 54;
|
||||
}
|
||||
tooldata_last_index_set(CANON_POCKETS_MAX);
|
||||
if (tooldata_last_index_get() != 0) {
|
||||
return 24;
|
||||
}
|
||||
tooldata_last_index_set(12);
|
||||
|
||||
char line[CANON_TOOL_ENTRY_LEN] = {};
|
||||
tooldata_format_toolline(12, true, loaded, line);
|
||||
if (!std::strstr(line, "T7") || !std::strstr(line, "P12") || !std::strstr(line, "D+8.000000")) {
|
||||
return 8;
|
||||
}
|
||||
|
||||
std::string path_template = make_temp_path("cnc_tooldata_probe_XXXXXX");
|
||||
std::vector<char> path(path_template.begin(), path_template.end());
|
||||
path.push_back('\0');
|
||||
const int fd = mkstemp(path.data());
|
||||
if (fd < 0) {
|
||||
return 9;
|
||||
}
|
||||
close(fd);
|
||||
tooldata_last_index_set(0);
|
||||
if (tooldata_save(path.data()) != 0) {
|
||||
std::remove(path.data());
|
||||
return 10;
|
||||
}
|
||||
|
||||
tooldata_reset();
|
||||
if (tooldata_find_index_for_tool(7) != -1) {
|
||||
std::remove(path.data());
|
||||
return 11;
|
||||
}
|
||||
if (tooldata_load(path.data()) != 0) {
|
||||
std::remove(path.data());
|
||||
return 12;
|
||||
}
|
||||
std::remove(path.data());
|
||||
|
||||
CANON_TOOL_TABLE reloaded = tooldata_entry_init();
|
||||
if (tooldata_get(&reloaded, 12) != IDX_OK) {
|
||||
return 13;
|
||||
}
|
||||
if (reloaded.toolno != 7 || reloaded.pocketno != 12 ||
|
||||
reloaded.offset.tran.z != 3.5 || reloaded.diameter != 8.0) {
|
||||
return 14;
|
||||
}
|
||||
|
||||
tooldata_init(false);
|
||||
std::string nonrandom_path_template = make_temp_path("cnc_tooldata_nonrandom_probe_XXXXXX");
|
||||
std::vector<char> nonrandom_path(nonrandom_path_template.begin(), nonrandom_path_template.end());
|
||||
nonrandom_path.push_back('\0');
|
||||
const int nonrandom_fd = mkstemp(nonrandom_path.data());
|
||||
if (nonrandom_fd < 0) {
|
||||
return 19;
|
||||
}
|
||||
FILE *nonrandom_fp = fdopen(nonrandom_fd, "w");
|
||||
if (!nonrandom_fp) {
|
||||
close(nonrandom_fd);
|
||||
std::remove(nonrandom_path.data());
|
||||
return 20;
|
||||
}
|
||||
std::fputs("T-1 P5 Z4.25\n", nonrandom_fp);
|
||||
std::fclose(nonrandom_fp);
|
||||
|
||||
if (tooldata_load(nonrandom_path.data()) != 0) {
|
||||
std::remove(nonrandom_path.data());
|
||||
return 21;
|
||||
}
|
||||
std::remove(nonrandom_path.data());
|
||||
|
||||
CANON_TOOL_TABLE nonrandom_spindle = tooldata_entry_init();
|
||||
if (tooldata_get(&nonrandom_spindle, 0) != IDX_OK) {
|
||||
return 22;
|
||||
}
|
||||
if (nonrandom_spindle.toolno != -1 || nonrandom_spindle.pocketno != 5 ||
|
||||
nonrandom_spindle.offset.tran.z != 4.25) {
|
||||
return 23;
|
||||
}
|
||||
|
||||
tool_mmap_close();
|
||||
if (tool_mmap_user() != -1) {
|
||||
return 39;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
47
core/wasm_shims/tooldata/tooldata_runtime_stubs.cc
Normal file
47
core/wasm_shims/tooldata/tooldata_runtime_stubs.cc
Normal file
@@ -0,0 +1,47 @@
|
||||
#include "tooldata.hh"
|
||||
|
||||
#include <cstring>
|
||||
#include <unistd.h>
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr int MAX_DB_PROGRAM_ARGS = 10;
|
||||
bool db_live = false;
|
||||
|
||||
} // namespace
|
||||
|
||||
extern "C" {
|
||||
|
||||
int tool_nml_register(CANON_TOOL_TABLE *tblptr) {
|
||||
return tblptr ? 0 : -1;
|
||||
}
|
||||
|
||||
int tooldata_db_init(char progname_plus_args[], int) {
|
||||
if (!progname_plus_args) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
char *saveptr = nullptr;
|
||||
char *program = strtok_r(progname_plus_args, " ", &saveptr);
|
||||
int argc = 0;
|
||||
for (char *token = program; token; token = strtok_r(nullptr, " ", &saveptr)) {
|
||||
++argc;
|
||||
if (argc >= MAX_DB_PROGRAM_ARGS) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if (!program || access(program, X_OK) != 0) {
|
||||
return -1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int tooldata_db_notify(tool_notify_t, int, int, CANON_TOOL_TABLE) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tooldata_db_getall(void) {
|
||||
return db_live ? 0 : -1;
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
Reference in New Issue
Block a user