#include <math.h>
#include <float.h>
#include <string.h>
#include <stdlib.h>
#include <sys/wait.h>
#include "rcs.hh"
#include "rcs_print.hh"
#include "timer.hh"
#include "emc.hh"
#include "emc_nml.hh"
#include "emcglb.h"
#include "initool.hh"
#include "python_plugin.hh"
#include "taskclass.hh"
#define BOOST_PYTHON_MAX_ARITY 4
#include <boost/python/dict.hpp>
#include <boost/python/extract.hpp>
#include <boost/python/object.hpp>
#include <boost/python/tuple.hpp>
namespace bp = boost::python;
#define TASK_MODULE "task"
#define TASK_VAR "pytask"
#define PLUGIN_CALL "plugin_call"
extern PythonPlugin *python_plugin; #define PYUSABLE (((python_plugin) != NULL) && (python_plugin->usable()))
extern int return_int(const char *funcname, bp::object &retval);
Task *task_methods;
static RCS_CMD_CHANNEL *emcIoCommandBuffer = 0;
static RCS_STAT_CHANNEL *emcIoStatusBuffer = 0;
EMC_IO_STAT *emcIoStatus = 0;
static int emcIoCommandSerialNumber = 0;
static double EMCIO_BUFFER_GET_TIMEOUT = 5.0;
static int forceCommand(RCS_CMD_MSG *msg);
static int emcioNmlGet()
{
int retval = 0;
double start_time;
RCS_PRINT_DESTINATION_TYPE orig_dest;
if (emcIoCommandBuffer == 0) {
orig_dest = get_rcs_print_destination();
set_rcs_print_destination(RCS_PRINT_TO_NULL);
start_time = etime();
while (start_time - etime() < EMCIO_BUFFER_GET_TIMEOUT) {
emcIoCommandBuffer =
new RCS_CMD_CHANNEL(emcFormat, "toolCmd", "emc",
emc_nmlfile);
if (!emcIoCommandBuffer->valid()) {
delete emcIoCommandBuffer;
emcIoCommandBuffer = 0;
} else {
break;
}
esleep(0.1);
}
set_rcs_print_destination(orig_dest);
}
if (emcIoCommandBuffer == 0) {
emcIoCommandBuffer =
new RCS_CMD_CHANNEL(emcFormat, "toolCmd", "emc", emc_nmlfile);
if (!emcIoCommandBuffer->valid()) {
delete emcIoCommandBuffer;
emcIoCommandBuffer = 0;
retval = -1;
}
}
if (emcIoStatusBuffer == 0) {
orig_dest = get_rcs_print_destination();
set_rcs_print_destination(RCS_PRINT_TO_NULL);
start_time = etime();
while (start_time - etime() < EMCIO_BUFFER_GET_TIMEOUT) {
emcIoStatusBuffer =
new RCS_STAT_CHANNEL(emcFormat, "toolSts", "emc",
emc_nmlfile);
if (!emcIoStatusBuffer->valid()) {
delete emcIoStatusBuffer;
emcIoStatusBuffer = 0;
} else {
emcIoStatus =
(EMC_IO_STAT *) emcIoStatusBuffer->get_address();
emcIoCommandSerialNumber = emcIoStatus->echo_serial_number;
break;
}
esleep(0.1);
}
set_rcs_print_destination(orig_dest);
}
if (emcIoStatusBuffer == 0) {
emcIoStatusBuffer =
new RCS_STAT_CHANNEL(emcFormat, "toolSts", "emc", emc_nmlfile);
if (!emcIoStatusBuffer->valid()
|| EMC_IO_STAT_TYPE != emcIoStatusBuffer->peek()) {
delete emcIoStatusBuffer;
emcIoStatusBuffer = 0;
emcIoStatus = 0;
retval = -1;
} else {
emcIoStatus = (EMC_IO_STAT *) emcIoStatusBuffer->get_address();
emcIoCommandSerialNumber = emcIoStatus->echo_serial_number;
}
}
return retval;
}
static RCS_CMD_MSG *last_io_command = 0;
static long largest_io_command_size = 0;
static int sendCommand(RCS_CMD_MSG * msg)
{
if (0 == emcIoCommandBuffer) {
return -1;
}
if (0 == emcIoStatusBuffer || !emcIoStatusBuffer->valid()) {
return -1;
}
if (msg->type == EMC_TOOL_ABORT_TYPE) {
int rc = forceCommand(msg);
if (rc) {
rcs_print_error("forceCommand(EMC_TOOL_ABORT) returned %d\n", rc);
}
return 0;
}
double send_command_timeout = etime() + 5.0;
while (etime() < send_command_timeout) {
emcIoStatusBuffer->peek();
if (emcIoStatus->echo_serial_number != emcIoCommandSerialNumber ||
emcIoStatus->status == RCS_EXEC) {
esleep(0.001);
continue;
} else {
break;
}
}
if (emcIoStatus->echo_serial_number != emcIoCommandSerialNumber ||
emcIoStatus->status == RCS_EXEC) {
rcs_print_error
("Command to IO level (%s:%s) timed out waiting for last command done. \n",
emcSymbolLookup(msg->type), emcIoCommandBuffer->msg2str(msg));
rcs_print_error
("emcIoStatus->echo_serial_number=%d, emcIoCommandSerialNumber=%d, emcIoStatus->status=%d\n",
emcIoStatus->echo_serial_number, emcIoCommandSerialNumber,
emcIoStatus->status);
if (0 != last_io_command) {
rcs_print_error("Last command sent to IO level was (%s:%s)\n",
emcSymbolLookup(last_io_command->type),
emcIoCommandBuffer->msg2str(last_io_command));
}
return -1;
}
msg->serial_number = ++emcIoCommandSerialNumber;
if (0 != emcIoCommandBuffer->write(msg)) {
rcs_print_error("Failed to send command to IO level (%s:%s)\n",
emcSymbolLookup(msg->type),
emcIoCommandBuffer->msg2str(msg));
return -1;
}
if (largest_io_command_size < msg->size) {
largest_io_command_size = std::max<long>(msg->size, 4096);
last_io_command = (RCS_CMD_MSG *) realloc(last_io_command, largest_io_command_size);
}
if (0 != last_io_command) {
memcpy(last_io_command, msg, msg->size);
}
return 0;
}
static int forceCommand(RCS_CMD_MSG * msg)
{
if (0 == emcIoCommandBuffer) {
return -1;
}
if (0 == emcIoStatusBuffer || !emcIoStatusBuffer->valid()) {
return -1;
}
msg->serial_number = ++emcIoCommandSerialNumber;
if (0 != emcIoCommandBuffer->write(msg)) {
rcs_print_error("Failed to send command to IO level (%s:%s)\n",
emcSymbolLookup(msg->type),
emcIoCommandBuffer->msg2str(msg));
return -1;
}
if (largest_io_command_size < msg->size) {
largest_io_command_size = std::max<long>(msg->size, 4096);
last_io_command = (RCS_CMD_MSG *) realloc(last_io_command, largest_io_command_size);
}
if (0 != last_io_command) {
memcpy(last_io_command, msg, msg->size);
}
return 0;
}
int emcIoInit() { return task_methods->emcIoInit(); }
int emcIoHalt() {
try {
return task_methods->emcIoHalt();
} catch( bp::error_already_set ) {
std::string msg = handle_pyerror();
rcs_print("emcIoHalt(): %s\n", msg.c_str());
PyErr_Clear();
return -1;
}
}
int emcIoAbort(int reason) { return task_methods->emcIoAbort(reason); }
int emcIoSetDebug(int debug) { return task_methods->emcIoSetDebug(debug); }
int emcAuxEstopOn() { return task_methods->emcAuxEstopOn(); }
int emcAuxEstopOff() { return task_methods->emcAuxEstopOff(); }
int emcCoolantMistOn() { return task_methods->emcCoolantMistOn(); }
int emcCoolantMistOff() { return task_methods->emcCoolantMistOff(); }
int emcCoolantFloodOn() { return task_methods->emcCoolantFloodOn(); }
int emcCoolantFloodOff() { return task_methods->emcCoolantFloodOff(); }
int emcLubeOn() { return task_methods->emcLubeOn(); }
int emcLubeOff() { return task_methods->emcLubeOff(); }
int emcToolPrepare(int p, int tool) { return task_methods->emcToolPrepare(p, tool); }
int emcToolStartChange() { return task_methods->emcToolStartChange(); }
int emcToolLoad() { return task_methods->emcToolLoad(); }
int emcToolUnload() { return task_methods->emcToolUnload(); }
int emcToolLoadToolTable(const char *file) { return task_methods->emcToolLoadToolTable(file); }
int emcToolSetOffset(int pocket, int toolno, EmcPose offset, double diameter,
double frontangle, double backangle, int orientation) {
return task_methods->emcToolSetOffset( pocket, toolno, offset, diameter,
frontangle, backangle, orientation); }
int emcToolSetNumber(int number) { return task_methods->emcToolSetNumber(number); }
int emcIoUpdate(EMC_IO_STAT * stat) { return task_methods->emcIoUpdate(stat); }
int emcIoPluginCall(EMC_IO_PLUGIN_CALL *call_msg) { return task_methods->emcIoPluginCall(call_msg->len,
call_msg->call); }
static const char *instance_name = "task_instance";
int emcTaskOnce(const char *filename)
{
bp::object retval;
bp::tuple arg;
bp::dict kwarg;
extern struct _inittab builtin_modules[];
if (!PythonPlugin::instantiate(builtin_modules)) {
rcs_print("emcTaskOnce: cant instantiate Python plugin\n");
goto no_pytask;
}
if (python_plugin->configure(filename, "PYTHON") == PLUGIN_OK) {
if (emc_debug & EMC_DEBUG_PYTHON_TASK) {
rcs_print("emcTaskOnce: Python plugin configured\n");
}
} else {
goto no_pytask;
}
if (PYUSABLE) {
try {
bp::object task_namespace = python_plugin->main_namespace[TASK_MODULE].attr("__dict__");;
bp::object result = task_namespace[TASK_VAR];
bp::extract<Task *> typetest(result);
if (typetest.check()) {
task_methods = bp::extract< Task * >(result);
} else {
rcs_print("cant extract a Task instance out of '%s'\n", instance_name);
task_methods = NULL;
}
} catch( bp::error_already_set ) {
std::string msg = handle_pyerror();
if (emc_debug & EMC_DEBUG_PYTHON_TASK) {
rcs_print("emcTaskOnce: extract(%s): %s\n", instance_name, msg.c_str());
}
PyErr_Clear();
}
}
no_pytask:
if (task_methods == NULL) {
if (emc_debug & EMC_DEBUG_PYTHON_TASK) {
rcs_print("emcTaskOnce: no Python Task() instance available, using default iocontrol-based task methods\n");
}
task_methods = new Task();
}
return 0;
}
int emcRunHalFiles(const char *filename)
{
IniFile inifile;
const char *inistring;
int lineno,status;
int n = 1;
pid_t pid;
if (inifile.Open(filename) == false) {
return -1;
}
while (NULL != (inistring = inifile.Find("POSTTASK_HALFILE", "HAL",
n, &lineno))) {
if ((pid = vfork()) < 0)
perror("vfork()");
else if (pid == 0) {
execlp("halcmd", "halcmd","-i",filename,"-f",inistring, NULL);
perror("execlp halcmd");
} else {
if ((waitpid (pid, &status, 0) == pid) && WEXITSTATUS(status))
rcs_print("'halcmd -i %s -f %s' exited with %d\n",
filename, inistring, WEXITSTATUS(status));
}
n++;
}
return 0;
}
int return_int(const char *funcname, PyObject *retval)
{
int status = python_plugin->plugin_status();
if (status == PLUGIN_EXCEPTION) {
emcOperatorError(status,"return_int(%s): %s",
funcname, python_plugin->last_exception().c_str());
return -1;
}
if ((retval != Py_None) &&
(PyInt_Check(retval))) {
return PyInt_AS_LONG(retval);
} else {
emcOperatorError(0, "return_int(%s): expected int return value, got '%s' (%s)",
funcname,
PyString_AsString(retval),
retval->ob_type->tp_name);
Py_XDECREF(retval);
return -1;
}
}
int emcPluginCall(EMC_EXEC_PLUGIN_CALL *call_msg)
{
if (PYUSABLE) {
bp::object retval;
bp::object arg = bp::make_tuple(bp::object(call_msg->call));
bp::dict kwarg;
python_plugin->call(TASK_MODULE, PLUGIN_CALL, arg, kwarg, retval);
return return_int(PLUGIN_CALL, retval.ptr());
} else {
emcOperatorError(0, "emcPluginCall: Python plugin not initialized");
return -1;
}
}
extern "C" void initemctask();
extern "C" void initinterpreter();
extern "C" void initemccanon();
struct _inittab builtin_modules[] = {
{ (char *) "interpreter", initinterpreter },
{ (char *) "emccanon", initemccanon },
{ (char *) "emctask", initemctask },
{ NULL, NULL }
};
Task::Task() : use_iocontrol(0), random_toolchanger(0) {
IniFile inifile;
ini_filename = emc_inifile;
if (inifile.Open(ini_filename)) {
use_iocontrol = (inifile.Find("EMCIO", "EMCIO") != NULL);
inifile.Find(&random_toolchanger, "RANDOM_TOOLCHANGER", "EMCIO");
const char *t;
if ((t = inifile.Find("TOOL_TABLE", "EMCIO")) != NULL)
tooltable_filename = strdup(t);
}
if (!use_iocontrol) {
for(int i = 0; i < CANON_POCKETS_MAX; i++) {
ttcomments[i] = (char *)malloc(CANON_TOOL_ENTRY_LEN);
}
}
};
Task::~Task() {};
int Task::emcIoInit()
{
EMC_TOOL_INIT ioInitMsg;
if (0 != emcioNmlGet()) {
rcs_print_error("emcioNmlGet() failed.\n");
return -1;
}
if (0 != iniTool(emc_inifile)) {
return -1;
}
if (forceCommand(&ioInitMsg)) {
rcs_print_error("Can't forceCommand(ioInitMsg)\n");
return -1;
}
return 0;
}
int Task::emcIoHalt()
{
EMC_TOOL_HALT ioHaltMsg;
if (emcIoCommandBuffer != 0) {
forceCommand(&ioHaltMsg);
}
if (emcIoStatusBuffer != 0) {
delete emcIoStatusBuffer;
emcIoStatusBuffer = 0;
emcIoStatus = 0;
}
if (emcIoCommandBuffer != 0) {
delete emcIoCommandBuffer;
emcIoCommandBuffer = 0;
}
if (last_io_command) {
free(last_io_command);
last_io_command = 0;
}
return 0;
}
int Task::emcIoAbort(int reason)
{
EMC_TOOL_ABORT ioAbortMsg;
ioAbortMsg.reason = reason;
sendCommand(&ioAbortMsg);
return 0;
}
int Task::emcIoSetDebug(int debug)
{
EMC_SET_DEBUG ioDebugMsg;
ioDebugMsg.debug = debug;
return sendCommand(&ioDebugMsg);
}
int Task::emcAuxEstopOn()
{
EMC_AUX_ESTOP_ON estopOnMsg;
return forceCommand(&estopOnMsg);
}
int Task::emcAuxEstopOff()
{
EMC_AUX_ESTOP_OFF estopOffMsg;
return forceCommand(&estopOffMsg); }
int Task::emcCoolantMistOn()
{
EMC_COOLANT_MIST_ON mistOnMsg;
sendCommand(&mistOnMsg);
return 0;
}
int Task::emcCoolantMistOff()
{
EMC_COOLANT_MIST_OFF mistOffMsg;
sendCommand(&mistOffMsg);
return 0;
}
int Task::emcCoolantFloodOn()
{
EMC_COOLANT_FLOOD_ON floodOnMsg;
sendCommand(&floodOnMsg);
return 0;
}
int Task::emcCoolantFloodOff()
{
EMC_COOLANT_FLOOD_OFF floodOffMsg;
sendCommand(&floodOffMsg);
return 0;
}
int Task::emcLubeOn()
{
EMC_LUBE_ON lubeOnMsg;
sendCommand(&lubeOnMsg);
return 0;
}
int Task::emcLubeOff()
{
EMC_LUBE_OFF lubeOffMsg;
sendCommand(&lubeOffMsg);
return 0;
}
int Task::emcToolPrepare(int p, int tool)
{
EMC_TOOL_PREPARE toolPrepareMsg;
toolPrepareMsg.pocket = p;
toolPrepareMsg.tool = tool;
sendCommand(&toolPrepareMsg);
return 0;
}
int Task::emcToolStartChange()
{
EMC_TOOL_START_CHANGE toolStartChangeMsg;
sendCommand(&toolStartChangeMsg);
return 0;
}
int Task::emcToolLoad()
{
EMC_TOOL_LOAD toolLoadMsg;
sendCommand(&toolLoadMsg);
return 0;
}
int Task::emcToolUnload()
{
EMC_TOOL_UNLOAD toolUnloadMsg;
sendCommand(&toolUnloadMsg);
return 0;
}
int Task::emcToolLoadToolTable(const char *file)
{
EMC_TOOL_LOAD_TOOL_TABLE toolLoadToolTableMsg;
strcpy(toolLoadToolTableMsg.file, file);
sendCommand(&toolLoadToolTableMsg);
return 0;
}
int Task::emcToolSetOffset(int pocket, int toolno, EmcPose offset, double diameter,
double frontangle, double backangle, int orientation)
{
EMC_TOOL_SET_OFFSET toolSetOffsetMsg;
toolSetOffsetMsg.pocket = pocket;
toolSetOffsetMsg.toolno = toolno;
toolSetOffsetMsg.offset = offset;
toolSetOffsetMsg.diameter = diameter;
toolSetOffsetMsg.frontangle = frontangle;
toolSetOffsetMsg.backangle = backangle;
toolSetOffsetMsg.orientation = orientation;
sendCommand(&toolSetOffsetMsg);
return 0;
}
int Task::emcToolSetNumber(int number)
{
EMC_TOOL_SET_NUMBER toolSetNumberMsg;
toolSetNumberMsg.tool = number;
sendCommand(&toolSetNumberMsg);
return 0;
}
int Task::emcIoUpdate(EMC_IO_STAT * stat)
{
if (!use_iocontrol) {
return 0;
}
if (0 == emcIoStatusBuffer || !emcIoStatusBuffer->valid()) {
return -1;
}
switch (emcIoStatusBuffer->peek()) {
case -1:
return -1;
break;
case 0: case EMC_IO_STAT_TYPE: break;
default:
return -1;
break;
}
*stat = *emcIoStatus;
if (stat->echo_serial_number != emcIoCommandSerialNumber) {
stat->status = RCS_EXEC;
}
return 0;
}
int Task::emcIoPluginCall(int len, const char *msg)
{
if (emc_debug & EMC_DEBUG_PYTHON_TASK) {
rcs_print("emcIoPluginCall(%d,%s) - no Python handler set\n",len,msg);
}
return 0;
}