diff --git a/wasm-port/AGENTS.md b/wasm-port/AGENTS.md index 3ea1c96..f379314 100644 --- a/wasm-port/AGENTS.md +++ b/wasm-port/AGENTS.md @@ -13,6 +13,9 @@ This workspace is separate from the upstream LinuxCNC tree in Build a standalone CNC simulation system that: - reuses LinuxCNC source as the semantic source of truth; +- derives the CNC simulation program primarily from the LinuxCNC source + program and strictly follows LinuxCNC behavior, structure, and semantics + unless a documented standalone runtime boundary requires adaptation; - compiles core CNC logic to WASM; - uses HTML + JavaScript for the frontend; - uses OPFS for browser persistence; @@ -44,24 +47,28 @@ expanded into a separate implementation of G-code behavior. ## Engineering Rules 1. Reuse LinuxCNC source before reimplementing any CNC logic. -2. Do not add new project-authored CNC semantics when LinuxCNC source exists. +2. Treat the LinuxCNC source program as the primary implementation source for + the CNC simulation program. Standalone code must strictly follow vendored + LinuxCNC behavior and may only adapt runtime edges such as filesystem, HAL, + IPC, process model, and browser integration. +3. Do not add new project-authored CNC semantics when LinuxCNC source exists. Replace temporary wrapper behavior with direct calls into vendored LinuxCNC source, or with the narrowest shims needed to make those calls compile. -3. Prefer wrappers, shims, and extraction scripts over invasive source edits. -4. Preserve LinuxCNC semantics for: +4. Prefer wrappers, shims, and extraction scripts over invasive source edits. +5. Preserve LinuxCNC semantics for: - G-code execution; - modal state; - parameter and variable behavior; - kinematics; - planner behavior; - machine and controller state visible to software. -5. Replace only the native runtime edges: +6. Replace only the native runtime edges: - file IO; - process model; - HAL runtime; - IPC; - GUI. -6. Frontend code must be implemented with web technology, not migrated from +7. Frontend code must be implemented with web technology, not migrated from native GUI code. ## Required Layout diff --git a/wasm-port/SKILL.md b/wasm-port/SKILL.md index f901971..5f8d9bd 100644 --- a/wasm-port/SKILL.md +++ b/wasm-port/SKILL.md @@ -9,6 +9,11 @@ LinuxCNC WASM Simulation Port This skill guides work inside `wasm-port/` for building a standalone LinuxCNC-based CNC simulation program. +The CNC simulation program must be derived primarily from the LinuxCNC source +program. Work in this port must strictly follow LinuxCNC behavior, structure, +and semantics, except where a documented standalone runtime boundary requires +an adapter. + It is intended for tasks involving: - source extraction from upstream LinuxCNC; @@ -33,12 +38,15 @@ Use this skill when the work involves any of the following: ## Core Principles 1. Upstream LinuxCNC is the semantic source of truth. -2. The standalone port is a separate program and separate workspace. -3. Reuse comes before rewrite. -4. Native runtime dependencies are replaced at the edges, not copied whole. -5. Machine state and controller-visible behavior are first-class compatibility +2. The CNC simulation program is primarily sourced from LinuxCNC source code; + port-specific code must adapt LinuxCNC to standalone native/WASM execution, + not replace LinuxCNC CNC behavior. +3. The standalone port is a separate program and separate workspace. +4. Reuse comes before rewrite. +5. Native runtime dependencies are replaced at the edges, not copied whole. +6. Machine state and controller-visible behavior are first-class compatibility targets, not optional nice-to-haves. -6. Do not continue building a project-authored CNC program once the porting +7. Do not continue building a project-authored CNC program once the porting harness runs; move behavior back to vendored LinuxCNC source functions. ## Source Reuse Priorities diff --git a/wasm-port/runtime/core/linuxcnc_wrap/linuxcnc_hal_adapter.cpp b/wasm-port/runtime/core/linuxcnc_wrap/linuxcnc_hal_adapter.cpp new file mode 100644 index 0000000..e90e7ba --- /dev/null +++ b/wasm-port/runtime/core/linuxcnc_wrap/linuxcnc_hal_adapter.cpp @@ -0,0 +1,109 @@ +#include "linuxcnc_hal_adapter.hh" + +#include +#include + +namespace { + +struct HalEntry { + hal_type_t type = HAL_TYPE_UNINITIALIZED; + hal_data_u value{}; + bool connected = true; +}; + +std::unordered_map &pins() +{ + static std::unordered_map values; + return values; +} + +std::unordered_map &signals() +{ + static std::unordered_map values; + return values; +} + +std::unordered_map ¶ms() +{ + static std::unordered_map values; + return values; +} + +std::unordered_map &values_for(standalone::HalValueKind kind) +{ + switch (kind) { + case standalone::HalValueKind::Pin: + return pins(); + case standalone::HalValueKind::Signal: + return signals(); + case standalone::HalValueKind::Param: + return params(); + } + return pins(); +} + +int lookup_hal_value(const char *name, std::unordered_map &values, + hal_type_t *type, hal_data_u **ptr, bool *connected) +{ + if (!name || !type || !ptr) { + return -1; + } + + auto it = values.find(name); + if (it == values.end()) { + return -1; + } + + *type = it->second.type; + *ptr = &it->second.value; + if (connected) { + *connected = it->second.connected; + } + return 0; +} + +} // namespace + +namespace standalone { + +void reset_hal_adapter() +{ + pins().clear(); + signals().clear(); + params().clear(); +} + +void set_hal_value(HalValueKind kind, const char *name, hal_type_t type, hal_data_u value, + bool connected) +{ + values_for(kind)[name] = HalEntry{type, value, connected}; +} + +} // namespace standalone + +int hal_init(const char *) +{ + return 1; +} + +int hal_ready(int) +{ + return 0; +} + +int hal_get_pin_value_by_name(const char *name, hal_type_t *type, hal_data_u **ptr, + bool *connected) +{ + return lookup_hal_value(name, pins(), type, ptr, connected); +} + +int hal_get_signal_value_by_name(const char *name, hal_type_t *type, hal_data_u **ptr, + bool *connected) +{ + return lookup_hal_value(name, signals(), type, ptr, connected); +} + +int hal_get_param_value_by_name(const char *name, hal_type_t *type, hal_data_u **ptr) +{ + return lookup_hal_value(name, params(), type, ptr, nullptr); +} diff --git a/wasm-port/runtime/core/linuxcnc_wrap/linuxcnc_hal_adapter.hh b/wasm-port/runtime/core/linuxcnc_wrap/linuxcnc_hal_adapter.hh new file mode 100644 index 0000000..74cb197 --- /dev/null +++ b/wasm-port/runtime/core/linuxcnc_wrap/linuxcnc_hal_adapter.hh @@ -0,0 +1,17 @@ +#pragma once + +#include "hal.h" + +namespace standalone { + +enum class HalValueKind { + Pin, + Signal, + Param, +}; + +void reset_hal_adapter(); +void set_hal_value(HalValueKind kind, const char *name, hal_type_t type, hal_data_u value, + bool connected = true); + +} // namespace standalone diff --git a/wasm-port/runtime/core/linuxcnc_wrap/linuxcnc_interp_edge_stubs.cpp b/wasm-port/runtime/core/linuxcnc_wrap/linuxcnc_interp_edge_stubs.cpp new file mode 100644 index 0000000..af71610 --- /dev/null +++ b/wasm-port/runtime/core/linuxcnc_wrap/linuxcnc_interp_edge_stubs.cpp @@ -0,0 +1,49 @@ +#include + +#define private public +#include "emc/rs274ngc/rs274ngc_interp.hh" +#undef private + +#include "emc/rs274ngc/rs274ngc_return.hh" +#include "interp_python.hh" +#include "pythonplugin/python_plugin.hh" + +PythonPlugin *python_plugin = nullptr; +int _task = 0; + +struct _inittab { + const char *name; + void *initfunc; +}; + +_inittab builtin_modules[] = {{nullptr, nullptr}}; + +InterpBase::~InterpBase() {} + +PythonPlugin *PythonPlugin::instantiate(struct _inittab *) +{ + static PythonPlugin standalone_plugin; + python_plugin = &standalone_plugin; + return python_plugin; +} + +std::string handle_pyerror() +{ + return {}; +} + +bool Interp::is_pycallable(setup_pointer, const char *, const char *) { return false; } +bool Interp::is_user_defined_g_code(int) { return false; } +bool Interp::is_any_m_code_remapped(block_pointer, setup_pointer) { return false; } +bool Interp::is_user_defined_m_code(block_pointer, setup_pointer, int) { return false; } +bool Interp::is_m_code_remappable(int) { return false; } +bool Interp::is_g_code_remappable(int) { return false; } +bool Interp::remap_in_progress(const char *) { return false; } +remap_pointer Interp::remapping(const char *) { return nullptr; } +remap_pointer Interp::remapping(const char, int) { return nullptr; } +int Interp::parse_remap(const char *, int) { return INTERP_ERROR; } +int Interp::convert_remapped_code(block_pointer, setup_pointer, int, char, int) { return INTERP_ERROR; } +int Interp::add_parameters(setup_pointer, block_pointer, char *) { return INTERP_ERROR; } +int Interp::pycall(setup_pointer, context_pointer, const char *, const char *, int) { return INTERP_ERROR; } +int Interp::py_execute(const char *, bool) { return INTERP_ERROR; } +int Interp::py_reload() { return INTERP_OK; } diff --git a/wasm-port/runtime/core/linuxcnc_wrap/linuxcnc_interp_minimal_harness.cpp b/wasm-port/runtime/core/linuxcnc_wrap/linuxcnc_interp_minimal_harness.cpp index cdc1336..cf0e4fc 100644 --- a/wasm-port/runtime/core/linuxcnc_wrap/linuxcnc_interp_minimal_harness.cpp +++ b/wasm-port/runtime/core/linuxcnc_wrap/linuxcnc_interp_minimal_harness.cpp @@ -9,11 +9,67 @@ #include #include "canon_event_sink.hh" +#include "linuxcnc_hal_adapter.hh" +#include "linuxcnc_tool_adapter.hh" namespace { +void seed_hal_values() +{ + standalone::reset_hal_adapter(); + + hal_data_u pin_bit{}; + pin_bit.b = true; + standalone::set_hal_value(standalone::HalValueKind::Pin, "standalone.pin-bit", HAL_BIT, + pin_bit); + + hal_data_u signal_float{}; + signal_float.f = 98.25; + standalone::set_hal_value(standalone::HalValueKind::Signal, "standalone.signal-float", + HAL_FLOAT, signal_float); + + hal_data_u param_s32{}; + param_s32.s = -17; + standalone::set_hal_value(standalone::HalValueKind::Param, "standalone.param-s32", HAL_S32, + param_s32); + + hal_data_u pin_u32{}; + pin_u32.u = 123456789u; + standalone::set_hal_value(standalone::HalValueKind::Pin, "standalone.pin-u32", HAL_U32, + pin_u32); + + hal_data_u signal_s64{}; + signal_s64.ls = -9000000000LL; + standalone::set_hal_value(standalone::HalValueKind::Signal, "standalone.signal-s64", HAL_S64, + signal_s64); + + hal_data_u param_u64{}; + param_u64.lu = 9000000000ULL; + standalone::set_hal_value(standalone::HalValueKind::Param, "standalone.param-u64", HAL_U64, + param_u64); + + hal_data_u disconnected{}; + disconnected.f = 12.5; + standalone::set_hal_value(standalone::HalValueKind::Pin, "standalone.disconnected-float", + HAL_FLOAT, disconnected, false); +} + +void seed_tool_values() +{ + standalone::reset_tool_adapter(); + + CANON_TOOL_TABLE tool = standalone::tool_entry_init(); + tool.toolno = 2; + tool.pocketno = 2; + tool.offset.tran.z = 1.25; + tool.diameter = 0.25; + standalone::set_tool_entry(2, tool); +} + void initialize_minimal_interp(Interp &interp) { + seed_hal_values(); + seed_tool_values(); interp._setup.length_units = CANON_UNITS_MM; interp._setup.distance_mode = DISTANCE_MODE::ABSOLUTE; interp._setup.ijk_distance_mode = DISTANCE_MODE::ABSOLUTE; @@ -23,6 +79,10 @@ void initialize_minimal_interp(Interp &interp) interp._setup.percent_flag = false; interp._setup.sequence_number = 0; interp._setup.parameter_occurrence = 0; + interp._setup.num_spindles = 1; + interp._setup.feature_set = FEATURE_INI_VARS | FEATURE_HAL_PIN_VARS; + interp._setup.parameters[5599] = 1.0; + interp.load_tool_table(); std::memcpy(interp._readers, Interp::default_readers, sizeof(Interp::default_readers)); } @@ -80,6 +140,51 @@ int main(int argc, char **argv) interp._setup.sequence_number = static_cast(idx + 1); const int execute_rc = interp.execute(program[idx].c_str()); std::cout << "execute_line_" << (idx + 1) << "=" << execute_rc << "\n"; + if (execute_rc > INTERP_MIN_ERROR) { + char error_buf[LINELEN] = {0}; + interp.error_text(execute_rc, error_buf, sizeof(error_buf)); + std::cout << "error_text=" << error_buf << "\n"; + } + } + + int file_open_rc = INTERP_FILE_NOT_OPEN; + int file_read_count = 0; + int file_execute_count = 0; + if (argc > 1) { + Interp file_interp; + initialize_minimal_interp(file_interp); + file_open_rc = file_interp.open(argv[1]); + if (file_open_rc == INTERP_OK) { + while (true) { + const int file_read_rc = file_interp.read(); + if (file_read_rc == INTERP_ENDFILE) { + std::cout << "file_read_eof=" << file_read_rc << "\n"; + break; + } + ++file_read_count; + std::cout << "file_read_" << file_read_count << "=" << file_read_rc << "\n"; + if ((file_read_rc != INTERP_OK) && (file_read_rc != INTERP_EXECUTE_FINISH)) { + break; + } + + const int file_execute_rc = file_interp.execute(); + ++file_execute_count; + std::cout << "file_execute_" << file_execute_count << "=" << file_execute_rc << "\n"; + if (file_execute_rc > INTERP_MIN_ERROR) { + char error_buf[LINELEN] = {0}; + file_interp.error_text(file_execute_rc, error_buf, sizeof(error_buf)); + std::cout << "file_error_text=" << error_buf << "\n"; + } + if ((file_execute_rc != INTERP_OK) && + (file_execute_rc != INTERP_EXECUTE_FINISH) && + (file_execute_rc != INTERP_EXIT)) { + break; + } + if (file_execute_rc == INTERP_EXIT) { + break; + } + } + } } block block{}; @@ -90,6 +195,9 @@ int main(int argc, char **argv) } std::cout << "read_text=" << read_text_rc << "\n"; + std::cout << "file_open=" << file_open_rc << "\n"; + std::cout << "file_read_count=" << file_read_count << "\n"; + std::cout << "file_execute_count=" << file_execute_count << "\n"; std::cout << "raw_line=" << raw_line << "\n"; std::cout << "cooked_line=" << cooked_line << "\n"; std::cout << "line_length=" << length << "\n"; diff --git a/wasm-port/runtime/core/linuxcnc_wrap/linuxcnc_interp_minimal_runtime.cpp b/wasm-port/runtime/core/linuxcnc_wrap/linuxcnc_interp_minimal_runtime.cpp index d973f9e..a50190c 100644 --- a/wasm-port/runtime/core/linuxcnc_wrap/linuxcnc_interp_minimal_runtime.cpp +++ b/wasm-port/runtime/core/linuxcnc_wrap/linuxcnc_interp_minimal_runtime.cpp @@ -12,8 +12,7 @@ #include "emc/rs274ngc/rs274ngc_return.hh" #include "canon_event_sink.hh" - -PythonPlugin *python_plugin = nullptr; +#include "linuxcnc_tool_adapter.hh" namespace standalone { @@ -71,13 +70,45 @@ void STOP_SPEED_FEED_SYNCH() {} void RIGID_TAP(int, double, double, double, double) {} void STRAIGHT_PROBE(int, double, double, double, double, double, double, double, double, double, unsigned char) {} void STOP() {} -void DWELL(double) {} -void SET_SPINDLE_MODE(int, double) {} +void DWELL(double seconds) +{ + std::ostringstream oss; + oss << "DWELL seconds=" << seconds; + standalone::push_canon_event(oss.str()); +} +void SET_SPINDLE_MODE(int spindle, double css_max) +{ + std::ostringstream oss; + oss << "SET_SPINDLE_MODE spindle=" << spindle << " css_max=" << css_max; + standalone::push_canon_event(oss.str()); +} void SPINDLE_RETRACT_TRAVERSE() {} -void START_SPINDLE_CLOCKWISE(int, int) {} -void START_SPINDLE_COUNTERCLOCKWISE(int, int) {} -void SET_SPINDLE_SPEED(int, double) {} -void STOP_SPINDLE_TURNING(int) {} +void START_SPINDLE_CLOCKWISE(int spindle, int wait_for_at_speed) +{ + std::ostringstream oss; + oss << "START_SPINDLE_CLOCKWISE spindle=" << spindle + << " wait_for_at_speed=" << wait_for_at_speed; + standalone::push_canon_event(oss.str()); +} +void START_SPINDLE_COUNTERCLOCKWISE(int spindle, int wait_for_at_speed) +{ + std::ostringstream oss; + oss << "START_SPINDLE_COUNTERCLOCKWISE spindle=" << spindle + << " wait_for_at_speed=" << wait_for_at_speed; + standalone::push_canon_event(oss.str()); +} +void SET_SPINDLE_SPEED(int spindle, double speed) +{ + std::ostringstream oss; + oss << "SET_SPINDLE_SPEED spindle=" << spindle << " speed=" << speed; + standalone::push_canon_event(oss.str()); +} +void STOP_SPINDLE_TURNING(int spindle) +{ + std::ostringstream oss; + oss << "STOP_SPINDLE_TURNING spindle=" << spindle; + standalone::push_canon_event(oss.str()); +} void SPINDLE_RETRACT() {} void ORIENT_SPINDLE(int, double, int) {} void WAIT_SPINDLE_ORIENT_COMPLETE(int, double) {} @@ -85,10 +116,40 @@ void LOCK_SPINDLE_Z() {} void USE_SPINDLE_FORCE() {} void USE_NO_SPINDLE_FORCE() {} void SET_TOOL_TABLE_ENTRY(int, int, const EmcPose &, double, double, double, int) {} -void USE_TOOL_LENGTH_OFFSET(const EmcPose &) {} -void CHANGE_TOOL() {} -void SELECT_TOOL(int) {} -void CHANGE_TOOL_NUMBER(int) {} +void USE_TOOL_LENGTH_OFFSET(const EmcPose &offset) +{ + std::ostringstream oss; + oss << "USE_TOOL_LENGTH_OFFSET" + << " x=" << offset.tran.x + << " y=" << offset.tran.y + << " z=" << offset.tran.z + << " a=" << offset.a + << " b=" << offset.b + << " c=" << offset.c + << " u=" << offset.u + << " v=" << offset.v + << " w=" << offset.w; + standalone::push_canon_event(oss.str()); +} +void CHANGE_TOOL() +{ + standalone::change_selected_tool(); + standalone::push_canon_event("CHANGE_TOOL"); +} +void SELECT_TOOL(int tool) +{ + standalone::select_tool(tool); + std::ostringstream oss; + oss << "SELECT_TOOL tool=" << tool; + standalone::push_canon_event(oss.str()); +} +void CHANGE_TOOL_NUMBER(int pocket) +{ + standalone::change_tool_number(pocket); + std::ostringstream oss; + oss << "CHANGE_TOOL_NUMBER pocket=" << pocket; + standalone::push_canon_event(oss.str()); +} void RELOAD_TOOLDATA(void) {} void CLAMP_AXIS(CANON_AXIS) {} void DISABLE_ADAPTIVE_FEED() {} @@ -99,10 +160,10 @@ void DISABLE_SPEED_OVERRIDE(int) {} void ENABLE_SPEED_OVERRIDE(int) {} void DISABLE_FEED_HOLD() {} void ENABLE_FEED_HOLD() {} -void FLOOD_OFF() {} -void FLOOD_ON() {} -void MIST_OFF() {} -void MIST_ON() {} +void FLOOD_OFF() { standalone::push_canon_event("FLOOD_OFF"); } +void FLOOD_ON() { standalone::push_canon_event("FLOOD_ON"); } +void MIST_OFF() { standalone::push_canon_event("MIST_OFF"); } +void MIST_ON() { standalone::push_canon_event("MIST_ON"); } void PALLET_SHUTTLE() {} void TURN_PROBE_OFF() {} void TURN_PROBE_ON() {} @@ -144,7 +205,8 @@ void CANON_ERROR(const char *fmt, ...) double GET_EXTERNAL_FEED_RATE() { return 0.0; } int GET_EXTERNAL_FLOOD() { return 0; } -double GET_EXTERNAL_LENGTH_UNITS() { return CANON_UNITS_MM; } +CANON_UNITS GET_EXTERNAL_LENGTH_UNIT_TYPE() { return CANON_UNITS_MM; } +double GET_EXTERNAL_LENGTH_UNITS() { return 1.0; } double GET_EXTERNAL_ANGLE_UNITS() { return 1.0; } int GET_EXTERNAL_MIST() { return 0; } CANON_MOTION_MODE GET_EXTERNAL_MOTION_CONTROL_MODE() { return CANON_EXACT_STOP; } @@ -198,7 +260,12 @@ double GET_EXTERNAL_TOOL_LENGTH_VOFFSET() { return 0.0; } double GET_EXTERNAL_TOOL_LENGTH_WOFFSET() { return 0.0; } int GET_EXTERNAL_TOOL_SLOT() { return 0; } int GET_EXTERNAL_SELECTED_TOOL_SLOT() { return -1; } -CANON_TOOL_TABLE GET_EXTERNAL_TOOL_TABLE(int) { return tooldata_entry_init(); } +CANON_TOOL_TABLE GET_EXTERNAL_TOOL_TABLE(int index) +{ + CANON_TOOL_TABLE tool = standalone::tool_entry_init(); + standalone::get_tool_entry(&tool, index); + return tool; +} int GET_EXTERNAL_TC_FAULT() { return 0; } int GET_EXTERNAL_TC_REASON() { return 0; } double GET_EXTERNAL_TRAVERSE_RATE() { return 0.0; } @@ -288,277 +355,3 @@ void SET_FEED_RATE(double rate) oss << "SET_FEED_RATE rate=" << rate; standalone::push_canon_event(oss.str()); } - -InterpBase::~InterpBase() {} - -Interp::Interp() - : log_file(stderr), - _setup{} -{ - _setup.init_once = 1; - memset(_readers, 0, sizeof(_readers)); -} - -Interp::~Interp() { - if (log_file && log_file != stderr) { - fclose(log_file); - } - log_file = nullptr; -} - -void Interp::doLog(unsigned int, const char *, int, const char *fmt, ...) -{ - va_list ap; - va_start(ap, fmt); - vfprintf(stderr, fmt, ap); - va_end(ap); -} - -const char *Interp::interp_status(int status) -{ - static char statustext[64]; - snprintf(statustext, sizeof(statustext), "%d", status); - return statustext; -} - -const char *Interp::getSavedError() -{ - return ""; -} - -int Interp::setSavedError(const char *) -{ - return INTERP_OK; -} - -void Interp::setError(const char *fmt, ...) -{ - va_list ap; - va_start(ap, fmt); - vfprintf(stderr, fmt, ap); - fputc('\n', stderr); - va_end(ap); -} - -int Interp::unwind_call(int status, const char *, int, const char *) -{ - return status; -} - -int Interp::close() { return INTERP_OK; } -int Interp::execute(const char *command) -{ - int status = read(command); - if (status != INTERP_OK) { - if (status > INTERP_MIN_ERROR) { - unwind_call(status, __FILE__, __LINE__, __FUNCTION__); - } - return status; - } - - if (_setup.line_length != 0) { - status = execute_block(&EXECUTING_BLOCK(_setup), &_setup); - if (status > INTERP_MIN_ERROR) { - unwind_call(status, __FILE__, __LINE__, __FUNCTION__); - } - return status; - } - return INTERP_OK; -} - -int Interp::execute() { return execute(nullptr); } - -int Interp::execute(const char *command, int line_number) -{ - if (command && line_number) { - _setup.sequence_number = line_number; - } - int status = execute(command); - if ((_setup.call_level == 0) && - (status == INTERP_EXECUTE_FINISH) && - (_setup.mdi_interrupt)) { - _setup.mdi_interrupt = false; - } - return status; -} -int Interp::exit() { return INTERP_OK; } -int Interp::init() { return INTERP_OK; } -void Interp::set_loop_on_main_m99(bool state) { _setup.loop_on_main_m99 = state; } -int Interp::open(const char *) { return INTERP_ERROR; } - -int Interp::read_inputs(setup_pointer) -{ - return INTERP_OK; -} - -int Interp::_read(const char *command) -{ - int read_status = INTERP_OK; - block_pointer eblock = &EXECUTING_BLOCK(_setup); - - if ((_setup.call_state > CS_NORMAL) && - (eblock->call_type != CT_NGC_OWORD_SUB) && - (eblock->call_type != CT_NGC_M98_SUB) && - (eblock->call_type != CT_NONE) && - ((eblock->o_type == O_call) || - (eblock->o_type == M_98) || - (eblock->o_type == O_return) || - (eblock->o_type == O_endsub) || - (eblock->o_type == M_99))) { - _setup.line_length = 0; - _setup.linetext[0] = 0; - return INTERP_OK; - } - - _setup.call_state = CS_NORMAL; - if (read_inputs(&_setup) != INTERP_OK) { - return INTERP_ERROR; - } - - if ((command == nullptr) && (_setup.file_pointer == nullptr)) { - return INTERP_FILE_NOT_OPEN; - } - - _setup.parameters[5420] = _setup.current_x; - _setup.parameters[5421] = _setup.current_y; - _setup.parameters[5422] = _setup.current_z; - _setup.parameters[5423] = _setup.AA_current; - _setup.parameters[5424] = _setup.BB_current; - _setup.parameters[5425] = _setup.CC_current; - _setup.parameters[5426] = _setup.u_current; - _setup.parameters[5427] = _setup.v_current; - _setup.parameters[5428] = _setup.w_current; - - if (_setup.file_pointer) { - EXECUTING_BLOCK(_setup).offset = ftell(_setup.file_pointer); - } - - read_status = read_text(command, _setup.file_pointer, _setup.linetext, - _setup.blocktext, &_setup.line_length); - - if ((read_status == INTERP_EXECUTE_FINISH) || (read_status == INTERP_OK)) { - if (_setup.line_length != 0) { - if (parse_line(_setup.blocktext, &(EXECUTING_BLOCK(_setup)), &_setup) != INTERP_OK) { - return INTERP_ERROR; - } - } else { - if (EXECUTING_BLOCK(_setup).o_type != O_none) { - EXECUTING_BLOCK(_setup).o_type = 0; - } - } - } else if (read_status == INTERP_ENDFILE) { - if (_setup.skipping_o != nullptr) { - return INTERP_ERROR; - } - } else { - return read_status; - } - - return read_status; -} - -int Interp::read(const char *command) -{ - int status = _read(command); - if (status > INTERP_MIN_ERROR) { - unwind_call(status, __FILE__, __LINE__, __FUNCTION__); - } - return status; -} - -int Interp::read() -{ - return read(nullptr); -} - -int Interp::reset() { return INTERP_OK; } -int Interp::synch() { return INTERP_OK; } -void Interp::active_g_codes(int *codes) { std::memcpy(codes, _setup.active_g_codes, sizeof(_setup.active_g_codes)); } -void Interp::active_m_codes(int *codes) { std::memcpy(codes, _setup.active_m_codes, sizeof(_setup.active_m_codes)); } -void Interp::active_settings(double *settings) { std::memcpy(settings, _setup.active_settings, sizeof(_setup.active_settings)); } -int Interp::active_modes(int *, int *, double *, StateTag const &) { return INTERP_ERROR; } -void Interp::print_state_tag(StateTag const &) {} -char *Interp::error_text(int, char *buf, size_t max_size) -{ - if (max_size) buf[0] = '\0'; - return buf; -} -char *Interp::file_name(char *buf, size_t max_size) -{ - if (max_size) { - std::strncpy(buf, _setup.filename, max_size - 1); - buf[max_size - 1] = '\0'; - } - return buf; -} -size_t Interp::line_length() { return static_cast(_setup.line_length); } -char *Interp::line_text(char *buf, size_t max_size) -{ - if (max_size) { - std::strncpy(buf, _setup.linetext, max_size - 1); - buf[max_size - 1] = '\0'; - } - return buf; -} -int Interp::sequence_number() { return _setup.sequence_number; } -char *Interp::stack_name(int idx, char *buf, size_t max_size) -{ - if (!max_size) return buf; - if (idx < 0 || idx >= STACK_LEN) { - buf[0] = '\0'; - return buf; - } - std::strncpy(buf, _setup.stack[idx], max_size - 1); - buf[max_size - 1] = '\0'; - return buf; -} -int Interp::ini_load(const char *) { return INTERP_OK; } -int Interp::on_abort(int, const char *) { return INTERP_OK; } -void Interp::set_loglevel(int level) { _setup.loggingLevel = level; } - -int Interp::find_remappings(block_pointer, setup_pointer) { return 0; } - -int Interp::load_tool_table() { return INTERP_OK; } -int Interp::init_tool_parameters() { return INTERP_OK; } -int Interp::default_tool_parameters() { return INTERP_OK; } -int Interp::set_tool_parameters() { return INTERP_OK; } -bool Interp::is_pycallable(setup_pointer, const char *, const char *) { return false; } -bool Interp::is_user_defined_g_code(int) { return false; } -bool Interp::is_any_m_code_remapped(block_pointer, setup_pointer) { return false; } -bool Interp::is_user_defined_m_code(block_pointer, setup_pointer, int) { return false; } -void Interp::loop_to_beginning(setup_pointer) {} -int Interp::convert_control_functions(block_pointer, setup_pointer) { return INTERP_OK; } -int Interp::convert_remapped_code(block_pointer, setup_pointer, int, char, int) { return INTERP_ERROR; } -int Interp::py_execute(const char *, bool) { return INTERP_OK; } -int Interp::py_reload() { return INTERP_OK; } - -const char *o_ops[] = { - "O_none", "O_sub", "O_endsub", "O_call", "O_do", "O_while", "O_if", - "O_elseif", "O_else", "O_endif", "O_break", "O_continue", - "O_endwhile", "O_return", "O_repeat", "O_endrepeat", "M_98", "M_99", "O_" -}; - -int Interp::read_named_parameter(char *, int *, double *double_ptr, double *, bool check_exists) -{ - if (check_exists) { - *double_ptr = 0.0; - } - return INTERP_ERROR; -} - -int Interp::find_named_param(const char *, int *status, double *value) -{ - *status = 0; - *value = 0.0; - return INTERP_OK; -} - -int Interp::store_named_param(setup_pointer, const char *, double, int) -{ - return INTERP_ERROR; -} - -int Interp::add_named_param(const char *, int) -{ - return INTERP_OK; -} diff --git a/wasm-port/runtime/core/linuxcnc_wrap/linuxcnc_namedparam_harness.cpp b/wasm-port/runtime/core/linuxcnc_wrap/linuxcnc_namedparam_harness.cpp index 7a045a6..1f228e0 100644 --- a/wasm-port/runtime/core/linuxcnc_wrap/linuxcnc_namedparam_harness.cpp +++ b/wasm-port/runtime/core/linuxcnc_wrap/linuxcnc_namedparam_harness.cpp @@ -4,338 +4,104 @@ #include #include -#include -#include "config.h" -#include "emc/ini/inifile.hh" +#include "linuxcnc_hal_adapter.hh" namespace { -enum predefined_named_parameters { - NP_LINE, - NP_MOTION_MODE, - NP_PLANE, - NP_CCOMP, - NP_METRIC, - NP_IMPERIAL, - NP_ABSOLUTE, - NP_INCREMENTAL, - NP_INVERSE_TIME, - NP_UNITS_PER_MINUTE, - NP_UNITS_PER_REV, - NP_COORD_SYSTEM, - NP_TOOL_OFFSET, - NP_RETRACT_R_PLANE, - NP_RETRACT_OLD_Z, - NP_SPINDLE_RPM_MODE, - NP_SPINDLE_CSS_MODE, - NP_IJK_ABSOLUTE_MODE, - NP_LATHE_DIAMETER_MODE, - NP_LATHE_RADIUS_MODE, - NP_SPINDLE_ON, - NP_SPINDLE_CW, - NP_MIST, - NP_FLOOD, - NP_SPEED_OVERRIDE, - NP_FEED_OVERRIDE, - NP_ADAPTIVE_FEED, - NP_FEED_HOLD, - NP_FEED, - NP_RPM, - NP_CURRENT_TOOL, - NP_SELECTED_POCKET, - NP_CURRENT_POCKET, - NP_X, - NP_Y, - NP_Z, - NP_A, - NP_B, - NP_C, - NP_U, - NP_V, - NP_W, - NP_ABS_X, - NP_ABS_Y, - NP_ABS_Z, - NP_ABS_A, - NP_ABS_B, - NP_ABS_C, - NP_VALUE, - NP_CALL_LEVEL, - NP_REMAP_LEVEL, - NP_SELECTED_TOOL, - NP_VALUE_RETURNED, - NP_TASK, -}; +void seed_hal_values() +{ + standalone::reset_hal_adapter(); -struct NamedParamRuntime { - setup state; + hal_data_u pin_bit{}; + pin_bit.b = true; + standalone::set_hal_value(standalone::HalValueKind::Pin, "standalone.pin-bit", HAL_BIT, + pin_bit); - int fetch_ini_param(const char *nameBuf, int *status, double *value) { - *status = 0; - const int n = static_cast(strlen(nameBuf)); - if (n < 8) { - return INTERP_OK; - } + hal_data_u signal_float{}; + signal_float.f = 98.25; + standalone::set_hal_value(standalone::HalValueKind::Signal, "standalone.signal-float", + HAL_FLOAT, signal_float); - std::string sect = nameBuf + 5; - for (auto &c : sect) { - c = static_cast(toupper(c)); - } - const size_t i = sect.find(']'); - if (i == std::string::npos) { - return INTERP_ERROR; - } - std::string var = sect.substr(i + 1); - sect.erase(i); + hal_data_u param_s32{}; + param_s32.s = -17; + standalone::set_hal_value(standalone::HalValueKind::Param, "standalone.param-s32", HAL_S32, + param_s32); - const char *iniFileName = getenv("INI_FILE_NAME"); - if (!iniFileName) { - return INTERP_OK; - } - linuxcnc::IniFile inifile(iniFileName); - if (!inifile) { - return INTERP_OK; - } + hal_data_u pin_u32{}; + pin_u32.u = 123456789u; + standalone::set_hal_value(standalone::HalValueKind::Pin, "standalone.pin-u32", HAL_U32, + pin_u32); - if (auto inival = inifile.findReal(var, sect)) { - *value = *inival; - *status = 1; - } - return INTERP_OK; - } + hal_data_u signal_s64{}; + signal_s64.ls = -9000000000LL; + standalone::set_hal_value(standalone::HalValueKind::Signal, "standalone.signal-s64", HAL_S64, + signal_s64); - int lookup_named_param(const char *nameBuf, double index, double *value) { - const int cmd = round_to_int(index); - switch (cmd) { - case NP_LINE: - *value = state.sequence_number; - break; - case NP_MOTION_MODE: - *value = state.motion_mode; - break; - case NP_METRIC: - *value = (state.length_units == CANON_UNITS_MM); - break; - case NP_IMPERIAL: - *value = (state.length_units == CANON_UNITS_INCHES); - break; - case NP_ABSOLUTE: - *value = (state.distance_mode == DISTANCE_MODE::ABSOLUTE); - break; - case NP_INCREMENTAL: - *value = (state.distance_mode == DISTANCE_MODE::INCREMENTAL); - break; - case NP_FEED: - *value = state.feed_rate; - break; - case NP_RPM: - *value = state.speed[0]; - break; - case NP_X: - *value = state.current_x; - break; - case NP_Y: - *value = state.current_y; - break; - case NP_Z: - *value = state.current_z; - break; - case NP_CURRENT_TOOL: - *value = state.parameters[interp_param_global::TOOL_NUMBER]; - break; - case NP_CALL_LEVEL: - *value = state.call_level; - break; - default: - return INTERP_ERROR; - } - return INTERP_OK; - } + hal_data_u param_u64{}; + param_u64.lu = 9000000000ULL; + standalone::set_hal_value(standalone::HalValueKind::Param, "standalone.param-u64", HAL_U64, + param_u64); - int find_named_param(const char *nameBuf, int *status, double *value) { - const int level = (nameBuf[0] == '_') ? 0 : state.call_level; - context_pointer frame = &state.sub_context[level]; - *status = 0; + hal_data_u disconnected{}; + disconnected.f = 12.5; + standalone::set_hal_value(standalone::HalValueKind::Pin, "standalone.disconnected-float", + HAL_FLOAT, disconnected, false); +} - auto pi = frame->named_params.find(nameBuf); - if (pi == frame->named_params.end()) { - int exists = 0; - double inivalue = 0.0; - if ((state.feature_set & FEATURE_INI_VARS) && (strncasecmp(nameBuf, "_ini[", 5) == 0)) { - fetch_ini_param(nameBuf, &exists, &inivalue); - if (exists) { - *value = inivalue; - *status = 1; - parameter_value param; - param.value = inivalue; - param.attr = PA_GLOBAL | PA_READONLY | PA_FROM_INI; - state.sub_context[0].named_params[strstore(nameBuf)] = param; - return INTERP_OK; - } - } - *value = 0.0; - *status = 0; - } else { - parameter_pointer pv = &pi->second; - if (pv->attr & PA_USE_LOOKUP) { - if (lookup_named_param(nameBuf, pv->value, value) != INTERP_OK) { - return INTERP_ERROR; - } - *status = 1; - } else { - *value = pv->value; - *status = 1; - } - } - return INTERP_OK; - } - - int store_named_param(const char *nameBuf, double value, bool override_readonly) { - const int level = (nameBuf[0] == '_') ? 0 : state.call_level; - context_pointer frame = &state.sub_context[level]; - auto pi = frame->named_params.find(nameBuf); - if (pi == frame->named_params.end()) { - return INTERP_ERROR; - } - parameter_pointer pv = &pi->second; - if ((pv->attr & PA_READONLY) && !override_readonly) { - return INTERP_ERROR; - } - pv->value = value; - pv->attr &= ~PA_UNSET; - return INTERP_OK; - } - - int add_named_param(const char *nameBuf, int attr) { - int findStatus = 0; - double value = 0.0; - find_named_param(nameBuf, &findStatus, &value); - if (findStatus) { - return INTERP_OK; - } - - int level = 0; - if (nameBuf[0] != '_') { - level = state.call_level; - } else { - level = 0; - attr |= PA_GLOBAL; - } - attr |= PA_UNSET; - - parameter_value param; - param.value = 0.0; - param.attr = attr; - state.sub_context[level].named_params[strstore(nameBuf)] = param; - return INTERP_OK; - } - - int init_readonly_param(const char *nameBuf, double value, int attr) { - if (add_named_param(nameBuf, PA_READONLY | attr) != INTERP_OK) { - return INTERP_ERROR; - } - if (store_named_param(nameBuf, value, true) != INTERP_OK) { - return INTERP_ERROR; - } - return INTERP_OK; - } - - double inicheck() { - const char *filename = getenv("INI_FILE_NAME"); - if (!filename) { - return -1.0; - } - linuxcnc::IniFile inifile(filename); - if (!inifile) { - return -1.0; - } - if (auto inistring = inifile.findString("LINEAR_UNITS", "TRAJ")) { - if ((strcasecmp("mm", inistring->c_str()) == 0) || - (strcasecmp("metric", inistring->c_str()) == 0)) { - return 1.0; - } - return 0.0; - } - return -1.0; - } - - int init_named_parameters() { - const char *pkgversion = PACKAGE_VERSION; - const char *version_major = "_vmajor"; - const char *version_minor = "_vminor"; - const char *metric_machine = "_metric_machine"; - double vmajor = 0.0; - double vminor = 0.0; - double munits = 1.0; - sscanf(pkgversion, "%lf%lf", &vmajor, &vminor); - - if (init_readonly_param(version_major, vmajor, 0) != INTERP_OK) return INTERP_ERROR; - if (init_readonly_param(version_minor, vminor, 0) != INTERP_OK) return INTERP_ERROR; - - munits = inicheck(); - if (init_readonly_param(metric_machine, munits, 0) != INTERP_OK) return INTERP_ERROR; - - if (init_readonly_param("_line", NP_LINE, PA_USE_LOOKUP) != INTERP_OK) return INTERP_ERROR; - if (init_readonly_param("_motion_mode", NP_MOTION_MODE, PA_USE_LOOKUP) != INTERP_OK) return INTERP_ERROR; - if (init_readonly_param("_metric", NP_METRIC, PA_USE_LOOKUP) != INTERP_OK) return INTERP_ERROR; - if (init_readonly_param("_imperial", NP_IMPERIAL, PA_USE_LOOKUP) != INTERP_OK) return INTERP_ERROR; - if (init_readonly_param("_absolute", NP_ABSOLUTE, PA_USE_LOOKUP) != INTERP_OK) return INTERP_ERROR; - if (init_readonly_param("_incremental", NP_INCREMENTAL, PA_USE_LOOKUP) != INTERP_OK) return INTERP_ERROR; - if (init_readonly_param("_feed", NP_FEED, PA_USE_LOOKUP) != INTERP_OK) return INTERP_ERROR; - if (init_readonly_param("_rpm", NP_RPM, PA_USE_LOOKUP) != INTERP_OK) return INTERP_ERROR; - if (init_readonly_param("_x", NP_X, PA_USE_LOOKUP) != INTERP_OK) return INTERP_ERROR; - if (init_readonly_param("_y", NP_Y, PA_USE_LOOKUP) != INTERP_OK) return INTERP_ERROR; - if (init_readonly_param("_z", NP_Z, PA_USE_LOOKUP) != INTERP_OK) return INTERP_ERROR; - if (init_readonly_param("_current_tool", NP_CURRENT_TOOL, PA_USE_LOOKUP) != INTERP_OK) return INTERP_ERROR; - if (init_readonly_param("_call_level", NP_CALL_LEVEL, PA_USE_LOOKUP) != INTERP_OK) return INTERP_ERROR; - - return INTERP_OK; - } -}; - -void print_named_value(NamedParamRuntime &runtime, const char *name) { +void print_named_value(Interp &interp, const char *name) +{ int status = 0; double value = 0.0; - const int rc = runtime.find_named_param(name, &status, &value); + const int rc = interp.find_named_param(name, &status, &value); std::cout << name << ": rc=" << rc << " found=" << status << " value=" << value << "\n"; } } // namespace -int main(int argc, char **argv) { +int main(int argc, char **argv) +{ if (argc == 2) { setenv("INI_FILE_NAME", argv[1], 1); } - NamedParamRuntime runtime; - runtime.state.feature_set = FEATURE_INI_VARS; - runtime.state.length_units = CANON_UNITS_MM; - runtime.state.distance_mode = DISTANCE_MODE::ABSOLUTE; - runtime.state.motion_mode = G_1; - runtime.state.feed_rate = 123.45; - runtime.state.speed[0] = 678.9; - runtime.state.current_x = 1.25; - runtime.state.current_y = 2.5; - runtime.state.current_z = 3.75; - runtime.state.parameters[interp_param_global::TOOL_NUMBER] = 12.0; + Interp interp; + seed_hal_values(); + interp._setup.feature_set = FEATURE_INI_VARS | FEATURE_HAL_PIN_VARS; + interp._setup.length_units = CANON_UNITS_MM; + interp._setup.distance_mode = DISTANCE_MODE::ABSOLUTE; + interp._setup.motion_mode = G_1; + interp._setup.feed_rate = 123.45; + interp._setup.speed[0] = 678.9; + interp._setup.current_x = 1.25; + interp._setup.current_y = 2.5; + interp._setup.current_z = 3.75; + interp._setup.parameters[interp_param_global::TOOL_NUMBER] = 12.0; - const int rc = runtime.init_named_parameters(); + const int rc = interp.init_named_parameters(); std::cout << "init_named_parameters=" << rc << "\n"; - std::cout << "global_named_count=" << runtime.state.sub_context[0].named_params.size() << "\n"; + std::cout << "global_named_count=" << interp._setup.sub_context[0].named_params.size() << "\n"; std::cout << "required_parameter_first=" << interp_param_global::G28_X << "\n"; std::cout << "readonly_tool_number_index=" << interp_param_global::TOOL_NUMBER << "\n"; - print_named_value(runtime, "_vmajor"); - print_named_value(runtime, "_vminor"); - print_named_value(runtime, "_metric_machine"); - print_named_value(runtime, "_motion_mode"); - print_named_value(runtime, "_metric"); - print_named_value(runtime, "_feed"); - print_named_value(runtime, "_rpm"); - print_named_value(runtime, "_x"); - print_named_value(runtime, "_current_tool"); - print_named_value(runtime, "_ini[traj]max_linear_velocity"); + print_named_value(interp, "_vmajor"); + print_named_value(interp, "_vminor"); + print_named_value(interp, "_metric_machine"); + print_named_value(interp, "_motion_mode"); + print_named_value(interp, "_metric"); + print_named_value(interp, "_feed"); + print_named_value(interp, "_rpm"); + print_named_value(interp, "_x"); + print_named_value(interp, "_current_tool"); + print_named_value(interp, "_ini[traj]max_linear_velocity"); + print_named_value(interp, "_hal[standalone.pin-bit]"); + print_named_value(interp, "_hal[standalone.signal-float]"); + print_named_value(interp, "_hal[standalone.param-s32]"); + print_named_value(interp, "_hal[standalone.pin-u32]"); + print_named_value(interp, "_hal[standalone.signal-s64]"); + print_named_value(interp, "_hal[standalone.param-u64]"); + print_named_value(interp, "_hal[standalone.disconnected-float]"); + print_named_value(interp, "_hal[standalone.missing]"); return rc == INTERP_OK ? 0 : 1; } diff --git a/wasm-port/runtime/core/linuxcnc_wrap/linuxcnc_runtime_state_stubs.cpp b/wasm-port/runtime/core/linuxcnc_wrap/linuxcnc_runtime_state_stubs.cpp index 0ca2cc2..9207e74 100644 --- a/wasm-port/runtime/core/linuxcnc_wrap/linuxcnc_runtime_state_stubs.cpp +++ b/wasm-port/runtime/core/linuxcnc_wrap/linuxcnc_runtime_state_stubs.cpp @@ -5,8 +5,7 @@ #include #include "emc/rs274ngc/interp_internal.hh" - -struct pycontext_impl {}; +#include "interp_python.hh" pycontext::pycontext() : impl(new pycontext_impl) {} pycontext::~pycontext() { delete impl; } @@ -20,6 +19,7 @@ pycontext &pycontext::operator=(const pycontext &other) { return *this; } +#ifndef LINUXCNC_STANDALONE_USE_RS274_PRE_STATE const char *strstore(const char *s) { static std::unordered_set stringtable; @@ -45,6 +45,7 @@ void context_struct::clear() { new (this) context_struct(); } +#endif setup::setup() : AA_axis_offset(0.0), diff --git a/wasm-port/runtime/core/linuxcnc_wrap/linuxcnc_tool_adapter.cpp b/wasm-port/runtime/core/linuxcnc_wrap/linuxcnc_tool_adapter.cpp new file mode 100644 index 0000000..9f2bdbe --- /dev/null +++ b/wasm-port/runtime/core/linuxcnc_wrap/linuxcnc_tool_adapter.cpp @@ -0,0 +1,101 @@ +#include "linuxcnc_tool_adapter.hh" + +#include + +namespace { + +std::array &tool_table() +{ + static std::array tools{}; + return tools; +} + +int &selected_tool_index() +{ + static int index = -1; + return index; +} + +CANON_TOOL_TABLE empty_tool() +{ + CANON_TOOL_TABLE tool{}; + tool.toolno = 0; + tool.pocketno = 0; + return tool; +} + +} // namespace + +namespace standalone { + +void reset_tool_adapter() +{ + selected_tool_index() = -1; + auto &tools = tool_table(); + for (int index = 0; index < CANON_POCKETS_MAX; ++index) { + tools[index] = empty_tool(); + tools[index].pocketno = index; + } + tools[0].pocketno = 0; +} + +void set_tool_entry(int index, const CANON_TOOL_TABLE &tool) +{ + if ((index < 0) || (index >= CANON_POCKETS_MAX)) { + return; + } + tool_table()[index] = tool; +} + +CANON_TOOL_TABLE tool_entry_init() +{ + return empty_tool(); +} + +int find_tool_index_for_tool(int toolno) +{ + if (toolno == 0) { + return 0; + } + + const auto &tools = tool_table(); + for (int index = 0; index < CANON_POCKETS_MAX; ++index) { + if (tools[index].toolno == toolno) { + return index; + } + } + return -1; +} + +int get_tool_entry(CANON_TOOL_TABLE *tool, int index) +{ + if ((tool == nullptr) || (index < 0) || (index >= CANON_POCKETS_MAX)) { + return -1; + } + *tool = tool_table()[index]; + return 0; +} + +void select_tool(int toolno) +{ + selected_tool_index() = find_tool_index_for_tool(toolno); +} + +void change_tool_number(int index) +{ + if ((index < 0) || (index >= CANON_POCKETS_MAX)) { + return; + } + + auto &tools = tool_table(); + CANON_TOOL_TABLE spindle_tool = tools[index]; + spindle_tool.pocketno = 0; + tools[0] = spindle_tool; +} + +void change_selected_tool() +{ + change_tool_number(selected_tool_index()); +} + +} // namespace standalone diff --git a/wasm-port/runtime/core/linuxcnc_wrap/linuxcnc_tool_adapter.hh b/wasm-port/runtime/core/linuxcnc_wrap/linuxcnc_tool_adapter.hh new file mode 100644 index 0000000..9c89d92 --- /dev/null +++ b/wasm-port/runtime/core/linuxcnc_wrap/linuxcnc_tool_adapter.hh @@ -0,0 +1,16 @@ +#pragma once + +#include "emc/nml_intf/emctool.h" + +namespace standalone { + +void reset_tool_adapter(); +void set_tool_entry(int index, const CANON_TOOL_TABLE &tool); +CANON_TOOL_TABLE tool_entry_init(); +int find_tool_index_for_tool(int toolno); +int get_tool_entry(CANON_TOOL_TABLE *tool, int index); +void select_tool(int toolno); +void change_selected_tool(); +void change_tool_number(int index); + +} // namespace standalone diff --git a/wasm-port/runtime/core/shims/boost/python/dict.hpp b/wasm-port/runtime/core/shims/boost/python/dict.hpp new file mode 100644 index 0000000..a91811e --- /dev/null +++ b/wasm-port/runtime/core/shims/boost/python/dict.hpp @@ -0,0 +1,3 @@ +#pragma once + +#include "boost/python/object_fwd.hpp" diff --git a/wasm-port/runtime/core/shims/boost/python/extract.hpp b/wasm-port/runtime/core/shims/boost/python/extract.hpp new file mode 100644 index 0000000..a91811e --- /dev/null +++ b/wasm-port/runtime/core/shims/boost/python/extract.hpp @@ -0,0 +1,3 @@ +#pragma once + +#include "boost/python/object_fwd.hpp" diff --git a/wasm-port/runtime/core/shims/boost/python/import.hpp b/wasm-port/runtime/core/shims/boost/python/import.hpp new file mode 100644 index 0000000..a91811e --- /dev/null +++ b/wasm-port/runtime/core/shims/boost/python/import.hpp @@ -0,0 +1,3 @@ +#pragma once + +#include "boost/python/object_fwd.hpp" diff --git a/wasm-port/runtime/core/shims/boost/python/list.hpp b/wasm-port/runtime/core/shims/boost/python/list.hpp new file mode 100644 index 0000000..a91811e --- /dev/null +++ b/wasm-port/runtime/core/shims/boost/python/list.hpp @@ -0,0 +1,3 @@ +#pragma once + +#include "boost/python/object_fwd.hpp" diff --git a/wasm-port/runtime/core/shims/boost/python/object_fwd.hpp b/wasm-port/runtime/core/shims/boost/python/object_fwd.hpp index 7771608..cc43aca 100644 --- a/wasm-port/runtime/core/shims/boost/python/object_fwd.hpp +++ b/wasm-port/runtime/core/shims/boost/python/object_fwd.hpp @@ -1,9 +1,88 @@ #pragma once +#include + +struct _typeobject { + const char *tp_name = "standalone-python-shim"; +}; + +struct _object { + _typeobject *ob_type = nullptr; +}; +typedef _object PyObject; + +inline int PyCallable_Check(PyObject *) { return 0; } +inline int PyErr_ExceptionMatches(PyObject *) { return 0; } +inline void PyErr_Clear() {} +inline int PyUnicode_Check(PyObject *) { return 0; } +inline int PyLong_Check(PyObject *) { return 0; } +inline int PyFloat_Check(PyObject *) { return 0; } +inline PyObject *PyObject_Str(PyObject *) { return nullptr; } +inline void Py_XDECREF(PyObject *) {} +inline const char *PyUnicode_AsUTF8(PyObject *) { return ""; } + +inline PyObject *PyExc_KeyError = nullptr; +inline PyObject *Py_None = nullptr; + namespace boost { namespace python { -class object {}; +class error_already_set {}; + +class object { +public: + object() = default; + + template + explicit object(const T &) {} + + object attr(const char *) const { return object(); } + object operator[](const char *) const { return object(); } + object operator[](const std::string &) const { return object(); } + object operator[](int) const { return object(); } + PyObject *ptr() const { return nullptr; } +}; + +class list : public object { +public: + using object::object; + list() = default; + explicit list(const object &) {} + + template + void append(const T &) {} +}; + +class tuple : public object { +public: + tuple() = default; + explicit tuple(const list &) {} +}; + +class dict : public object { +public: + object keys() const { return object(); } +}; + +class scope { +public: + explicit scope(const object &) {} + object attr(const char *) const { return object(); } +}; + +template +object import(const T &) { return object(); } + +template +class extract { +public: + explicit extract(const object &) {} + + operator T() const { return T(); } +}; + +inline int len(const object &) { return 0; } +inline void handle_exception() {} } // namespace python } // namespace boost diff --git a/wasm-port/runtime/core/shims/boost/python/scope.hpp b/wasm-port/runtime/core/shims/boost/python/scope.hpp new file mode 100644 index 0000000..a91811e --- /dev/null +++ b/wasm-port/runtime/core/shims/boost/python/scope.hpp @@ -0,0 +1,3 @@ +#pragma once + +#include "boost/python/object_fwd.hpp" diff --git a/wasm-port/runtime/core/shims/boost/python/tuple.hpp b/wasm-port/runtime/core/shims/boost/python/tuple.hpp new file mode 100644 index 0000000..a91811e --- /dev/null +++ b/wasm-port/runtime/core/shims/boost/python/tuple.hpp @@ -0,0 +1,3 @@ +#pragma once + +#include "boost/python/object_fwd.hpp" diff --git a/wasm-port/runtime/core/shims/hal.h b/wasm-port/runtime/core/shims/hal.h new file mode 100644 index 0000000..0329cd8 --- /dev/null +++ b/wasm-port/runtime/core/shims/hal.h @@ -0,0 +1,30 @@ +#pragma once + +#include + +#define HAL_NAME_LEN 64 + +typedef enum { + HAL_TYPE_UNINITIALIZED = 0, + HAL_BIT, + HAL_FLOAT, + HAL_S32, + HAL_U32, + HAL_S64, + HAL_U64 +} hal_type_t; + +typedef union { + bool b; + double f; + int s; + unsigned int u; + long long ls; + unsigned long long lu; +} hal_data_u; + +int hal_init(const char *); +int hal_ready(int); +int hal_get_pin_value_by_name(const char *, hal_type_t *, hal_data_u **, bool *); +int hal_get_signal_value_by_name(const char *, hal_type_t *, hal_data_u **, bool *); +int hal_get_param_value_by_name(const char *, hal_type_t *, hal_data_u **); diff --git a/wasm-port/runtime/core/shims/interp_python.hh b/wasm-port/runtime/core/shims/interp_python.hh new file mode 100644 index 0000000..c376e73 --- /dev/null +++ b/wasm-port/runtime/core/shims/interp_python.hh @@ -0,0 +1,16 @@ +#pragma once + +#include + +#include "boost/python/object_fwd.hpp" + +struct pycontext_impl { + boost::python::object tupleargs; + boost::python::object kwargs; + int py_return_type = 0; + double py_returned_double = 0.0; + int py_returned_int = 0; + boost::python::object generator_next; +}; + +std::string handle_pyerror(); diff --git a/wasm-port/runtime/core/shims/pythonplugin/python_plugin.hh b/wasm-port/runtime/core/shims/pythonplugin/python_plugin.hh index 476a506..ffebda9 100644 --- a/wasm-port/runtime/core/shims/pythonplugin/python_plugin.hh +++ b/wasm-port/runtime/core/shims/pythonplugin/python_plugin.hh @@ -2,12 +2,37 @@ #include +#include "boost/python/object_fwd.hpp" + +enum pp_status { + PLUGIN_NO_SECTION = -1, + PLUGIN_OK = 0, + PLUGIN_NO_CALLABLE = 1, + PLUGIN_EXCEPTION = 2 +}; + +std::string handle_pyerror(); + class PythonPlugin { public: + static PythonPlugin *instantiate(struct _inittab * = nullptr); + int configure(const char * = nullptr, const char * = nullptr) { return PLUGIN_NO_SECTION; } + bool is_callable(const char *, const char *) { return false; } + int call(const char *, const char *, boost::python::object, boost::python::object, + boost::python::object &) { return PLUGIN_NO_CALLABLE; } + int run_string(const char *, boost::python::object &, bool = false) { return PLUGIN_NO_CALLABLE; } + int call_method(boost::python::object, boost::python::object &) { return PLUGIN_NO_CALLABLE; } + int plugin_status() const { return PLUGIN_NO_SECTION; } bool usable() const { return false; } - int plugin_status() const { return 0; } + int initialize() { return PLUGIN_NO_SECTION; } const std::string &last_exception() const { static std::string empty; return empty; } + const std::string &last_errmsg() const { + static std::string empty; + return empty; + } + + boost::python::object main_namespace; }; diff --git a/wasm-port/runtime/core/shims/tooldata/tooldata.hh b/wasm-port/runtime/core/shims/tooldata/tooldata.hh index e276e1e..b857b01 100644 --- a/wasm-port/runtime/core/shims/tooldata/tooldata.hh +++ b/wasm-port/runtime/core/shims/tooldata/tooldata.hh @@ -1,6 +1,7 @@ #pragma once #include "emc/nml_intf/emctool.h" +#include "linuxcnc_tool_adapter.hh" enum { IDX_OK = 0, @@ -8,22 +9,15 @@ enum { inline CANON_TOOL_TABLE tooldata_entry_init() { - CANON_TOOL_TABLE tool{}; - tool.toolno = 0; - tool.pocketno = 0; - return tool; + return standalone::tool_entry_init(); } inline int tooldata_find_index_for_tool(int toolno) { - return toolno == 0 ? 0 : -1; + return standalone::find_tool_index_for_tool(toolno); } inline int tooldata_get(CANON_TOOL_TABLE *tool, int index) { - if ((tool == nullptr) || (index != 0)) { - return -1; - } - *tool = tooldata_entry_init(); - return IDX_OK; + return standalone::get_tool_entry(tool, index) == 0 ? IDX_OK : -1; } diff --git a/wasm-port/tests/fixtures/canon/arc_semantics.events b/wasm-port/tests/fixtures/canon/arc_semantics.events new file mode 100644 index 0000000..40d58c6 --- /dev/null +++ b/wasm-port/tests/fixtures/canon/arc_semantics.events @@ -0,0 +1,13 @@ +canon_event=STRAIGHT_TRAVERSE line=1 x=0 y=0 z=0 a=0 b=0 c=0 u=0 v=0 w=0 +canon_event=COMMENT: interpreter: IJK distance mode changed to incremental +canon_event=SET_FEED_RATE rate=60 +canon_event=ARC_FEED line=3 first_end=1 second_end=1 first_axis=1 second_axis=0 rotation=-1 axis_end_point=0 a=0 b=0 c=0 u=0 v=0 w=0 +canon_event=COMMENT: interpreter: IJK distance mode changed to absolute +canon_event=ARC_FEED line=5 first_end=0 second_end=0 first_axis=0 second_axis=1 rotation=1 axis_end_point=0 a=0 b=0 c=0 u=0 v=0 w=0 +canon_event=ARC_FEED line=6 first_end=1 second_end=0 first_axis=0.5 second_axis=-3.06162e-17 rotation=-1 axis_end_point=0 a=0 b=0 c=0 u=0 v=0 w=0 +canon_event=STRAIGHT_TRAVERSE line=7 x=0 y=0 z=0 a=0 b=0 c=0 u=0 v=0 w=0 +canon_event=ARC_FEED line=9 first_end=1 second_end=1 first_axis=0 second_axis=1 rotation=-1 axis_end_point=0 a=0 b=0 c=0 u=0 v=0 w=0 +canon_event=STRAIGHT_TRAVERSE line=10 x=0 y=0 z=0 a=0 b=0 c=0 u=0 v=0 w=0 +canon_event=ARC_FEED line=11 first_end=1 second_end=1 first_axis=0 second_axis=1 rotation=1 axis_end_point=0 a=0 b=0 c=0 u=0 v=0 w=0 +canon_event=STRAIGHT_TRAVERSE line=12 x=0 y=0 z=0 a=0 b=0 c=0 u=0 v=0 w=0 +canon_event=ARC_FEED line=13 first_end=1 second_end=0 first_axis=0.5 second_axis=0.866025 rotation=-1 axis_end_point=2 a=0 b=0 c=0 u=0 v=0 w=0 diff --git a/wasm-port/tests/fixtures/canon/canon_runtime_edges.events b/wasm-port/tests/fixtures/canon/canon_runtime_edges.events new file mode 100644 index 0000000..5707178 --- /dev/null +++ b/wasm-port/tests/fixtures/canon/canon_runtime_edges.events @@ -0,0 +1,11 @@ +canon_event=SET_SPINDLE_SPEED spindle=0 speed=1200 +canon_event=START_SPINDLE_CLOCKWISE spindle=0 wait_for_at_speed=1 +canon_event=STOP_SPINDLE_TURNING spindle=0 +canon_event=SET_SPINDLE_SPEED spindle=0 speed=900 +canon_event=START_SPINDLE_COUNTERCLOCKWISE spindle=0 wait_for_at_speed=1 +canon_event=STOP_SPINDLE_TURNING spindle=0 +canon_event=MIST_ON +canon_event=FLOOD_ON +canon_event=MIST_OFF +canon_event=FLOOD_OFF +canon_event=DWELL seconds=0.25 diff --git a/wasm-port/tests/fixtures/canon/namedparam_semantics.events b/wasm-port/tests/fixtures/canon/namedparam_semantics.events new file mode 100644 index 0000000..935d798 --- /dev/null +++ b/wasm-port/tests/fixtures/canon/namedparam_semantics.events @@ -0,0 +1,7 @@ +canon_event=MESSAGE: named global=42.5000 +canon_event=MESSAGE: named local=7.2500 +canon_event=MESSAGE: exists global=1 local=1 missing=0 +canon_event=MESSAGE: ini velocity=35 +canon_event=MESSAGE: hal pin=1 signal=98.2500 param=-17 +canon_event=MESSAGE: hal u32=123456789 s64=-9000000000 u64=9000000000 +canon_event=MESSAGE: hal disconnected=12.5000 missing_exists=0 diff --git a/wasm-port/tests/fixtures/canon/numbered_params.events b/wasm-port/tests/fixtures/canon/numbered_params.events new file mode 100644 index 0000000..4e7020c --- /dev/null +++ b/wasm-port/tests/fixtures/canon/numbered_params.events @@ -0,0 +1,3 @@ +canon_event=MESSAGE: numbered p1=12.5000 p2=15.5000 exists1=1 exists5602=0 +canon_event=STRAIGHT_TRAVERSE line=6 x=2 y=3 z=4 a=0 b=0 c=0 u=0 v=0 w=0 +canon_event=MESSAGE: numbered pos x=2.0000 y=3.0000 z=4.0000 diff --git a/wasm-port/tests/fixtures/canon/oword_subroutine.events b/wasm-port/tests/fixtures/canon/oword_subroutine.events new file mode 100644 index 0000000..502497e --- /dev/null +++ b/wasm-port/tests/fixtures/canon/oword_subroutine.events @@ -0,0 +1,3 @@ +STRAIGHT_TRAVERSE line=4 x=0 y=0 z=0 +SET_FEED_RATE rate=100 +STRAIGHT_FEED line=2 x=2 y=3 z=0 diff --git a/wasm-port/tests/fixtures/canon/tool_semantics.events b/wasm-port/tests/fixtures/canon/tool_semantics.events new file mode 100644 index 0000000..af52a59 --- /dev/null +++ b/wasm-port/tests/fixtures/canon/tool_semantics.events @@ -0,0 +1,11 @@ +canon_event=SELECT_TOOL tool=2 +canon_event=MESSAGE: tool selected=2 selected_pocket=2 +canon_event=STOP_SPINDLE_TURNING spindle=0 +canon_event=CHANGE_TOOL +canon_event=MESSAGE: tool after_m6 current_pocket=2 current_tool=2 +canon_event=USE_TOOL_LENGTH_OFFSET x=0 y=0 z=1.25 a=0 b=0 c=0 u=0 v=0 w=0 +canon_event=MESSAGE: tool g43 offset=1 x=0.0000 y=0.0000 z=1.2500 +canon_event=USE_TOOL_LENGTH_OFFSET x=0 y=0 z=0 a=0 b=0 c=0 u=0 v=0 w=0 +canon_event=MESSAGE: tool g49 offset=0 x=0.0000 y=0.0000 z=0.0000 +canon_event=CHANGE_TOOL_NUMBER pocket=0 +canon_event=MESSAGE: tool after_m61 current_pocket=0 current_tool=2 diff --git a/wasm-port/tests/fixtures/canon_errors/arc_radius_mismatch.expected b/wasm-port/tests/fixtures/canon_errors/arc_radius_mismatch.expected new file mode 100644 index 0000000..3d232b7 --- /dev/null +++ b/wasm-port/tests/fixtures/canon_errors/arc_radius_mismatch.expected @@ -0,0 +1,4 @@ +execute_line_1=0 +execute_line_2=5 +error_text=Radius to end of arc differs from radius to start +absent=canon_event=ARC_FEED diff --git a/wasm-port/tests/fixtures/canon_errors/arc_zero_radius.expected b/wasm-port/tests/fixtures/canon_errors/arc_zero_radius.expected new file mode 100644 index 0000000..82fa557 --- /dev/null +++ b/wasm-port/tests/fixtures/canon_errors/arc_zero_radius.expected @@ -0,0 +1,4 @@ +execute_line_1=0 +execute_line_2=5 +error_text=Zero-radius arc +absent=canon_event=ARC_FEED diff --git a/wasm-port/tests/fixtures/canon_errors/namedparam_readonly.expected b/wasm-port/tests/fixtures/canon_errors/namedparam_readonly.expected new file mode 100644 index 0000000..f7f4de2 --- /dev/null +++ b/wasm-port/tests/fixtures/canon_errors/namedparam_readonly.expected @@ -0,0 +1,2 @@ +execute_line_1=5 +error_text=Cannot assign to read-only parameter #<_feed> diff --git a/wasm-port/tests/fixtures/canon_errors/numbered_param_readonly.expected b/wasm-port/tests/fixtures/canon_errors/numbered_param_readonly.expected new file mode 100644 index 0000000..81ca8e2 --- /dev/null +++ b/wasm-port/tests/fixtures/canon_errors/numbered_param_readonly.expected @@ -0,0 +1,2 @@ +execute_line_1=5 +error_text=Parameter is readonly diff --git a/wasm-port/tests/fixtures/canon_errors/tool_length_offset_not_found.expected b/wasm-port/tests/fixtures/canon_errors/tool_length_offset_not_found.expected new file mode 100644 index 0000000..3514de8 --- /dev/null +++ b/wasm-port/tests/fixtures/canon_errors/tool_length_offset_not_found.expected @@ -0,0 +1,3 @@ +execute_line_1=5 +error_text=Requested tool 999 not found in the tool table +absent=canon_event=USE_TOOL_LENGTH_OFFSET diff --git a/wasm-port/tests/fixtures/canon_errors/tool_not_found.expected b/wasm-port/tests/fixtures/canon_errors/tool_not_found.expected new file mode 100644 index 0000000..12bed3b --- /dev/null +++ b/wasm-port/tests/fixtures/canon_errors/tool_not_found.expected @@ -0,0 +1,2 @@ +execute_line_1=5 +error_text=Requested tool 999 not found in the tool table diff --git a/wasm-port/tests/fixtures/gcode/arc_semantics.ngc b/wasm-port/tests/fixtures/gcode/arc_semantics.ngc new file mode 100644 index 0000000..ef531c3 --- /dev/null +++ b/wasm-port/tests/fixtures/gcode/arc_semantics.ngc @@ -0,0 +1,13 @@ +G90 G17 G0 X0 Y0 Z0 +G91.1 +G2 X1 Y1 I1 J0 F60 +G90.1 +G3 X0 Y0 I0 J1 +G2 X1 Y0 R0.5 +G18 G0 X0 Y0 Z0 +G91.1 +G2 X1 Z1 I1 K0 +G19 G0 X0 Y0 Z0 +G3 Y1 Z1 J0 K1 +G17 G0 X0 Y0 Z0 +G2 X1 Y0 Z2 R-1 diff --git a/wasm-port/tests/fixtures/gcode/canon_runtime_edges.ngc b/wasm-port/tests/fixtures/gcode/canon_runtime_edges.ngc new file mode 100644 index 0000000..c5a16ec --- /dev/null +++ b/wasm-port/tests/fixtures/gcode/canon_runtime_edges.ngc @@ -0,0 +1,8 @@ +S1200 M3 +M5 +S900 M4 +M5 +M7 +M8 +M9 +G4 P0.25 diff --git a/wasm-port/tests/fixtures/gcode/namedparam_semantics.ngc b/wasm-port/tests/fixtures/gcode/namedparam_semantics.ngc new file mode 100644 index 0000000..27c8a1d --- /dev/null +++ b/wasm-port/tests/fixtures/gcode/namedparam_semantics.ngc @@ -0,0 +1,21 @@ +#<_global_probe> = 42.5 +# = 7.25 +# = EXISTS[#<_global_probe>] +# = EXISTS[#] +# = EXISTS[#] +# = #<_ini[traj]max_linear_velocity> +# = #<_hal[standalone.pin-bit]> +# = #<_hal[standalone.signal-float]> +# = #<_hal[standalone.param-s32]> +# = #<_hal[standalone.pin-u32]> +# = #<_hal[standalone.signal-s64]> +# = #<_hal[standalone.param-u64]> +# = #<_hal[standalone.disconnected-float]> +# = EXISTS[#<_hal[standalone.missing]>] +(DEBUG, named global=%f#<_global_probe>) +(DEBUG, named local=%f#) +(DEBUG, exists global=%d# local=%d# missing=%d#) +(DEBUG, ini velocity=%d#) +(DEBUG, hal pin=%d# signal=%f# param=%d#) +(DEBUG, hal u32=%d# s64=%.0f# u64=%.0f#) +(DEBUG, hal disconnected=%f# missing_exists=%d#) diff --git a/wasm-port/tests/fixtures/gcode/numbered_params.ngc b/wasm-port/tests/fixtures/gcode/numbered_params.ngc new file mode 100644 index 0000000..bd6f7e5 --- /dev/null +++ b/wasm-port/tests/fixtures/gcode/numbered_params.ngc @@ -0,0 +1,7 @@ +#1 = 12.5 +#2 = [#1 + 3] +#3 = EXISTS[#1] +#4 = EXISTS[#5602] +(DEBUG, numbered p1=%f#1 p2=%f#2 exists1=%d#3 exists5602=%d#4) +G90 G0 X2 Y3 Z4 +(DEBUG, numbered pos x=%f#5420 y=%f#5421 z=%f#5422) diff --git a/wasm-port/tests/fixtures/gcode/oword_subroutine.ngc b/wasm-port/tests/fixtures/gcode/oword_subroutine.ngc new file mode 100644 index 0000000..d99b268 --- /dev/null +++ b/wasm-port/tests/fixtures/gcode/oword_subroutine.ngc @@ -0,0 +1,5 @@ +O sub +G1 X#1 Y#2 F100 +O endsub +G0 X0 Y0 +O call [2] [3] diff --git a/wasm-port/tests/fixtures/gcode/tool_semantics.ngc b/wasm-port/tests/fixtures/gcode/tool_semantics.ngc new file mode 100644 index 0000000..f97c1a0 --- /dev/null +++ b/wasm-port/tests/fixtures/gcode/tool_semantics.ngc @@ -0,0 +1,10 @@ +T2 +(DEBUG, tool selected=%d#<_selected_tool> selected_pocket=%d#<_selected_pocket>) +M6 +(DEBUG, tool after_m6 current_pocket=%d#<_current_pocket> current_tool=%d#<_current_tool>) +G43 H2 +(DEBUG, tool g43 offset=%d#<_tool_offset> x=%f#5401 y=%f#5402 z=%f#5403) +G49 +(DEBUG, tool g49 offset=%d#<_tool_offset> x=%f#5401 y=%f#5402 z=%f#5403) +M61 Q2 +(DEBUG, tool after_m61 current_pocket=%d#<_current_pocket> current_tool=%d#<_current_tool>) diff --git a/wasm-port/tests/fixtures/gcode_errors/arc_radius_mismatch.ngc b/wasm-port/tests/fixtures/gcode_errors/arc_radius_mismatch.ngc new file mode 100644 index 0000000..eb6fa83 --- /dev/null +++ b/wasm-port/tests/fixtures/gcode_errors/arc_radius_mismatch.ngc @@ -0,0 +1,2 @@ +G90 G17 G0 X0 Y0 +G2 X1 Y1 I0.2 J0 F60 diff --git a/wasm-port/tests/fixtures/gcode_errors/arc_zero_radius.ngc b/wasm-port/tests/fixtures/gcode_errors/arc_zero_radius.ngc new file mode 100644 index 0000000..8c07291 --- /dev/null +++ b/wasm-port/tests/fixtures/gcode_errors/arc_zero_radius.ngc @@ -0,0 +1,2 @@ +G90 G17 G0 X0 Y0 +G2 X1 Y0 I0 J0 F60 diff --git a/wasm-port/tests/fixtures/gcode_errors/namedparam_readonly.ngc b/wasm-port/tests/fixtures/gcode_errors/namedparam_readonly.ngc new file mode 100644 index 0000000..22c5bb8 --- /dev/null +++ b/wasm-port/tests/fixtures/gcode_errors/namedparam_readonly.ngc @@ -0,0 +1 @@ +#<_feed> = 1 diff --git a/wasm-port/tests/fixtures/gcode_errors/numbered_param_readonly.ngc b/wasm-port/tests/fixtures/gcode_errors/numbered_param_readonly.ngc new file mode 100644 index 0000000..ad35129 --- /dev/null +++ b/wasm-port/tests/fixtures/gcode_errors/numbered_param_readonly.ngc @@ -0,0 +1 @@ +#5400 = 1 diff --git a/wasm-port/tests/fixtures/gcode_errors/tool_length_offset_not_found.ngc b/wasm-port/tests/fixtures/gcode_errors/tool_length_offset_not_found.ngc new file mode 100644 index 0000000..5e7636e --- /dev/null +++ b/wasm-port/tests/fixtures/gcode_errors/tool_length_offset_not_found.ngc @@ -0,0 +1 @@ +G43 H999 diff --git a/wasm-port/tests/fixtures/gcode_errors/tool_not_found.ngc b/wasm-port/tests/fixtures/gcode_errors/tool_not_found.ngc new file mode 100644 index 0000000..1583325 --- /dev/null +++ b/wasm-port/tests/fixtures/gcode_errors/tool_not_found.ngc @@ -0,0 +1 @@ +T999 diff --git a/wasm-port/tests/fixtures/ini/namedparams.ini b/wasm-port/tests/fixtures/ini/namedparams.ini new file mode 100644 index 0000000..8fdc215 --- /dev/null +++ b/wasm-port/tests/fixtures/ini/namedparams.ini @@ -0,0 +1,3 @@ +[TRAJ] +LINEAR_UNITS = mm +MAX_LINEAR_VELOCITY = 35 diff --git a/wasm-port/tests/native/verify_native_probes.sh b/wasm-port/tests/native/verify_native_probes.sh index 5f6ba40..de550e1 100755 --- a/wasm-port/tests/native/verify_native_probes.sh +++ b/wasm-port/tests/native/verify_native_probes.sh @@ -7,6 +7,7 @@ GCODE_FIXTURE_DIR="$ROOT_DIR/tests/fixtures/gcode" CANON_FIXTURE_DIR="$ROOT_DIR/tests/fixtures/canon" GCODE_ERROR_FIXTURE_DIR="$ROOT_DIR/tests/fixtures/gcode_errors" CANON_ERROR_FIXTURE_DIR="$ROOT_DIR/tests/fixtures/canon_errors" +NAMEDPARAM_INI_FIXTURE="$ROOT_DIR/tests/fixtures/ini/namedparams.ini" "$ROOT_DIR/tools/build_native_probes.sh" @@ -32,25 +33,56 @@ check_exitcode() { check_exitcode linuxcnc_interp_state_probe check_exitcode linuxcnc_namedparam_harness +check_exitcode linuxcnc_namedparam_harness.run check_exitcode linuxcnc_interp_minimal_harness check_exitcode linuxcnc_interp_minimal_harness.run check_exitcode linuxcnc_rs274_compile_probe check_exitcode linuxcnc_interp_convert_source_probe +NAMEDPARAM_STDOUT="$BUILD_DIR/linuxcnc_namedparam_harness.run.stdout.log" +grep -Fq "init_named_parameters=0" "$NAMEDPARAM_STDOUT" +grep -Fq "global_named_count=57" "$NAMEDPARAM_STDOUT" +grep -Fq "_metric_machine: rc=0 found=1 value=1" "$NAMEDPARAM_STDOUT" +grep -Fq "_motion_mode: rc=0 found=1 value=10" "$NAMEDPARAM_STDOUT" +grep -Fq "_metric: rc=0 found=1 value=1" "$NAMEDPARAM_STDOUT" +grep -Fq "_feed: rc=0 found=1 value=123.45" "$NAMEDPARAM_STDOUT" +grep -Fq "_rpm: rc=0 found=1 value=678.9" "$NAMEDPARAM_STDOUT" +grep -Fq "_x: rc=0 found=1 value=1.25" "$NAMEDPARAM_STDOUT" +grep -Fq "_current_tool: rc=0 found=1 value=12" "$NAMEDPARAM_STDOUT" +grep -Fq "_ini[traj]max_linear_velocity: rc=0 found=1 value=35" "$NAMEDPARAM_STDOUT" +grep -Fq "_hal[standalone.pin-bit]: rc=0 found=1 value=1" "$NAMEDPARAM_STDOUT" +grep -Fq "_hal[standalone.signal-float]: rc=0 found=1 value=98.25" "$NAMEDPARAM_STDOUT" +grep -Fq "_hal[standalone.param-s32]: rc=0 found=1 value=-17" "$NAMEDPARAM_STDOUT" +grep -Fq "_hal[standalone.pin-u32]: rc=0 found=1 value=1.23457e+08" "$NAMEDPARAM_STDOUT" +grep -Fq "_hal[standalone.signal-s64]: rc=0 found=1 value=-9e+09" "$NAMEDPARAM_STDOUT" +grep -Fq "_hal[standalone.param-u64]: rc=0 found=1 value=9e+09" "$NAMEDPARAM_STDOUT" +grep -Fq "_hal[standalone.disconnected-float]: rc=0 found=1 value=12.5" "$NAMEDPARAM_STDOUT" +grep -Fq "_hal[standalone.missing]: rc=0 found=0 value=0" "$NAMEDPARAM_STDOUT" + check_fixture_output() { local fixture="$1" local expected="$2" local stdout_file="$3" + local require_mdi="${4:-1}" grep -Fq "read=0" "$stdout_file" grep -Fq "parse_line=0" "$stdout_file" - local line_count - line_count="$(grep -cv '^[[:space:]]*$' "$fixture")" - local line_number - for ((line_number = 1; line_number <= line_count; line_number += 1)); do - grep -Fq "execute_line_${line_number}=0" "$stdout_file" - done + if [[ "$require_mdi" == "1" ]]; then + local line_count + line_count="$(grep -cv '^[[:space:]]*$' "$fixture")" + local line_number + for ((line_number = 1; line_number <= line_count; line_number += 1)); do + if ! grep -Fq "execute_line_${line_number}=0" "$stdout_file" && + ! grep -Fq "execute_line_${line_number}=2" "$stdout_file"; then + echo "missing successful execute status for line $line_number in $stdout_file" >&2 + exit 1 + fi + done + else + grep -Fq "file_open=0" "$stdout_file" + grep -Fq "file_execute_1=0" "$stdout_file" + fi while IFS= read -r expected_event; do [[ -z "$expected_event" ]] && continue @@ -74,10 +106,14 @@ for fixture in "$GCODE_FIXTURE_DIR"/*.ngc; do stdout_file="$BUILD_DIR/linuxcnc_interp_minimal_harness.$name.stdout.log" stderr_file="$BUILD_DIR/linuxcnc_interp_minimal_harness.$name.stderr.log" - "$BUILD_DIR/linuxcnc_interp_minimal_harness" "$fixture" \ + INI_FILE_NAME="$NAMEDPARAM_INI_FIXTURE" "$BUILD_DIR/linuxcnc_interp_minimal_harness" "$fixture" \ >"$stdout_file" \ 2>"$stderr_file" - check_fixture_output "$fixture" "$expected" "$stdout_file" + require_mdi=1 + if [[ "$name" == "oword_subroutine" ]]; then + require_mdi=0 + fi + check_fixture_output "$fixture" "$expected" "$stdout_file" "$require_mdi" done for fixture in "$GCODE_ERROR_FIXTURE_DIR"/*.ngc; do @@ -90,7 +126,7 @@ for fixture in "$GCODE_ERROR_FIXTURE_DIR"/*.ngc; do stdout_file="$BUILD_DIR/linuxcnc_interp_minimal_harness.$name.stdout.log" stderr_file="$BUILD_DIR/linuxcnc_interp_minimal_harness.$name.stderr.log" - "$BUILD_DIR/linuxcnc_interp_minimal_harness" "$fixture" \ + INI_FILE_NAME="$NAMEDPARAM_INI_FIXTURE" "$BUILD_DIR/linuxcnc_interp_minimal_harness" "$fixture" \ >"$stdout_file" \ 2>"$stderr_file" @@ -103,7 +139,7 @@ for fixture in "$GCODE_ERROR_FIXTURE_DIR"/*.ngc; do exit 1 fi elif [[ "$expected_line" == error_text=* ]]; then - grep -Fq "${expected_line#error_text=}" "$stderr_file" + grep -Fq "$expected_line" "$stdout_file" else grep -Fq "$expected_line" "$stdout_file" fi diff --git a/wasm-port/tools/build_native_probes.sh b/wasm-port/tools/build_native_probes.sh index 4832daf..576109f 100755 --- a/wasm-port/tools/build_native_probes.sh +++ b/wasm-port/tools/build_native_probes.sh @@ -8,141 +8,332 @@ WRAP_DIR="$ROOT_DIR/runtime/core/linuxcnc_wrap" SHIM_DIR="$ROOT_DIR/runtime/core/shims" INCLUDE_DIR="$ROOT_DIR/runtime/core/include" MINIMAL_GCODE_FIXTURE="$ROOT_DIR/tests/fixtures/gcode/minimal_linear.ngc" +NAMEDPARAM_INI_FIXTURE="$ROOT_DIR/tests/fixtures/ini/namedparams.ini" +CXX="${CXX:-g++}" mkdir -p "$BUILD_DIR" -rm -f \ +COMMON_FLAGS=( + -std=c++20 + -O2 + -D_GNU_SOURCE + -DM_PI=3.14159265358979323846 + -DOBJECT_FWD_DWA2002724_HPP + -I"$WRAP_DIR" + -I"$SHIM_DIR" + -I"$INCLUDE_DIR" + -I"$VENDOR_DIR/src" + -I"$VENDOR_DIR/src/rtapi" + -I"$VENDOR_DIR/src/emc" + -I"$VENDOR_DIR/src/emc/nml_intf" + -I"$VENDOR_DIR/src/emc/motion" + -I"$VENDOR_DIR/src/libnml/posemath" +) + +COMMON_INI_FLAGS=( + "${COMMON_FLAGS[@]}" + -I"$VENDOR_DIR/src/emc/ini" +) + +MINIMAL_FLAGS=( + "${COMMON_INI_FLAGS[@]}" + -ffunction-sections + -fdata-sections + -DUNIT_TEST + -DLINUXCNC_STANDALONE_USE_RS274_PRE_STATE +) + +MINIMAL_LINK_FLAGS=( + -Wl,--gc-sections +) + +write_command_file() { + local file="$1" + shift + printf '%q\n' "$@" > "$file" +} + +command_matches() { + local file="$1" + shift + + local tmp + tmp="$(mktemp)" + write_command_file "$tmp" "$@" + if [[ -f "$file" ]] && cmp -s "$tmp" "$file"; then + rm -f "$tmp" + return 0 + fi + rm -f "$tmp" + return 1 +} + +depfile_newer_than() { + local depfile="$1" + local output="$2" + + [[ -f "$depfile" ]] || return 0 + local deps + deps="$(tr '\\\n' ' ' < "$depfile" | sed -e 's/^[^:]*://')" + local dep + for dep in $deps; do + if [[ -f "$dep" && "$dep" -nt "$output" ]]; then + return 0 + fi + done + return 1 +} + +object_needs_rebuild() { + local obj="$1" + local depfile="$2" + local cmdfile="$3" + shift 3 + + [[ -f "$obj" ]] || return 0 + command_matches "$cmdfile" "$@" || return 0 + depfile_newer_than "$depfile" "$obj" && return 0 + return 1 +} + +compile_object() { + local target="$1" + local source="$2" + local obj="$3" + shift 3 + + local stdout_log="$BUILD_DIR/$target.stdout.log" + local stderr_log="$BUILD_DIR/$target.stderr.log" + local depfile="$obj.d" + local cmdfile="$obj.cmd" + local cmd=("$CXX" "$@" -MMD -MP -MF "$depfile" -c "$source" -o "$obj") + + mkdir -p "$(dirname "$obj")" + if ! object_needs_rebuild "$obj" "$depfile" "$cmdfile" "${cmd[@]}"; then + printf 'up to date: %s\n' "$source" >> "$stdout_log" + return 0 + fi + + printf 'compile: %s\n' "$source" >> "$stdout_log" + if "${cmd[@]}" >> "$stdout_log" 2>> "$stderr_log"; then + write_command_file "$cmdfile" "${cmd[@]}" + return 0 + fi + return 1 +} + +link_needs_rebuild() { + local output="$1" + local cmdfile="$2" + shift 2 + + [[ -f "$output" ]] || return 0 + command_matches "$cmdfile" "$@" || return 0 + + local arg + for arg in "$@"; do + if [[ -f "$arg" && "$arg" -nt "$output" ]]; then + return 0 + fi + done + return 1 +} + +link_binary() { + local target="$1" + local output="$2" + shift 2 + + local stdout_log="$BUILD_DIR/$target.stdout.log" + local stderr_log="$BUILD_DIR/$target.stderr.log" + local cmdfile="$output.cmd" + local cmd=("$CXX" "$@" -o "$output") + + if ! link_needs_rebuild "$output" "$cmdfile" "${cmd[@]}"; then + printf 'up to date: %s\n' "$output" >> "$stdout_log" + return 0 + fi + + printf 'link: %s\n' "$output" >> "$stdout_log" + if "${cmd[@]}" >> "$stdout_log" 2>> "$stderr_log"; then + write_command_file "$cmdfile" "${cmd[@]}" + return 0 + fi + return 1 +} + +compile_target_objects() { + local target="$1" + local flags_name="$2" + local sources_name="$3" + local objs_name="$4" + + local -n flags="$flags_name" + local -n sources="$sources_name" + local -n objs="$objs_name" + local obj_dir="$BUILD_DIR/obj/$target" + local status=0 + + objs=() + local source + for source in "${sources[@]}"; do + local base + base="$(basename "$source")" + local obj="$obj_dir/${base%.*}.o" + objs+=("$obj") + if ! compile_object "$target" "$source" "$obj" "${flags[@]}"; then + status=1 + fi + done + + return "$status" +} + +build_binary_target() { + local target="$1" + local output="$2" + local flags_name="$3" + local sources_name="$4" + local link_flags_name="$5" + shift 5 + + local stdout_log="$BUILD_DIR/$target.stdout.log" + local stderr_log="$BUILD_DIR/$target.stderr.log" + : > "$stdout_log" + : > "$stderr_log" + + local target_objs=() + local status=0 + if ! compile_target_objects "$target" "$flags_name" "$sources_name" target_objs; then + status=1 + fi + + if [[ "$status" -eq 0 ]]; then + local -n link_flags="$link_flags_name" + if ! link_binary "$target" "$output" "${link_flags[@]}" "${target_objs[@]}" "$@"; then + status=1 + fi + fi + + echo "$status" > "$BUILD_DIR/$target.exitcode" + return "$status" +} + +build_object_target() { + local target="$1" + local output="$2" + local source="$3" + local flags_name="$4" + + local stdout_log="$BUILD_DIR/$target.stdout.log" + local stderr_log="$BUILD_DIR/$target.stderr.log" + : > "$stdout_log" + : > "$stderr_log" + + local -n flags="$flags_name" + local status=0 + if ! compile_object "$target" "$source" "$output" "${flags[@]}"; then + status=1 + fi + + echo "$status" > "$BUILD_DIR/$target.exitcode" + return "$status" +} + +NO_LINK_FLAGS=() + +INI_PROBE_SOURCES=( + "$VENDOR_DIR/src/emc/ini/inifile.cc" + "$WRAP_DIR/linuxcnc_ini_probe.cpp" +) + +STATE_PROBE_SOURCES=( + "$WRAP_DIR/linuxcnc_interp_state_probe.cpp" +) + +INTERP_CORE_SOURCES=( + "$VENDOR_DIR/src/emc/rs274ngc/modal_state.cc" + "$VENDOR_DIR/src/emc/rs274ngc/interp_array.cc" + "$VENDOR_DIR/src/emc/rs274ngc/interp_internal.cc" + "$VENDOR_DIR/src/emc/rs274ngc/interp_read.cc" + "$VENDOR_DIR/src/emc/rs274ngc/interp_check.cc" + "$VENDOR_DIR/src/emc/rs274ngc/interp_arc.cc" + "$VENDOR_DIR/src/emc/rs274ngc/interp_inverse.cc" + "$VENDOR_DIR/src/emc/rs274ngc/interp_execute.cc" + "$VENDOR_DIR/src/emc/rs274ngc/interp_convert.cc" + "$VENDOR_DIR/src/emc/rs274ngc/interp_cycles.cc" + "$VENDOR_DIR/src/emc/rs274ngc/interp_g7x.cc" + "$VENDOR_DIR/src/emc/rs274ngc/interp_queue.cc" + "$VENDOR_DIR/src/emc/rs274ngc/interp_find.cc" + "$VENDOR_DIR/src/emc/rs274ngc/interp_namedparams.cc" + "$VENDOR_DIR/src/emc/rs274ngc/interp_write.cc" + "$VENDOR_DIR/src/emc/rs274ngc/interp_o_word.cc" + "$VENDOR_DIR/src/emc/rs274ngc/rs274ngc_pre.cc" + "$WRAP_DIR/linuxcnc_hal_adapter.cpp" + "$WRAP_DIR/linuxcnc_interp_edge_stubs.cpp" + "$WRAP_DIR/linuxcnc_runtime_state_stubs.cpp" + "$WRAP_DIR/linuxcnc_tool_adapter.cpp" + "$WRAP_DIR/linuxcnc_interp_minimal_runtime.cpp" + "$VENDOR_DIR/src/emc/ini/inifile.cc" +) + +NAMEDPARAM_SOURCES=( + "${INTERP_CORE_SOURCES[@]}" + "$WRAP_DIR/linuxcnc_namedparam_harness.cpp" +) + +MINIMAL_SOURCES=( + "${INTERP_CORE_SOURCES[@]}" + "$WRAP_DIR/linuxcnc_interp_minimal_harness.cpp" +) + +build_binary_target \ + linuxcnc_ini_probe \ "$BUILD_DIR/linuxcnc_ini_probe" \ + COMMON_FLAGS \ + INI_PROBE_SOURCES \ + NO_LINK_FLAGS \ + -lfmt + +build_binary_target \ + linuxcnc_interp_state_probe \ "$BUILD_DIR/linuxcnc_interp_state_probe" \ - "$BUILD_DIR/linuxcnc_interp_state_probe.exitcode" \ - "$BUILD_DIR/linuxcnc_interp_state_probe.stdout.log" \ - "$BUILD_DIR/linuxcnc_interp_state_probe.stderr.log" \ + COMMON_FLAGS \ + STATE_PROBE_SOURCES \ + NO_LINK_FLAGS + +build_binary_target \ + linuxcnc_namedparam_harness \ "$BUILD_DIR/linuxcnc_namedparam_harness" \ - "$BUILD_DIR/linuxcnc_namedparam_harness.exitcode" \ - "$BUILD_DIR/linuxcnc_namedparam_harness.stdout.log" \ - "$BUILD_DIR/linuxcnc_namedparam_harness.stderr.log" \ + MINIMAL_FLAGS \ + NAMEDPARAM_SOURCES \ + MINIMAL_LINK_FLAGS \ + -lfmt + +if [[ "$(tr -d '[:space:]' < "$BUILD_DIR/linuxcnc_namedparam_harness.exitcode")" == "0" ]]; then + set +e + "$BUILD_DIR/linuxcnc_namedparam_harness" "$NAMEDPARAM_INI_FIXTURE" \ + >"$BUILD_DIR/linuxcnc_namedparam_harness.run.stdout.log" \ + 2>"$BUILD_DIR/linuxcnc_namedparam_harness.run.stderr.log" + NAMEDPARAM_RUN_RC=$? + set -e + echo "$NAMEDPARAM_RUN_RC" > "$BUILD_DIR/linuxcnc_namedparam_harness.run.exitcode" +else + rm -f \ + "$BUILD_DIR/linuxcnc_namedparam_harness.run.exitcode" \ + "$BUILD_DIR/linuxcnc_namedparam_harness.run.stdout.log" \ + "$BUILD_DIR/linuxcnc_namedparam_harness.run.stderr.log" +fi + +build_binary_target \ + linuxcnc_interp_minimal_harness \ "$BUILD_DIR/linuxcnc_interp_minimal_harness" \ - "$BUILD_DIR/linuxcnc_interp_minimal_harness.exitcode" \ - "$BUILD_DIR/linuxcnc_interp_minimal_harness.stdout.log" \ - "$BUILD_DIR/linuxcnc_interp_minimal_harness.stderr.log" \ - "$BUILD_DIR/linuxcnc_interp_minimal_harness.run.exitcode" \ - "$BUILD_DIR/linuxcnc_interp_minimal_harness.run.stdout.log" \ - "$BUILD_DIR/linuxcnc_interp_minimal_harness.run.stderr.log" \ - "$BUILD_DIR/linuxcnc_rs274_compile_probe.o" \ - "$BUILD_DIR/linuxcnc_rs274_compile_probe.exitcode" \ - "$BUILD_DIR/linuxcnc_rs274_compile_probe.stdout.log" \ - "$BUILD_DIR/linuxcnc_rs274_compile_probe.stderr.log" \ - "$BUILD_DIR/linuxcnc_interp_convert_source_probe.o" \ - "$BUILD_DIR/linuxcnc_interp_convert_source_probe.exitcode" \ - "$BUILD_DIR/linuxcnc_interp_convert_source_probe.stdout.log" \ - "$BUILD_DIR/linuxcnc_interp_convert_source_probe.stderr.log" + MINIMAL_FLAGS \ + MINIMAL_SOURCES \ + MINIMAL_LINK_FLAGS \ + -lfmt -g++ -std=c++20 -O2 \ - -D_GNU_SOURCE \ - -DM_PI=3.14159265358979323846 \ - -DOBJECT_FWD_DWA2002724_HPP \ - -I"$SHIM_DIR" \ - -I"$INCLUDE_DIR" \ - -I"$VENDOR_DIR/src" \ - -I"$VENDOR_DIR/src/rtapi" \ - -I"$VENDOR_DIR/src/emc" \ - -I"$VENDOR_DIR/src/emc/nml_intf" \ - -I"$VENDOR_DIR/src/emc/motion" \ - -I"$VENDOR_DIR/src/libnml/posemath" \ - "$VENDOR_DIR/src/emc/ini/inifile.cc" \ - "$WRAP_DIR/linuxcnc_ini_probe.cpp" \ - -lfmt \ - -o "$BUILD_DIR/linuxcnc_ini_probe" - -set +e -g++ -std=c++20 -O2 \ - -D_GNU_SOURCE \ - -DM_PI=3.14159265358979323846 \ - -DOBJECT_FWD_DWA2002724_HPP \ - -I"$SHIM_DIR" \ - -I"$INCLUDE_DIR" \ - -I"$VENDOR_DIR/src" \ - -I"$VENDOR_DIR/src/rtapi" \ - -I"$VENDOR_DIR/src/emc" \ - -I"$VENDOR_DIR/src/emc/nml_intf" \ - -I"$VENDOR_DIR/src/emc/motion" \ - -I"$VENDOR_DIR/src/libnml/posemath" \ - "$WRAP_DIR/linuxcnc_interp_state_probe.cpp" \ - -o "$BUILD_DIR/linuxcnc_interp_state_probe" \ - >"$BUILD_DIR/linuxcnc_interp_state_probe.stdout.log" \ - 2>"$BUILD_DIR/linuxcnc_interp_state_probe.stderr.log" -STATE_RC=$? -set -e - -echo "$STATE_RC" > "$BUILD_DIR/linuxcnc_interp_state_probe.exitcode" - -set +e -g++ -std=c++20 -O2 \ - -D_GNU_SOURCE \ - -DM_PI=3.14159265358979323846 \ - -DOBJECT_FWD_DWA2002724_HPP \ - -I"$SHIM_DIR" \ - -I"$INCLUDE_DIR" \ - -I"$VENDOR_DIR/src" \ - -I"$VENDOR_DIR/src/rtapi" \ - -I"$VENDOR_DIR/src/emc" \ - -I"$VENDOR_DIR/src/emc/nml_intf" \ - -I"$VENDOR_DIR/src/emc/motion" \ - -I"$VENDOR_DIR/src/libnml/posemath" \ - "$VENDOR_DIR/src/emc/rs274ngc/modal_state.cc" \ - "$WRAP_DIR/linuxcnc_runtime_state_stubs.cpp" \ - "$WRAP_DIR/linuxcnc_namedparam_harness.cpp" \ - "$VENDOR_DIR/src/emc/ini/inifile.cc" \ - -lfmt \ - -o "$BUILD_DIR/linuxcnc_namedparam_harness" \ - >"$BUILD_DIR/linuxcnc_namedparam_harness.stdout.log" \ - 2>"$BUILD_DIR/linuxcnc_namedparam_harness.stderr.log" -NAMEDPARAM_RC=$? -set -e - -echo "$NAMEDPARAM_RC" > "$BUILD_DIR/linuxcnc_namedparam_harness.exitcode" - -set +e -g++ -std=c++20 -O2 -ffunction-sections -fdata-sections \ - -Wl,--gc-sections \ - -D_GNU_SOURCE \ - -DM_PI=3.14159265358979323846 \ - -DOBJECT_FWD_DWA2002724_HPP \ - -I"$SHIM_DIR" \ - -I"$INCLUDE_DIR" \ - -I"$VENDOR_DIR/src" \ - -I"$VENDOR_DIR/src/rtapi" \ - -I"$VENDOR_DIR/src/emc" \ - -I"$VENDOR_DIR/src/emc/nml_intf" \ - -I"$VENDOR_DIR/src/emc/motion" \ - -I"$VENDOR_DIR/src/libnml/posemath" \ - "$VENDOR_DIR/src/emc/rs274ngc/modal_state.cc" \ - "$VENDOR_DIR/src/emc/rs274ngc/interp_array.cc" \ - "$VENDOR_DIR/src/emc/rs274ngc/interp_internal.cc" \ - "$VENDOR_DIR/src/emc/rs274ngc/interp_read.cc" \ - "$VENDOR_DIR/src/emc/rs274ngc/interp_check.cc" \ - "$VENDOR_DIR/src/emc/rs274ngc/interp_arc.cc" \ - "$VENDOR_DIR/src/emc/rs274ngc/interp_inverse.cc" \ - "$VENDOR_DIR/src/emc/rs274ngc/interp_execute.cc" \ - "$VENDOR_DIR/src/emc/rs274ngc/interp_convert.cc" \ - "$VENDOR_DIR/src/emc/rs274ngc/interp_cycles.cc" \ - "$VENDOR_DIR/src/emc/rs274ngc/interp_g7x.cc" \ - "$VENDOR_DIR/src/emc/rs274ngc/interp_queue.cc" \ - "$VENDOR_DIR/src/emc/rs274ngc/interp_find.cc" \ - "$VENDOR_DIR/src/emc/rs274ngc/interp_write.cc" \ - "$WRAP_DIR/linuxcnc_runtime_state_stubs.cpp" \ - "$WRAP_DIR/linuxcnc_interp_minimal_runtime.cpp" \ - "$WRAP_DIR/linuxcnc_interp_minimal_harness.cpp" \ - -lfmt \ - -o "$BUILD_DIR/linuxcnc_interp_minimal_harness" \ - >"$BUILD_DIR/linuxcnc_interp_minimal_harness.stdout.log" \ - 2>"$BUILD_DIR/linuxcnc_interp_minimal_harness.stderr.log" -INTERP_MIN_RC=$? -set -e - -echo "$INTERP_MIN_RC" > "$BUILD_DIR/linuxcnc_interp_minimal_harness.exitcode" - -if [[ "$INTERP_MIN_RC" -eq 0 ]]; then +if [[ "$(tr -d '[:space:]' < "$BUILD_DIR/linuxcnc_interp_minimal_harness.exitcode")" == "0" ]]; then set +e "$BUILD_DIR/linuxcnc_interp_minimal_harness" "$MINIMAL_GCODE_FIXTURE" \ >"$BUILD_DIR/linuxcnc_interp_minimal_harness.run.stdout.log" \ @@ -150,49 +341,23 @@ if [[ "$INTERP_MIN_RC" -eq 0 ]]; then INTERP_MIN_RUN_RC=$? set -e echo "$INTERP_MIN_RUN_RC" > "$BUILD_DIR/linuxcnc_interp_minimal_harness.run.exitcode" +else + rm -f \ + "$BUILD_DIR/linuxcnc_interp_minimal_harness.run.exitcode" \ + "$BUILD_DIR/linuxcnc_interp_minimal_harness.run.stdout.log" \ + "$BUILD_DIR/linuxcnc_interp_minimal_harness.run.stderr.log" fi -set +e -g++ -std=c++20 -O2 \ - -D_GNU_SOURCE \ - -DM_PI=3.14159265358979323846 \ - -DOBJECT_FWD_DWA2002724_HPP \ - -I"$SHIM_DIR" \ - -I"$INCLUDE_DIR" \ - -I"$VENDOR_DIR/src" \ - -I"$VENDOR_DIR/src/rtapi" \ - -I"$VENDOR_DIR/src/emc" \ - -I"$VENDOR_DIR/src/emc/nml_intf" \ - -I"$VENDOR_DIR/src/emc/motion" \ - -I"$VENDOR_DIR/src/libnml/posemath" \ - -c "$WRAP_DIR/linuxcnc_rs274_compile_probe.cpp" \ - -o "$BUILD_DIR/linuxcnc_rs274_compile_probe.o" \ - >"$BUILD_DIR/linuxcnc_rs274_compile_probe.stdout.log" \ - 2>"$BUILD_DIR/linuxcnc_rs274_compile_probe.stderr.log" -RS274_RC=$? -set -e +build_object_target \ + linuxcnc_rs274_compile_probe \ + "$BUILD_DIR/linuxcnc_rs274_compile_probe.o" \ + "$WRAP_DIR/linuxcnc_rs274_compile_probe.cpp" \ + COMMON_FLAGS -echo "$RS274_RC" > "$BUILD_DIR/linuxcnc_rs274_compile_probe.exitcode" +build_object_target \ + linuxcnc_interp_convert_source_probe \ + "$BUILD_DIR/linuxcnc_interp_convert_source_probe.o" \ + "$VENDOR_DIR/src/emc/rs274ngc/interp_convert.cc" \ + COMMON_FLAGS -set +e -g++ -std=c++20 -O2 \ - -D_GNU_SOURCE \ - -DM_PI=3.14159265358979323846 \ - -DOBJECT_FWD_DWA2002724_HPP \ - -I"$SHIM_DIR" \ - -I"$INCLUDE_DIR" \ - -I"$VENDOR_DIR/src" \ - -I"$VENDOR_DIR/src/rtapi" \ - -I"$VENDOR_DIR/src/emc" \ - -I"$VENDOR_DIR/src/emc/nml_intf" \ - -I"$VENDOR_DIR/src/emc/motion" \ - -I"$VENDOR_DIR/src/libnml/posemath" \ - -c "$VENDOR_DIR/src/emc/rs274ngc/interp_convert.cc" \ - -o "$BUILD_DIR/linuxcnc_interp_convert_source_probe.o" \ - >"$BUILD_DIR/linuxcnc_interp_convert_source_probe.stdout.log" \ - 2>"$BUILD_DIR/linuxcnc_interp_convert_source_probe.stderr.log" -CONVERT_SOURCE_RC=$? -set -e - -echo "$CONVERT_SOURCE_RC" > "$BUILD_DIR/linuxcnc_interp_convert_source_probe.exitcode" echo "native probes complete"