新增解释器核心WASM验证
结论:已建立基于LinuxCNC解释器源码的最小WASM核心构建和minimal_linear夹具验证,并接入host smoke。
This commit is contained in:
158
wasm-port/runtime/core/linuxcnc_wrap/linuxcnc_interp_wasm.cpp
Normal file
158
wasm-port/runtime/core/linuxcnc_wrap/linuxcnc_interp_wasm.cpp
Normal file
@@ -0,0 +1,158 @@
|
||||
#define private public
|
||||
#include "emc/rs274ngc/rs274ngc_interp.hh"
|
||||
#undef private
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <emscripten/emscripten.h>
|
||||
|
||||
#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;
|
||||
interp._setup.feed_mode = FEED_MODE::UNITS_PER_MINUTE;
|
||||
interp._setup.plane = CANON_PLANE::XY;
|
||||
interp._setup.motion_mode = G_0;
|
||||
interp._setup.percent_flag = false;
|
||||
interp._setup.sequence_number = 0;
|
||||
interp._setup.parameter_occurrence = 0;
|
||||
interp._setup.num_spindles = 1;
|
||||
interp._setup.feature_set = FEATURE_INI_VARS | FEATURE_HAL_PIN_VARS;
|
||||
interp._setup.parameter_g73_peck_clearance = 1.0;
|
||||
interp._setup.parameter_g83_peck_clearance = 1.0;
|
||||
interp._setup.parameters[5599] = 1.0;
|
||||
interp.load_tool_table();
|
||||
std::memcpy(interp._readers, Interp::default_readers, sizeof(Interp::default_readers));
|
||||
}
|
||||
|
||||
std::vector<std::string> split_program_lines(const char *program_text)
|
||||
{
|
||||
std::vector<std::string> lines;
|
||||
std::istringstream input(program_text ? program_text : "");
|
||||
std::string line;
|
||||
while (std::getline(input, line)) {
|
||||
if (!line.empty()) {
|
||||
lines.push_back(line + "\n");
|
||||
}
|
||||
}
|
||||
return lines;
|
||||
}
|
||||
|
||||
char *copy_result(const std::string &result)
|
||||
{
|
||||
char *out = static_cast<char *>(std::malloc(result.size() + 1));
|
||||
if (!out) {
|
||||
return nullptr;
|
||||
}
|
||||
std::memcpy(out, result.c_str(), result.size() + 1);
|
||||
return out;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
extern "C" {
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE
|
||||
char *lcinterp_run_program(const char *program_text)
|
||||
{
|
||||
Interp interp;
|
||||
standalone::reset_canon_events();
|
||||
initialize_minimal_interp(interp);
|
||||
|
||||
const std::vector<std::string> program = split_program_lines(program_text);
|
||||
std::ostringstream output;
|
||||
if (program.empty()) {
|
||||
output << "error=empty fixture\n";
|
||||
return copy_result(output.str());
|
||||
}
|
||||
|
||||
for (std::size_t idx = 0; idx < program.size(); ++idx) {
|
||||
interp._setup.sequence_number = static_cast<int>(idx + 1);
|
||||
const int execute_rc = interp.execute(program[idx].c_str());
|
||||
output << "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));
|
||||
output << "error_text=" << error_buf << "\n";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto &event : standalone::canon_events()) {
|
||||
output << "canon_event=" << event << "\n";
|
||||
}
|
||||
return copy_result(output.str());
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE
|
||||
void lcinterp_free_string(char *value)
|
||||
{
|
||||
std::free(value);
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
@@ -0,0 +1,47 @@
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
||||
#include <wordexp.h>
|
||||
|
||||
extern "C" {
|
||||
|
||||
int wordexp(const char *words, wordexp_t *pwordexp, int)
|
||||
{
|
||||
if (!words || !pwordexp) {
|
||||
return WRDE_BADCHAR;
|
||||
}
|
||||
|
||||
char **wordv = static_cast<char **>(std::calloc(2, sizeof(char *)));
|
||||
if (!wordv) {
|
||||
return WRDE_NOSPACE;
|
||||
}
|
||||
|
||||
wordv[0] = static_cast<char *>(std::malloc(std::strlen(words) + 1));
|
||||
if (!wordv[0]) {
|
||||
std::free(wordv);
|
||||
return WRDE_NOSPACE;
|
||||
}
|
||||
|
||||
std::strcpy(wordv[0], words);
|
||||
pwordexp->we_wordc = 1;
|
||||
pwordexp->we_wordv = wordv;
|
||||
pwordexp->we_offs = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void wordfree(wordexp_t *pwordexp)
|
||||
{
|
||||
if (!pwordexp || !pwordexp->we_wordv) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (size_t index = 0; index < pwordexp->we_wordc; ++index) {
|
||||
std::free(pwordexp->we_wordv[index]);
|
||||
}
|
||||
std::free(pwordexp->we_wordv);
|
||||
pwordexp->we_wordc = 0;
|
||||
pwordexp->we_wordv = nullptr;
|
||||
pwordexp->we_offs = 0;
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
14
wasm-port/runtime/core/shims/boost/noncopyable.hpp
Normal file
14
wasm-port/runtime/core/shims/boost/noncopyable.hpp
Normal file
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
namespace boost {
|
||||
|
||||
class noncopyable {
|
||||
protected:
|
||||
noncopyable() = default;
|
||||
~noncopyable() = default;
|
||||
|
||||
noncopyable(const noncopyable &) = delete;
|
||||
noncopyable &operator=(const noncopyable &) = delete;
|
||||
};
|
||||
|
||||
} // namespace boost
|
||||
8
wasm-port/runtime/core/shims/linuxcnc_wasm_compat.hh
Normal file
8
wasm-port/runtime/core/shims/linuxcnc_wasm_compat.hh
Normal file
@@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <libgen.h>
|
||||
|
||||
inline char *basename(const char *path)
|
||||
{
|
||||
return ::basename(const_cast<char *>(path));
|
||||
}
|
||||
Reference in New Issue
Block a user