#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#define BOOST_PYTHON_MAX_ARITY 4
#include "python_plugin.hh"
#include <boost/python/dict.hpp>
#include <boost/python/extract.hpp>
#include <boost/python/list.hpp>
#include <boost/python/tuple.hpp>
namespace bp = boost::python;
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sstream>
#include <map>
#include "rs274ngc.hh"
#include "rs274ngc_return.hh"
#include "interp_internal.hh"
#include "rs274ngc_interp.hh"
#include "inifile.hh"
#include "hal.h"
#include "hal/hal_priv.h"
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_VALUE,
NP_CALL_LEVEL,
NP_REMAP_LEVEL,
NP_SELECTED_TOOL,
NP_VALUE_RETURNED,
NP_TASK,
};
int Interp::read_named_parameter(
char *line, int *counter, double *double_ptr, double *parameters, bool check_exists) {
static char name[] = "read_named_parameter";
char paramNameBuf[LINELEN+1];
int exists;
double value;
parameter_map_iterator pi;
CHKS((line[*counter] != '<'),
NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED);
CHP(read_name(line, counter, paramNameBuf));
CHP(find_named_param(paramNameBuf, &exists, &value));
if (check_exists) {
*double_ptr = exists ? 1.0 : 0.0;
return INTERP_OK;
}
if (exists) {
*double_ptr = value;
return INTERP_OK;
} else {
if (_setup.defining_sub)
return INTERP_OK;
logNP("%s: referencing undefined named parameter '%s' level=%d",
name, paramNameBuf, (paramNameBuf[0] == '_') ? 0 : _setup.call_level);
ERS(_("Named parameter #<%s> not defined"), paramNameBuf);
}
return INTERP_OK;
}
int Interp::fetch_ini_param( const char *nameBuf, int *status, double *value)
{
char *s;
*status = 0;
int n = strlen(nameBuf);
if ((n > 7) &&
((s = (char *) strchr(&nameBuf[6],']')) != NULL)) {
IniFile inifile;
const char *iniFileName;
int retval;
int closeBracket = s - nameBuf;
if ((iniFileName = getenv("INI_FILE_NAME")) == NULL) {
logNP("warning: referencing ini parameter '%s': no ini file",nameBuf);
*status = 0;
return INTERP_OK;
}
if (!inifile.Open(iniFileName)) {
*status = 0;
ERS(_("cant open ini file '%s'"), iniFileName);
}
char capName[LINELEN];
strncpy(capName, nameBuf, n);
capName[n] = '\0';
for (char *p = capName; *p != 0; p++)
*p = toupper(*p);
capName[closeBracket] = '\0';
if ((retval = inifile.Find( value, &capName[closeBracket+1], &capName[5])) == 0) {
*status = 1;
inifile.Close();
} else {
inifile.Close();
*status = 0;
ERS(_("Named ini parameter #<%s> not found in inifile '%s': error=0x%x"),
nameBuf, iniFileName, retval);
}
}
return INTERP_OK;
}
int Interp::fetch_hal_param( const char *nameBuf, int *status, double *value)
{
static int comp_id;
int retval;
int type = 0;
hal_data_u* ptr;
char hal_name[LINELEN];
*status = 0;
if (!comp_id) {
char hal_comp[LINELEN];
sprintf(hal_comp,"interp%d",getpid());
comp_id = hal_init(hal_comp); CHKS(comp_id < 0,_("fetch_hal_param: hal_init(%s): %d"), hal_comp,comp_id);
CHKS((retval = hal_ready(comp_id)), _("fetch_hal_param: hal_ready(): %d"),retval);
}
char *s;
int n = strlen(nameBuf);
if ((n > 6) &&
((s = (char *) strchr(&nameBuf[5],']')) != NULL)) {
int closeBracket = s - nameBuf;
hal_pin_t *pin;
hal_sig_t *sig;
hal_param_t *param;
strncpy(hal_name, &nameBuf[5], closeBracket);
hal_name[closeBracket - 5] = '\0';
if (nameBuf[closeBracket + 1]) {
logOword("%s: trailing garbage after closing bracket", hal_name);
*status = 0;
ERS("%s: trailing garbage after closing bracket", nameBuf);
}
if ((pin = halpr_find_pin_by_name(hal_name)) != NULL) {
if (pin && !pin->signal) {
logOword("%s: no signal connected", hal_name);
}
type = pin->type;
if (pin->signal != 0) {
sig = (hal_sig_t *) SHMPTR(pin->signal);
ptr = (hal_data_u *) SHMPTR(sig->data_ptr);
} else {
ptr = (hal_data_u *) &(pin->dummysig);
}
goto assign;
}
if ((sig = halpr_find_sig_by_name(hal_name)) != NULL) {
if (!sig->writers)
logOword("%s: signal has no writer", hal_name);
type = sig->type;
ptr = (hal_data_u *) SHMPTR(sig->data_ptr);
goto assign;
}
if ((param = halpr_find_param_by_name(hal_name)) != NULL) {
type = param->type;
ptr = (hal_data_u *) SHMPTR(param->data_ptr);
goto assign;
}
*status = 0;
ERS("Named hal parameter #<%s> not found", nameBuf);
}
return INTERP_OK;
assign:
switch (type) {
case HAL_BIT: *value = (double) (ptr->b); break;
case HAL_U32: *value = (double) (ptr->u); break;
case HAL_S32: *value = (double) (ptr->s); break;
case HAL_FLOAT: *value = (double) (ptr->f); break;
}
logOword("%s: value=%f", hal_name, *value);
*status = 1;
return INTERP_OK;
}
int Interp::find_named_param(
const char *nameBuf, int *status, double *value )
{
context_pointer frame;
parameter_map_iterator pi;
int level;
level = (nameBuf[0] == '_') ? 0 : _setup.call_level; frame = &_setup.sub_context[level];
*status = 0;
pi = frame->named_params.find(nameBuf);
if (pi == frame->named_params.end()) { int exists = 0;
double inivalue;
if (FEATURE(INI_VARS) && (strncasecmp(nameBuf,"_ini[",5) == 0)) {
fetch_ini_param(nameBuf, &exists, &inivalue);
if (exists) {
logNP("parameter '%s' retrieved from INI: %f",nameBuf,inivalue);
*value = inivalue;
*status = 1;
parameter_value param; param.value = inivalue;
param.attr = PA_GLOBAL | PA_READONLY | PA_FROM_INI;
_setup.sub_context[0].named_params[strstore(nameBuf)] = param;
return INTERP_OK;
}
}
if (FEATURE(HAL_PIN_VARS) && (strncasecmp(nameBuf,"_hal[",5) == 0)) {
fetch_hal_param(nameBuf, &exists, &inivalue);
if (exists) {
logNP("parameter '%s' retrieved from HAL: %f",nameBuf,inivalue);
*value = inivalue;
*status = 1;
return INTERP_OK;
}
}
*value = 0.0;
*status = 0;
} else {
parameter_pointer pv = &pi->second;
if (pv->attr & PA_UNSET)
logNP("warning: referencing unset variable '%s'",nameBuf);
if (pv->attr & PA_USE_LOOKUP) {
CHP(lookup_named_param(nameBuf, pv->value, value));
*status = 1;
} else if (pv->attr & PA_PYTHON) {
bp::object retval, tupleargs, kwargs;
bp::list plist;
plist.append(*_setup.pythis); tupleargs = bp::tuple(plist);
kwargs = bp::dict();
python_plugin->call(NAMEDPARAMS_MODULE, nameBuf, tupleargs, kwargs, retval);
CHKS(python_plugin->plugin_status() == PLUGIN_EXCEPTION,
"named param - pycall(%s):\n%s", nameBuf,
python_plugin->last_exception().c_str());
CHKS(retval.ptr() == Py_None, "Python namedparams.%s returns no value", nameBuf);
if (PyString_Check(retval.ptr())) {
*status = 0;
char *msg = bp::extract<char *>(retval);
ERS("%s", msg);
}
if (PyInt_Check(retval.ptr())) { *value = (double) bp::extract<int>(retval);
*status = 1;
return INTERP_OK;
}
if (PyFloat_Check(retval.ptr())) {
*value = bp::extract<double>(retval);
*status = 1;
return INTERP_OK;
}
*status = 0;
PyObject *res_str = PyObject_Str(retval.ptr());
Py_XDECREF(res_str);
ERS("Python call %s.%s returned '%s' - expected double, int or string, got %s",
NAMEDPARAMS_MODULE, nameBuf,
PyString_AsString(res_str),
retval.ptr()->ob_type->tp_name);
} else {
*value = pv->value;
*status = 1;
}
}
return INTERP_OK;
}
int Interp::store_named_param(setup_pointer settings,
const char *nameBuf, double value, int override_readonly )
{
context_pointer frame;
int level;
parameter_map_iterator pi;
level = (nameBuf[0] == '_') ? 0 : _setup.call_level; frame = &settings->sub_context[level];
pi = frame->named_params.find(nameBuf);
if (pi == frame->named_params.end()) {
ERS(_("Internal error: Could not assign #<%s>"), nameBuf);
} else {
parameter_pointer pv = &pi->second;
CHKS(((pv->attr & PA_GLOBAL) && level),
"BUG: variable '%s' marked global, but assigned at level %d", nameBuf, level);
if ((pv->attr & PA_READONLY) && !override_readonly) {
ERS(_("Cannot assign to read-only parameter #<%s>"), nameBuf);
} else {
pv->value = value;
pv->attr &= ~PA_UNSET;
logNP("store_named_parameter: level[%d] %s value=%lf",
level, nameBuf, value);
}
}
return INTERP_OK;
}
int Interp::add_named_param(
const char *nameBuf, int attr) {
static char name[] = "add_named_param";
int findStatus;
double value;
int level;
parameter_value param;
CHP(find_named_param(nameBuf, &findStatus, &value));
if (findStatus) {
logNP("%s: parameter:|%s| already exists", name, nameBuf);
return INTERP_OK;
}
attr |= PA_UNSET;
if (nameBuf[0] != '_') { level = _setup.call_level;
} else {
level = 0; attr |= PA_GLOBAL;
}
param.value = 0.0;
param.attr = attr;
_setup.sub_context[level].named_params[strstore(nameBuf)] = param;
return INTERP_OK;
}
int Interp::free_named_parameters(context_pointer frame)
{
frame->named_params.clear();
return INTERP_OK;
}
int Interp::init_readonly_param(
const char *nameBuf, double value, int attr) {
CHKS( add_named_param((char *) nameBuf, PA_READONLY|attr),
"adding r/o '%s'", nameBuf);
CHKS(store_named_param(&_setup, (char *) nameBuf, value, OVERRIDE_READONLY),
"storing r/o '%s' %f", nameBuf, value);
return INTERP_OK;
}
int Interp::lookup_named_param(const char *nameBuf,
double index,
double *value)
{
int cmd = round_to_int(index);
switch (cmd) {
case NP_LINE: *value = _setup.sequence_number;
break;
case NP_MOTION_MODE: *value = _setup.motion_mode;
break;
case NP_PLANE: switch(_setup.plane) {
case CANON_PLANE_XY:
*value = G_17;
break;
case CANON_PLANE_XZ:
*value = G_18;
break;
case CANON_PLANE_YZ:
*value = G_19;
break;
case CANON_PLANE_UV:
*value = G_17_1;
break;
case CANON_PLANE_UW:
*value = G_18_1;
break;
case CANON_PLANE_VW:
*value = G_19_1;
break;
}
break;
case NP_CCOMP: *value =
(_setup.cutter_comp_side == RIGHT) ? G_42 :
(_setup.cutter_comp_side == LEFT) ? G_41 : G_40;
break;
case NP_METRIC: *value = (_setup.length_units == CANON_UNITS_MM);
break;
case NP_IMPERIAL: *value = (_setup.length_units == CANON_UNITS_INCHES);
break;
case NP_ABSOLUTE: *value = (_setup.distance_mode == MODE_ABSOLUTE);
break;
case NP_INCREMENTAL: *value = (_setup.distance_mode == MODE_INCREMENTAL);
break;
case NP_INVERSE_TIME: *value = (_setup.feed_mode == INVERSE_TIME);
break;
case NP_UNITS_PER_MINUTE: *value = (_setup.feed_mode == UNITS_PER_MINUTE);
break;
case NP_UNITS_PER_REV: *value = (_setup.feed_mode == UNITS_PER_REVOLUTION);
break;
case NP_COORD_SYSTEM: *value =
(_setup.origin_index < 7) ? (530 + (10 * _setup.origin_index)) :
(584 + _setup.origin_index);
break;
case NP_TOOL_OFFSET: *value = (_setup.tool_offset.tran.x || _setup.tool_offset.tran.y || _setup.tool_offset.tran.z ||
_setup.tool_offset.a || _setup.tool_offset.b || _setup.tool_offset.c ||
_setup.tool_offset.u || _setup.tool_offset.v || _setup.tool_offset.w) ;
break;
case NP_RETRACT_R_PLANE: *value = (_setup.retract_mode == R_PLANE);
break;
case NP_RETRACT_OLD_Z: *value = (_setup.retract_mode == OLD_Z);
break;
case NP_SPINDLE_RPM_MODE: *value = (_setup.spindle_mode[0] == CONSTANT_RPM);
break;
case NP_SPINDLE_CSS_MODE: *value = (_setup.spindle_mode[0] == CONSTANT_SURFACE);
break;
case NP_IJK_ABSOLUTE_MODE: *value = (_setup.ijk_distance_mode == MODE_ABSOLUTE);
break;
case NP_LATHE_DIAMETER_MODE: *value = _setup.lathe_diameter_mode;
break;
case NP_LATHE_RADIUS_MODE: *value = (_setup.lathe_diameter_mode == 0);
break;
case NP_SPINDLE_ON: *value = (_setup.spindle_turning[0] != CANON_STOPPED);
break;
case NP_SPINDLE_CW: *value = (_setup.spindle_turning[0] == CANON_CLOCKWISE);
break;
case NP_MIST: *value = _setup.mist;
break;
case NP_FLOOD: *value = _setup.flood;
break;
case NP_SPEED_OVERRIDE: *value = _setup.speed_override[0];
break;
case NP_FEED_OVERRIDE: *value = _setup.feed_override;
break;
case NP_ADAPTIVE_FEED: *value = _setup.adaptive_feed;
break;
case NP_FEED_HOLD: *value = _setup.feed_hold;
break;
case NP_FEED: *value = _setup.feed_rate;
break;
case NP_RPM: *value = abs(_setup.speed[0]);
break;
case NP_CURRENT_TOOL:
*value = _setup.parameters[5400];
break;
case NP_SELECTED_POCKET:
*value = _setup.selected_pocket;
break;
case NP_CURRENT_POCKET:
*value = _setup.current_pocket;
break;
case NP_SELECTED_TOOL:
*value = _setup.selected_tool;
break;
case NP_X: *value = _setup.current_x;
break;
case NP_Y: *value = _setup.current_y;
break;
case NP_Z: *value = _setup.current_z;
break;
case NP_A: *value = _setup.AA_current;
break;
case NP_B: *value = _setup.BB_current;
break;
case NP_C: *value = _setup.CC_current;
break;
case NP_U: *value = _setup.u_current;
break;
case NP_V: *value = _setup.v_current;
break;
case NP_W: *value = _setup.w_current;
break;
case NP_VALUE:
*value = _setup.return_value;
break;
case NP_VALUE_RETURNED:
*value = _setup.value_returned;
break;
case NP_CALL_LEVEL:
*value = _setup.call_level;
break;
case NP_REMAP_LEVEL:
*value = _setup.remap_level;
break;
case NP_TASK:
extern int _task; *value = _task;
break;
default:
ERS(_("BUG: lookup_named_param(%s): unhandled index=%fn"),
nameBuf,index);
}
return INTERP_OK;
}
int Interp::init_python_predef_parameter(const char *name)
{
int exists = 0;
double value;
parameter_value param;
if (name[0] == '_') { find_named_param(name, &exists, &value);
if (exists) {
fprintf(stderr, "warning: redefining named parameter %s\n",name);
_setup.sub_context[0].named_params.erase(name);
}
param.value = 0.0;
param.attr = PA_READONLY|PA_PYTHON|PA_GLOBAL;
_setup.sub_context[0].named_params[strstore(name)] = param;
}
return INTERP_OK;
}
int Interp::init_named_parameters()
{
const char *pkgversion = PACKAGE_VERSION; const char *version_major = "_vmajor"; const char *version_minor = "_vminor"; double vmajor=0.0, vminor=0.0;
sscanf(pkgversion, "%lf%lf", &vmajor, &vminor);
init_readonly_param(version_major,vmajor,0);
init_readonly_param(version_minor,vminor,0);
init_readonly_param("_line", NP_LINE, PA_USE_LOOKUP);
init_readonly_param("_motion_mode", NP_MOTION_MODE, PA_USE_LOOKUP);
init_readonly_param("_plane", NP_PLANE, PA_USE_LOOKUP);
init_readonly_param("_ccomp", NP_CCOMP, PA_USE_LOOKUP);
init_readonly_param("_metric", NP_METRIC, PA_USE_LOOKUP);
init_readonly_param("_imperial", NP_IMPERIAL, PA_USE_LOOKUP);
init_readonly_param("_absolute", NP_ABSOLUTE, PA_USE_LOOKUP);
init_readonly_param("_incremental", NP_INCREMENTAL, PA_USE_LOOKUP);
init_readonly_param("_inverse_time", NP_INVERSE_TIME, PA_USE_LOOKUP);
init_readonly_param("_units_per_minute", NP_UNITS_PER_MINUTE, PA_USE_LOOKUP);
init_readonly_param("_units_per_rev", NP_UNITS_PER_REV, PA_USE_LOOKUP);
init_readonly_param("_coord_system", NP_COORD_SYSTEM, PA_USE_LOOKUP);
init_readonly_param("_tool_offset", NP_TOOL_OFFSET, PA_USE_LOOKUP);
init_readonly_param("_retract_r_plane", NP_RETRACT_R_PLANE, PA_USE_LOOKUP);
init_readonly_param("_retract_old_z", NP_RETRACT_OLD_Z, PA_USE_LOOKUP);
init_readonly_param("_spindle_rpm_mode", NP_SPINDLE_RPM_MODE, PA_USE_LOOKUP);
init_readonly_param("_spindle_css_mode", NP_SPINDLE_CSS_MODE, PA_USE_LOOKUP);
init_readonly_param("_ijk_absolute_mode", NP_IJK_ABSOLUTE_MODE, PA_USE_LOOKUP);
init_readonly_param("_lathe_diameter_mode", NP_LATHE_DIAMETER_MODE, PA_USE_LOOKUP);
init_readonly_param("_lathe_radius_mode", NP_LATHE_RADIUS_MODE, PA_USE_LOOKUP);
init_readonly_param("_spindle_on", NP_SPINDLE_ON, PA_USE_LOOKUP);
init_readonly_param("_spindle_cw", NP_SPINDLE_CW, PA_USE_LOOKUP);
init_readonly_param("_mist", NP_MIST, PA_USE_LOOKUP);
init_readonly_param("_flood", NP_FLOOD, PA_USE_LOOKUP);
init_readonly_param("_speed_override", NP_SPEED_OVERRIDE, PA_USE_LOOKUP);
init_readonly_param("_feed_override", NP_FEED_OVERRIDE, PA_USE_LOOKUP);
init_readonly_param("_adaptive_feed", NP_ADAPTIVE_FEED, PA_USE_LOOKUP);
init_readonly_param("_feed_hold", NP_FEED_HOLD, PA_USE_LOOKUP);
init_readonly_param("_feed", NP_FEED, PA_USE_LOOKUP);
init_readonly_param("_rpm", NP_RPM, PA_USE_LOOKUP);
init_readonly_param("_current_tool", NP_CURRENT_TOOL, PA_USE_LOOKUP);
init_readonly_param("_current_pocket", NP_CURRENT_POCKET, PA_USE_LOOKUP);
init_readonly_param("_selected_pocket", NP_SELECTED_POCKET, PA_USE_LOOKUP);
init_readonly_param("_selected_tool", NP_SELECTED_TOOL, PA_USE_LOOKUP);
init_readonly_param("_x", NP_X, PA_USE_LOOKUP);
init_readonly_param("_y", NP_Y, PA_USE_LOOKUP);
init_readonly_param("_z", NP_Z, PA_USE_LOOKUP);
init_readonly_param("_a", NP_A, PA_USE_LOOKUP);
init_readonly_param("_b", NP_B, PA_USE_LOOKUP);
init_readonly_param("_c", NP_C, PA_USE_LOOKUP);
init_readonly_param("_u", NP_U, PA_USE_LOOKUP);
init_readonly_param("_v", NP_V, PA_USE_LOOKUP);
init_readonly_param("_w", NP_W, PA_USE_LOOKUP);
init_readonly_param("_value", NP_VALUE, PA_USE_LOOKUP);
init_readonly_param("_value_returned", NP_VALUE_RETURNED, PA_USE_LOOKUP);
init_readonly_param("_task", NP_TASK, PA_USE_LOOKUP);
init_readonly_param("_call_level", NP_CALL_LEVEL, PA_USE_LOOKUP);
init_readonly_param("_remap_level", NP_REMAP_LEVEL, PA_USE_LOOKUP);
return INTERP_OK;
}