wasm-port: broaden native LinuxCNC interpreter probes

This commit is contained in:
2026-06-07 05:49:34 +08:00
parent 5025b0c1a1
commit eb261462c1
49 changed files with 1276 additions and 798 deletions

View File

@@ -0,0 +1,109 @@
#include "linuxcnc_hal_adapter.hh"
#include <string>
#include <unordered_map>
namespace {
struct HalEntry {
hal_type_t type = HAL_TYPE_UNINITIALIZED;
hal_data_u value{};
bool connected = true;
};
std::unordered_map<std::string, HalEntry> &pins()
{
static std::unordered_map<std::string, HalEntry> values;
return values;
}
std::unordered_map<std::string, HalEntry> &signals()
{
static std::unordered_map<std::string, HalEntry> values;
return values;
}
std::unordered_map<std::string, HalEntry> &params()
{
static std::unordered_map<std::string, HalEntry> values;
return values;
}
std::unordered_map<std::string, HalEntry> &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<std::string, HalEntry> &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);
}

View File

@@ -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

View File

@@ -0,0 +1,49 @@
#include <string>
#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; }

View File

@@ -9,11 +9,67 @@
#include <vector>
#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<int>(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";

View File

@@ -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<size_t>(_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;
}

View File

@@ -4,338 +4,104 @@
#include <cstdlib>
#include <iostream>
#include <string>
#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<int>(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<char>(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;
}

View File

@@ -5,8 +5,7 @@
#include <unordered_set>
#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<std::string> stringtable;
@@ -45,6 +45,7 @@ void context_struct::clear()
{
new (this) context_struct();
}
#endif
setup::setup()
: AA_axis_offset(0.0),

View File

@@ -0,0 +1,101 @@
#include "linuxcnc_tool_adapter.hh"
#include <array>
namespace {
std::array<CANON_TOOL_TABLE, CANON_POCKETS_MAX> &tool_table()
{
static std::array<CANON_TOOL_TABLE, CANON_POCKETS_MAX> 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

View File

@@ -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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,9 +1,88 @@
#pragma once
#include <string>
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 <typename T>
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 <typename T>
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 <typename T>
object import(const T &) { return object(); }
template <typename T>
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

View File

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

View File

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

View File

@@ -0,0 +1,30 @@
#pragma once
#include <stdbool.h>
#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 **);

View File

@@ -0,0 +1,16 @@
#pragma once
#include <string>
#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();

View File

@@ -2,12 +2,37 @@
#include <string>
#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;
};

View File

@@ -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;
}