Skip to content

Instantly share code, notes, and snippets.

@the-snowwhite
Last active October 30, 2020 14:19
Show Gist options
  • Save the-snowwhite/4e8a79b69453253f7ff8b97ed90bc64c to your computer and use it in GitHub Desktop.
Save the-snowwhite/4e8a79b69453253f7ff8b97ed90bc64c to your computer and use it in GitHub Desktop.
/********************************************************************
* Description: emctaskmain.cc
* Main program for EMC task level
*
* Derived from a work by Fred Proctor & Will Shackleford
*
* Author:
* License: GPL Version 2
* System: Linux
*
* Copyright (c) 2004 All rights reserved.
*
********************************************************************/
/*
Principles of operation:
1. The main program calls emcTaskPlan() and emcTaskExecute() cyclically.
2. emcTaskPlan() reads the new command, and decides what to do with
it based on the mode (manual, auto, mdi) or state (estop, on) of the
machine. Many of the commands just go out immediately to the
subsystems (motion and IO). In auto mode, the interpreter is called
and as a result the interp_list is appended with NML commands.
3. emcTaskExecute() executes a big switch on execState. If it's done,
it gets the next item off the interp_list, and sets execState to the
preconditions for that. These preconditions include waiting for motion,
waiting for IO, etc. Once they are satisfied, it issues the command, and
sets execState to the postconditions. Once those are satisfied, it gets
the next item off the interp_list, and so on.
4. preconditions and postconditions are only looked at in conjunction
with commands on the interp_list. Immediate commands won't have any
pre- or postconditions associated with them looked at.
5. At this point, nothing in this file adds anything to the interp_list.
This could change, for example, when defining pre- and postconditions for
jog or home commands. If this is done, make sure that the corresponding
abort command clears out the interp_list.
6. Single-stepping is handled in checkPreconditions() as the first
condition. If we're in single-stepping mode, as indicated by the
variable 'stepping', we set the state to waiting-for-step. This
polls on the variable 'steppingWait' which is reset to zero when a
step command is received, and set to one when the command is
issued.
*/
#include <stdio.h> // vsprintf()
#include <string.h> // strcpy()
#include <stdarg.h> // va_start()
#include <stdlib.h> // exit()
#include <signal.h> // signal(), SIGINT
#include <float.h> // DBL_MAX
#include <sys/types.h> // pid_t
#include <unistd.h> // fork()
#include <sys/wait.h> // waitpid(), WNOHANG, WIFEXITED
#include <ctype.h> // isspace()
#include <libintl.h>
#include <locale.h>
#include "usrmotintf.h"
#include <rtapi_string.h>
#if 0
// Enable this to niftily trap floating point exceptions for debugging
#include <fpu_control.h>
fpu_control_t __fpu_control = _FPU_IEEE & ~(_FPU_MASK_IM | _FPU_MASK_ZM | _FPU_MASK_OM);
#endif
#include "rcs.hh" // NML classes, nmlErrorFormat()
#include "emc.hh" // EMC NML
#include "emc_nml.hh"
#include "canon.hh" // CANON_TOOL_TABLE stuff
#include "inifile.hh" // INIFILE
#include "interpl.hh" // NML_INTERP_LIST, interp_list
#include "emcglb.h" // EMC_INIFILE,NMLFILE, EMC_TASK_CYCLE_TIME
#include "interp_return.hh" // public interpreter return values
#include "interp_internal.hh" // interpreter private definitions
#include "rcs_print.hh"
#include "timer.hh"
#include "nml_oi.hh"
#include "task.hh" // emcTaskCommand etc
#include "taskclass.hh"
#include "motion.h" // EMCMOT_ORIENT_*
#include "inihal.hh"
static emcmot_config_t emcmotConfig;
/* time after which the user interface is declared dead
* because it would'nt read any more messages
*/
#define DEFAULT_EMC_UI_TIMEOUT 5.0
// NML channels
static RCS_CMD_CHANNEL *emcCommandBuffer = 0;
static RCS_STAT_CHANNEL *emcStatusBuffer = 0;
static NML *emcErrorBuffer = 0;
// NML command channel data pointer
static RCS_CMD_MSG *emcCommand = 0;
// global EMC status
EMC_STAT *emcStatus = 0;
// timer stuff
static RCS_TIMER *timer = 0;
// flag signifying that ini file [TASK] CYCLE_TIME is <= 0.0, so
// we should not delay at all between cycles. This means also that
// the EMC_TASK_CYCLE_TIME global will be set to the measured cycle
// time each cycle, in case other code references this.
static int emcTaskNoDelay = 0;
// flag signifying that on the next loop, there should be no delay.
// this is set when transferring trajectory data from userspace to kernel
// space, annd reset otherwise.
static int emcTaskEager = 0;
static int no_force_homing = 0; // forces the user to home first before allowing MDI and Program run
//can be overriden by [TRAJ]NO_FORCE_HOMING=1
static double EMC_TASK_CYCLE_TIME_ORIG = 0.0;
// delay counter
static double taskExecDelayTimeout = 0.0;
// emcTaskIssueCommand issues command immediately
static int emcTaskIssueCommand(NMLmsg * cmd);
// pending command to be sent out by emcTaskExecute()
NMLmsg *emcTaskCommand = 0;
// signal handling code to stop main loop
int done;
static int emctask_shutdown(void);
extern void backtrace(int signo);
int _task = 1; // control preview behaviour when remapping
// for operator display on iocontrol signalling a toolchanger fault if io.fault is set
// %d receives io.reason
static const char *io_error = "toolchanger error %d";
extern void setup_signal_handlers(); // backtrace, gdb-in-new-window supportx
int all_homed(void) {
for (int i = 0; i < emcStatus->motion.traj.joints; i++) {
if(!emcStatus->motion.joint[i].homed) // XXX
return 0;
}
return 1;
}
void emctask_quit(int sig)
{
// set main's done flag
done = 1;
// restore signal handler
signal(sig, emctask_quit);
}
/* make sure at least space bytes are available on
* error channel; wait a bit to drain if needed
*/
int emcErrorBufferOKtoWrite(int space, const char *caller)
{
// check channel for validity
if (emcErrorBuffer == NULL)
return -1;
if (!emcErrorBuffer->valid())
return -1;
double send_errorchan_timout = etime() + DEFAULT_EMC_UI_TIMEOUT;
while (etime() < send_errorchan_timout) {
if (emcErrorBuffer->get_space_available() < space) {
esleep(0.01);
continue;
} else {
break;
}
}
if (etime() >= send_errorchan_timout) {
if (emc_debug & EMC_DEBUG_TASK_ISSUE) {
rcs_print("timeout waiting for error channel to drain, caller=`%s' request=%d\n", caller,space);
}
return -1;
} else {
// printf("--- %d bytes available after %f seconds\n", space, etime() - send_errorchan_timout + DEFAULT_EMC_UI_TIMEOUT);
}
return 0;
}
// implementation of EMC error logger
int emcOperatorError(int id, const char *fmt, ...)
{
EMC_OPERATOR_ERROR error_msg;
va_list ap;
if ( emcErrorBufferOKtoWrite(sizeof(error_msg) * 2, "emcOperatorError"))
return -1;
if (NULL == fmt) {
return -1;
}
if (0 == *fmt) {
return -1;
}
// prepend error code, leave off 0 ad-hoc code
error_msg.error[0] = 0;
if (0 != id) {
snprintf(error_msg.error, sizeof(error_msg.error), "[%d] ", id);
}
// append error string
va_start(ap, fmt);
vsnprintf(&error_msg.error[strlen(error_msg.error)],
sizeof(error_msg.error) - strlen(error_msg.error), fmt, ap);
va_end(ap);
// force a NULL at the end for safety
error_msg.error[LINELEN - 1] = 0;
// write it
rcs_print("%s\n", error_msg.error);
return emcErrorBuffer->write(error_msg);
}
int emcOperatorText(int id, const char *fmt, ...)
{
EMC_OPERATOR_TEXT text_msg;
va_list ap;
if ( emcErrorBufferOKtoWrite(sizeof(text_msg) * 2, "emcOperatorText"))
return -1;
// write args to NML message (ignore int text code)
va_start(ap, fmt);
vsnprintf(text_msg.text, sizeof(text_msg.text), fmt, ap);
va_end(ap);
// force a NULL at the end for safety
text_msg.text[LINELEN - 1] = 0;
// write it
return emcErrorBuffer->write(text_msg);
}
int emcOperatorDisplay(int id, const char *fmt, ...)
{
EMC_OPERATOR_DISPLAY display_msg;
va_list ap;
if ( emcErrorBufferOKtoWrite(sizeof(display_msg) * 2, "emcOperatorDisplay"))
return -1;
// write args to NML message (ignore int display code)
va_start(ap, fmt);
vsnprintf(display_msg.display, sizeof(display_msg.display), fmt, ap);
va_end(ap);
// force a NULL at the end for safety
display_msg.display[LINELEN - 1] = 0;
// write it
return emcErrorBuffer->write(display_msg);
}
/*
handling of EMC_SYSTEM_CMD
*/
/* convert string to arg/argv set */
static int argvize(const char *src, char *dst, char *argv[], int len)
{
char *bufptr;
int argvix;
char inquote;
char looking;
strncpy(dst, src, len);
dst[len - 1] = 0;
bufptr = dst;
inquote = 0;
argvix = 0;
looking = 1;
while (0 != *bufptr) {
if (*bufptr == '"') {
*bufptr = 0;
if (inquote) {
inquote = 0;
looking = 1;
} else {
inquote = 1;
}
} else if (isspace(*bufptr) && !inquote) {
looking = 1;
*bufptr = 0;
} else if (looking) {
looking = 0;
argv[argvix] = bufptr;
argvix++;
}
bufptr++;
}
argv[argvix] = 0; // null-terminate the argv list
return argvix;
}
static pid_t emcSystemCmdPid = 0;
int emcSystemCmd(char *s)
{
char buffer[EMC_SYSTEM_CMD_LEN];
char *argv[EMC_SYSTEM_CMD_LEN / 2 + 1];
if (0 != emcSystemCmdPid) {
// something's already running, and we can only handle one
if (emc_debug & EMC_DEBUG_TASK_ISSUE) {
rcs_print
("emcSystemCmd: abandoning process %d, running ``%s''\n",
emcSystemCmdPid, s);
}
}
emcSystemCmdPid = fork();
if (-1 == emcSystemCmdPid) {
// we're still the parent, with no child created
if (emc_debug & EMC_DEBUG_TASK_ISSUE) {
rcs_print("system command ``%s'' can't be executed\n", s);
}
return -1;
}
if (0 == emcSystemCmdPid) {
// we're the child
// convert string to argc/argv
argvize(s, buffer, argv, EMC_SYSTEM_CMD_LEN);
execvp(argv[0], argv);
// if we get here, we didn't exec
if (emc_debug & EMC_DEBUG_TASK_ISSUE) {
rcs_print("emcSystemCmd: can't execute ``%s''\n", s);
}
exit(-1);
}
// else we're the parent
return 0;
}
// shorthand typecasting ptrs
static EMC_JOINT_HALT *joint_halt_msg;
static EMC_JOINT_DISABLE *disable_msg;
static EMC_JOINT_ENABLE *enable_msg;
static EMC_JOINT_HOME *home_msg;
static EMC_JOINT_UNHOME *unhome_msg;
static EMC_JOG_CONT *jog_cont_msg;
static EMC_JOG_STOP *jog_stop_msg;
static EMC_JOG_INCR *jog_incr_msg;
static EMC_JOG_ABS *jog_abs_msg;
static EMC_JOINT_SET_BACKLASH *set_backlash_msg;
static EMC_JOINT_SET_HOMING_PARAMS *set_homing_params_msg;
static EMC_JOINT_SET_FERROR *set_ferror_msg;
static EMC_JOINT_SET_MIN_FERROR *set_min_ferror_msg;
static EMC_JOINT_SET_MAX_POSITION_LIMIT *set_max_limit_msg;
static EMC_JOINT_SET_MIN_POSITION_LIMIT *set_min_limit_msg;
static EMC_JOINT_OVERRIDE_LIMITS *joint_lim_msg;
//static EMC_JOINT_SET_OUTPUT *axis_output_msg;
static EMC_JOINT_LOAD_COMP *joint_load_comp_msg;
//static EMC_AXIS_SET_STEP_PARAMS *set_step_params_msg;
static EMC_TRAJ_SET_SCALE *emcTrajSetScaleMsg;
static EMC_TRAJ_SET_RAPID_SCALE *emcTrajSetRapidScaleMsg;
static EMC_TRAJ_SET_MAX_VELOCITY *emcTrajSetMaxVelocityMsg;
static EMC_TRAJ_SET_SPINDLE_SCALE *emcTrajSetSpindleScaleMsg;
static EMC_TRAJ_SET_VELOCITY *emcTrajSetVelocityMsg;
static EMC_TRAJ_SET_ACCELERATION *emcTrajSetAccelerationMsg;
static EMC_TRAJ_LINEAR_MOVE *emcTrajLinearMoveMsg;
static EMC_TRAJ_CIRCULAR_MOVE *emcTrajCircularMoveMsg;
static EMC_TRAJ_DELAY *emcTrajDelayMsg;
static EMC_TRAJ_SET_TERM_COND *emcTrajSetTermCondMsg;
static EMC_TRAJ_SET_SPINDLESYNC *emcTrajSetSpindlesyncMsg;
// These classes are commented out because the compiler
// complains that they are "defined but not used".
//static EMC_MOTION_SET_AOUT *emcMotionSetAoutMsg;
//static EMC_MOTION_SET_DOUT *emcMotionSetDoutMsg;
static EMC_SPINDLE_SPEED *spindle_speed_msg;
static EMC_SPINDLE_ORIENT *spindle_orient_msg;
static EMC_SPINDLE_WAIT_ORIENT_COMPLETE *wait_spindle_orient_complete_msg;
static EMC_SPINDLE_ON *spindle_on_msg;
static EMC_SPINDLE_OFF *spindle_off_msg;
static EMC_SPINDLE_BRAKE_ENGAGE *spindle_brake_engage_msg;
static EMC_SPINDLE_BRAKE_RELEASE *spindle_brake_release_msg;
static EMC_SPINDLE_INCREASE *spindle_increase_msg;
static EMC_SPINDLE_DECREASE *spindle_decrease_msg;
static EMC_SPINDLE_CONSTANT *spindle_constant_msg;
static EMC_TOOL_PREPARE *tool_prepare_msg;
static EMC_TOOL_LOAD_TOOL_TABLE *load_tool_table_msg;
static EMC_TOOL_SET_OFFSET *emc_tool_set_offset_msg;
static EMC_TOOL_SET_NUMBER *emc_tool_set_number_msg;
static EMC_TASK_SET_MODE *mode_msg;
static EMC_TASK_SET_STATE *state_msg;
static EMC_TASK_PLAN_RUN *run_msg;
static EMC_TASK_PLAN_EXECUTE *execute_msg;
static EMC_TASK_PLAN_OPEN *open_msg;
static EMC_TASK_PLAN_SET_OPTIONAL_STOP *os_msg;
static EMC_TASK_PLAN_SET_BLOCK_DELETE *bd_msg;
static EMC_AUX_INPUT_WAIT *emcAuxInputWaitMsg;
static int emcAuxInputWaitType = 0;
static int emcAuxInputWaitIndex = -1;
// commands we compose here
static EMC_TASK_PLAN_RUN taskPlanRunCmd; // 16-Aug-1999 FMP
static EMC_TASK_PLAN_INIT taskPlanInitCmd;
static EMC_TASK_PLAN_SYNCH taskPlanSynchCmd;
static int interpResumeState = EMC_TASK_INTERP_IDLE;
static int programStartLine = 0; // which line to run program from
// how long the interp list can be
int stepping = 0;
int steppingWait = 0;
static int steppedLine = 0;
// Variables to handle MDI call interrupts
// Depth of call level before interrupted MDI call
static int mdi_execute_level = -1;
// Schedule execute(0) command
static int mdi_execute_next = 0;
// Wait after interrupted command
static int mdi_execute_wait = 0;
// Side queue to store MDI commands
static NML_INTERP_LIST mdi_execute_queue;
// MDI input queue
static NML_INTERP_LIST mdi_input_queue;
#define MAX_MDI_QUEUE 10
static int max_mdi_queued_commands = MAX_MDI_QUEUE;
/*
checkInterpList(NML_INTERP_LIST *il, EMC_STAT *stat) takes a pointer
to an interpreter list and a pointer to the EMC status, pops each NML
message off the list, and checks it against limits, resource availability,
etc. in the status.
It returns 0 if all messages check out, -1 if any of them fail. If one
fails, the rest of the list is not checked.
*/
static int checkInterpList(NML_INTERP_LIST * il, EMC_STAT * stat)
{
NMLmsg *cmd = 0;
// let's create some shortcuts to casts at compile time
#define operator_error_msg ((EMC_OPERATOR_ERROR *) cmd)
#define linear_move ((EMC_TRAJ_LINEAR_MOVE *) cmd)
#define circular_move ((EMC_TRAJ_CIRCULAR_MOVE *) cmd)
while (il->len() > 0) {
cmd = il->get();
switch (cmd->type) {
case EMC_OPERATOR_ERROR_TYPE:
emcOperatorError(operator_error_msg->id, "%s",
operator_error_msg->error);
break;
//FIXME: there was limit checking tests below, see if they were needed
case EMC_TRAJ_LINEAR_MOVE_TYPE:
break;
case EMC_TRAJ_CIRCULAR_MOVE_TYPE:
break;
default:
break;
}
}
return 0;
// get rid of the compile-time cast shortcuts
#undef circular_move_msg
#undef linear_move_msg
#undef operator_error_msg
}
extern int emcTaskMopup();
void readahead_reading(void)
{
int readRetval;
int execRetval;
if (interp_list.len() <= emc_task_interp_max_len) {
int count = 0;
interpret_again:
if (emcTaskPlanIsWait()) {
// delay reading of next line until all is done
if (interp_list.len() == 0 &&
emcTaskCommand == 0 &&
emcStatus->task.execState ==
EMC_TASK_EXEC_DONE) {
emcTaskPlanClearWait();
}
} else {
readRetval = emcTaskPlanRead();
/*! \todo MGS FIXME
This if() actually evaluates to if (readRetval != INTERP_OK)...
*** Need to look at all calls to things that return INTERP_xxx values! ***
MGS */
if (readRetval > INTERP_MIN_ERROR
|| readRetval == INTERP_ENDFILE
|| readRetval == INTERP_EXIT
|| readRetval == INTERP_EXECUTE_FINISH) {
/* emcTaskPlanRead retval != INTERP_OK
Signal to the rest of the system that that the interp
is now in a paused state. */
/*! \todo FIXME The above test *should* be reduced to:
readRetVal != INTERP_OK
(N.B. Watch for negative error codes.) */
emcStatus->task.interpState =
EMC_TASK_INTERP_WAITING;
} else {
// got a good line
// record the line number and command
emcStatus->task.readLine = emcTaskPlanLine();
emcTaskPlanCommand((char *) &emcStatus->task.
command);
// and execute it
execRetval = emcTaskPlanExecute(0);
// line number may need update after
// returns from subprograms in external
// files
emcStatus->task.readLine = emcTaskPlanLine();
if (execRetval > INTERP_MIN_ERROR) {
emcStatus->task.interpState =
EMC_TASK_INTERP_WAITING;
interp_list.clear();
emcAbortCleanup(EMC_ABORT_INTERPRETER_ERROR,
"interpreter error");
} else if (execRetval == -1
|| execRetval == INTERP_EXIT ) {
emcStatus->task.interpState =
EMC_TASK_INTERP_WAITING;
} else if (execRetval == INTERP_EXECUTE_FINISH) {
// INTERP_EXECUTE_FINISH signifies
// that no more reading should be done until
// everything
// outstanding is completed
emcTaskPlanSetWait();
// and resynch interp WM
emcTaskQueueCommand(&taskPlanSynchCmd);
} else if (execRetval != 0) {
// end of file
emcStatus->task.interpState =
EMC_TASK_INTERP_WAITING;
emcStatus->task.motionLine = 0;
emcStatus->task.readLine = 0;
} else {
// executed a good line
}
// throw the results away if we're supposed to
// read
// through it
if ( programStartLine != 0 &&
emcTaskPlanLevel() == 0 &&
( programStartLine < 0 ||
emcTaskPlanLine() <= programStartLine )) {
// we're stepping over lines, so check them
// for
// limits, etc. and clear then out
if (0 != checkInterpList(&interp_list,
emcStatus)) {
// problem with actions, so do same as we
// did
// for a bad read from emcTaskPlanRead()
// above
emcStatus->task.interpState =
EMC_TASK_INTERP_WAITING;
}
// and clear it regardless
interp_list.clear();
}
if (emcStatus->task.readLine < programStartLine &&
emcTaskPlanLevel() == 0) {
//update the position with our current position, as the other positions are only skipped through
CANON_UPDATE_END_POINT(emcStatus->motion.traj.actualPosition.tran.x,
emcStatus->motion.traj.actualPosition.tran.y,
emcStatus->motion.traj.actualPosition.tran.z,
emcStatus->motion.traj.actualPosition.a,
emcStatus->motion.traj.actualPosition.b,
emcStatus->motion.traj.actualPosition.c,
emcStatus->motion.traj.actualPosition.u,
emcStatus->motion.traj.actualPosition.v,
emcStatus->motion.traj.actualPosition.w);
if ((emcStatus->task.readLine + 1 == programStartLine) &&
(emcTaskPlanLevel() == 0)) {
emcTaskPlanSynch();
// reset programStartLine so we don't fall into our stepping routines
// if we happen to execute lines before the current point later (due to subroutines).
programStartLine = 0;
}
}
if (count++ < emc_task_interp_max_len
&& emcStatus->task.interpState == EMC_TASK_INTERP_READING
&& interp_list.len() <= emc_task_interp_max_len * 2/3) {
goto interpret_again;
}
} // else read was OK, so execute
} // else not emcTaskPlanIsWait
} // if interp len is less than max
}
static void mdi_execute_abort(void)
{
int queued_mdi_commands;
// XXX: Reset needed?
if (mdi_execute_wait || mdi_execute_next)
emcTaskPlanReset();
mdi_execute_level = -1;
mdi_execute_wait = 0;
mdi_execute_next = 0;
queued_mdi_commands = mdi_execute_queue.len();
if (queued_mdi_commands > 0) {
rcs_print("mdi_execute_abort: dropping %d queued MDI commands\n", queued_mdi_commands);
}
mdi_execute_queue.clear();
emcStatus->task.queuedMDIcommands = 0;
emcStatus->task.interpState = EMC_TASK_INTERP_IDLE;
}
static void mdi_execute_hook(void)
{
if (mdi_execute_wait && emcTaskPlanIsWait()) {
// delay reading of next line until all is done
if (interp_list.len() == 0 &&
emcTaskCommand == 0 &&
emcStatus->task.execState ==
EMC_TASK_EXEC_DONE) {
emcTaskPlanClearWait();
mdi_execute_wait = 0;
mdi_execute_hook();
}
return;
}
if (
(mdi_execute_level < 0)
&& (mdi_execute_wait == 0)
&& (mdi_execute_queue.len() > 0)
&& (interp_list.len() == 0)
&& (emcTaskCommand == NULL)
) {
interp_list.append(mdi_execute_queue.get());
emcStatus->task.queuedMDIcommands = mdi_execute_queue.len();
return;
}
// determine when a MDI command actually finishes normally.
if (interp_list.len() == 0 &&
emcTaskCommand == 0 &&
emcStatus->task.execState == EMC_TASK_EXEC_DONE &&
emcStatus->task.interpState != EMC_TASK_INTERP_IDLE &&
emcStatus->motion.traj.queue == 0 &&
emcStatus->io.status == RCS_DONE &&
!mdi_execute_wait &&
!mdi_execute_next) {
// finished. Check for dequeuing of queued MDI command is done in emcTaskPlan().
if (emc_debug & EMC_DEBUG_TASK_ISSUE)
rcs_print("mdi_execute_hook: MDI command '%s' done (remaining: %d)\n",
emcStatus->task.command, mdi_input_queue.len());
emcStatus->task.command[0] = 0;
emcStatus->task.interpState = EMC_TASK_INTERP_IDLE;
}
if (!mdi_execute_next) return;
if (interp_list.len() > emc_task_interp_max_len) return;
mdi_execute_next = 0;
EMC_TASK_PLAN_EXECUTE msg;
msg.command[0] = (char) 0xff;
interp_list.append(msg);
}
void readahead_waiting(void)
{
// now handle call logic
// check for subsystems done
if (interp_list.len() == 0 &&
emcTaskCommand == 0 &&
emcStatus->motion.traj.queue == 0 &&
emcStatus->io.status == RCS_DONE)
// finished
{
int was_open = taskplanopen;
if (was_open) {
emcTaskPlanClose();
if (emc_debug & EMC_DEBUG_INTERP && was_open) {
rcs_print
("emcTaskPlanClose() called at %s:%d\n",
__FILE__, __LINE__);
}
// then resynch interpreter
emcTaskQueueCommand(&taskPlanSynchCmd);
} else {
emcStatus->task.interpState = EMC_TASK_INTERP_IDLE;
}
emcStatus->task.readLine = 0;
} else {
// still executing
}
}
static bool allow_while_idle_type() {
// allow for EMC_TASK_MODE_AUTO, EMC_TASK_MODE_MDI
// expect immediate command
RCS_CMD_MSG *emcCommand;
emcCommand = emcCommandBuffer->get_address();
switch(emcCommand->type) {
case EMC_JOG_CONT_TYPE:
case EMC_JOG_INCR_TYPE:
case EMC_JOG_STOP_TYPE:
case EMC_JOG_ABS_TYPE:
case EMC_TRAJ_SET_TELEOP_ENABLE_TYPE:
return 1;
break;
}
return 0;
}
/*
emcTaskPlan()
Planner for NC code or manual mode operations
*/
static int emcTaskPlan(void)
{
NMLTYPE type;
int retval = 0;
// check for new command
if (emcCommand->serial_number != emcStatus->echo_serial_number) {
// flag it here locally as a new command
type = emcCommand->type;
} else {
// no new command-- reset local flag
type = 0;
}
// handle any new command
switch (emcStatus->task.state) {
case EMC_TASK_STATE_OFF:
case EMC_TASK_STATE_ESTOP:
case EMC_TASK_STATE_ESTOP_RESET:
// now switch on the mode
switch (emcStatus->task.mode) {
case EMC_TASK_MODE_MANUAL:
case EMC_TASK_MODE_AUTO:
case EMC_TASK_MODE_MDI:
// now switch on the command
switch (type) {
case 0:
case EMC_NULL_TYPE:
// no command
break;
// immediate commands
case EMC_JOINT_SET_BACKLASH_TYPE:
case EMC_JOINT_SET_HOMING_PARAMS_TYPE:
case EMC_JOINT_DISABLE_TYPE:
case EMC_JOINT_ENABLE_TYPE:
case EMC_JOINT_SET_FERROR_TYPE:
case EMC_JOINT_SET_MIN_FERROR_TYPE:
case EMC_JOINT_ABORT_TYPE:
case EMC_JOINT_LOAD_COMP_TYPE:
case EMC_JOINT_UNHOME_TYPE:
case EMC_TRAJ_SET_SCALE_TYPE:
case EMC_TRAJ_SET_RAPID_SCALE_TYPE:
case EMC_TRAJ_SET_MAX_VELOCITY_TYPE:
case EMC_TRAJ_SET_SPINDLE_SCALE_TYPE:
case EMC_TRAJ_SET_FO_ENABLE_TYPE:
case EMC_TRAJ_SET_FH_ENABLE_TYPE:
case EMC_TRAJ_SET_SO_ENABLE_TYPE:
case EMC_TRAJ_SET_VELOCITY_TYPE:
case EMC_TRAJ_SET_ACCELERATION_TYPE:
case EMC_TASK_INIT_TYPE:
case EMC_TASK_SET_MODE_TYPE:
case EMC_TASK_SET_STATE_TYPE:
case EMC_TASK_PLAN_INIT_TYPE:
case EMC_TASK_PLAN_OPEN_TYPE:
case EMC_TASK_PLAN_CLOSE_TYPE:
case EMC_TASK_PLAN_SET_OPTIONAL_STOP_TYPE:
case EMC_TASK_PLAN_SET_BLOCK_DELETE_TYPE:
case EMC_TASK_ABORT_TYPE:
case EMC_TASK_PLAN_SYNCH_TYPE:
case EMC_TRAJ_CLEAR_PROBE_TRIPPED_FLAG_TYPE:
case EMC_TRAJ_PROBE_TYPE:
case EMC_AUX_INPUT_WAIT_TYPE:
case EMC_MOTION_SET_DOUT_TYPE:
case EMC_MOTION_ADAPTIVE_TYPE:
case EMC_MOTION_SET_AOUT_TYPE:
case EMC_TRAJ_RIGID_TAP_TYPE:
case EMC_TRAJ_SET_TELEOP_ENABLE_TYPE:
case EMC_SET_DEBUG_TYPE:
retval = emcTaskIssueCommand(emcCommand);
break;
// one case where we need to be in manual mode
case EMC_JOINT_OVERRIDE_LIMITS_TYPE:
retval = 0;
if (emcStatus->task.mode == EMC_TASK_MODE_MANUAL) {
retval = emcTaskIssueCommand(emcCommand);
}
break;
case EMC_TOOL_LOAD_TOOL_TABLE_TYPE:
case EMC_TOOL_SET_OFFSET_TYPE:
// send to IO
emcTaskQueueCommand(emcCommand);
// signify no more reading
emcTaskPlanSetWait();
// then resynch interpreter
emcTaskQueueCommand(&taskPlanSynchCmd);
break;
case EMC_TOOL_SET_NUMBER_TYPE:
// send to IO
emcTaskQueueCommand(emcCommand);
// then resynch interpreter
emcTaskQueueCommand(&taskPlanSynchCmd);
break;
default:
emcOperatorError(0,
_
("command (%s) cannot be executed until the machine is out of E-stop and turned on"),
emc_symbol_lookup(type));
retval = -1;
break;
} // switch (type)
default:
// invalid mode
break;
} // switch (mode)
break; // case EMC_TASK_STATE_OFF,ESTOP,ESTOP_RESET
case EMC_TASK_STATE_ON:
/* we can do everything (almost) when the machine is on, so let's
switch on the execution mode */
switch (emcStatus->task.mode) {
case EMC_TASK_MODE_MANUAL: // ON, MANUAL
switch (type) {
case 0:
case EMC_NULL_TYPE:
// no command
break;
// immediate commands
case EMC_JOINT_DISABLE_TYPE:
case EMC_JOINT_ENABLE_TYPE:
case EMC_JOINT_SET_BACKLASH_TYPE:
case EMC_JOINT_SET_HOMING_PARAMS_TYPE:
case EMC_JOINT_SET_FERROR_TYPE:
case EMC_JOINT_SET_MIN_FERROR_TYPE:
case EMC_JOINT_SET_MAX_POSITION_LIMIT_TYPE:
case EMC_JOINT_SET_MIN_POSITION_LIMIT_TYPE:
case EMC_JOINT_HALT_TYPE:
case EMC_JOINT_HOME_TYPE:
case EMC_JOINT_UNHOME_TYPE:
case EMC_JOG_CONT_TYPE:
case EMC_JOG_INCR_TYPE:
case EMC_JOG_ABS_TYPE:
case EMC_JOG_STOP_TYPE:
case EMC_JOINT_OVERRIDE_LIMITS_TYPE:
case EMC_TRAJ_PAUSE_TYPE:
case EMC_TRAJ_RESUME_TYPE:
case EMC_TRAJ_ABORT_TYPE:
case EMC_TRAJ_SET_SCALE_TYPE:
case EMC_TRAJ_SET_RAPID_SCALE_TYPE:
case EMC_TRAJ_SET_MAX_VELOCITY_TYPE:
case EMC_TRAJ_SET_SPINDLE_SCALE_TYPE:
case EMC_TRAJ_SET_FO_ENABLE_TYPE:
case EMC_TRAJ_SET_FH_ENABLE_TYPE:
case EMC_TRAJ_SET_SO_ENABLE_TYPE:
case EMC_SPINDLE_SPEED_TYPE:
case EMC_SPINDLE_ON_TYPE:
case EMC_SPINDLE_OFF_TYPE:
case EMC_SPINDLE_BRAKE_RELEASE_TYPE:
case EMC_SPINDLE_BRAKE_ENGAGE_TYPE:
case EMC_SPINDLE_INCREASE_TYPE:
case EMC_SPINDLE_DECREASE_TYPE:
case EMC_SPINDLE_CONSTANT_TYPE:
case EMC_COOLANT_MIST_ON_TYPE:
case EMC_COOLANT_MIST_OFF_TYPE:
case EMC_COOLANT_FLOOD_ON_TYPE:
case EMC_COOLANT_FLOOD_OFF_TYPE:
case EMC_LUBE_ON_TYPE:
case EMC_LUBE_OFF_TYPE:
case EMC_TASK_SET_MODE_TYPE:
case EMC_TASK_SET_STATE_TYPE:
case EMC_TASK_ABORT_TYPE:
case EMC_TASK_PLAN_OPEN_TYPE:
case EMC_TASK_PLAN_CLOSE_TYPE:
case EMC_TASK_PLAN_PAUSE_TYPE:
case EMC_TASK_PLAN_REVERSE_TYPE:
case EMC_TASK_PLAN_FORWARD_TYPE:
case EMC_TASK_PLAN_RESUME_TYPE:
case EMC_TASK_PLAN_INIT_TYPE:
case EMC_TASK_PLAN_SYNCH_TYPE:
case EMC_TASK_PLAN_SET_OPTIONAL_STOP_TYPE:
case EMC_TASK_PLAN_SET_BLOCK_DELETE_TYPE:
case EMC_TASK_PLAN_OPTIONAL_STOP_TYPE:
case EMC_TRAJ_CLEAR_PROBE_TRIPPED_FLAG_TYPE:
case EMC_TRAJ_PROBE_TYPE:
case EMC_AUX_INPUT_WAIT_TYPE:
case EMC_MOTION_SET_DOUT_TYPE:
case EMC_MOTION_SET_AOUT_TYPE:
case EMC_MOTION_ADAPTIVE_TYPE:
case EMC_TRAJ_RIGID_TAP_TYPE:
case EMC_TRAJ_SET_TELEOP_ENABLE_TYPE:
case EMC_SET_DEBUG_TYPE:
retval = emcTaskIssueCommand(emcCommand);
break;
// queued commands
case EMC_TASK_PLAN_EXECUTE_TYPE:
// resynch the interpreter, since we may have moved
// externally
emcTaskIssueCommand(&taskPlanSynchCmd);
// and now call for interpreter execute
retval = emcTaskIssueCommand(emcCommand);
break;
case EMC_TOOL_LOAD_TOOL_TABLE_TYPE:
case EMC_TOOL_SET_OFFSET_TYPE:
// send to IO
emcTaskQueueCommand(emcCommand);
// signify no more reading
emcTaskPlanSetWait();
// then resynch interpreter
emcTaskQueueCommand(&taskPlanSynchCmd);
break;
case EMC_TOOL_SET_NUMBER_TYPE:
// send to IO
emcTaskQueueCommand(emcCommand);
// then resynch interpreter
emcTaskQueueCommand(&taskPlanSynchCmd);
break;
case EMC_TASK_PLAN_RUN_TYPE:
if (GET_EXTERNAL_OFFSET_APPLIED()) {
// err here, fewer err reports
retval = -1;
}
break;
// otherwise we can't handle it
default:
emcOperatorError(0, _("can't do that (%s:%d) in manual mode"),
emc_symbol_lookup(type),(int) type);
retval = -1;
break;
} // switch (type) in ON, MANUAL
break; // case EMC_TASK_MODE_MANUAL
case EMC_TASK_MODE_AUTO: // ON, AUTO
switch (emcStatus->task.interpState) {
case EMC_TASK_INTERP_IDLE: // ON, AUTO, IDLE
switch (type) {
case 0:
case EMC_NULL_TYPE:
// no command
break;
// immediate commands
case EMC_JOINT_SET_BACKLASH_TYPE:
case EMC_JOINT_SET_HOMING_PARAMS_TYPE:
case EMC_JOINT_SET_FERROR_TYPE:
case EMC_JOINT_SET_MIN_FERROR_TYPE:
case EMC_JOINT_UNHOME_TYPE:
case EMC_TRAJ_PAUSE_TYPE:
case EMC_TRAJ_RESUME_TYPE:
case EMC_TRAJ_ABORT_TYPE:
case EMC_TRAJ_SET_SCALE_TYPE:
case EMC_TRAJ_SET_RAPID_SCALE_TYPE:
case EMC_TRAJ_SET_MAX_VELOCITY_TYPE:
case EMC_TRAJ_SET_SPINDLE_SCALE_TYPE:
case EMC_TRAJ_SET_FO_ENABLE_TYPE:
case EMC_TRAJ_SET_FH_ENABLE_TYPE:
case EMC_TRAJ_SET_SO_ENABLE_TYPE:
case EMC_SPINDLE_SPEED_TYPE:
case EMC_SPINDLE_ORIENT_TYPE:
case EMC_SPINDLE_WAIT_ORIENT_COMPLETE_TYPE:
case EMC_SPINDLE_ON_TYPE:
case EMC_SPINDLE_OFF_TYPE:
case EMC_SPINDLE_BRAKE_RELEASE_TYPE:
case EMC_SPINDLE_BRAKE_ENGAGE_TYPE:
case EMC_SPINDLE_INCREASE_TYPE:
case EMC_SPINDLE_DECREASE_TYPE:
case EMC_SPINDLE_CONSTANT_TYPE:
case EMC_COOLANT_MIST_ON_TYPE:
case EMC_COOLANT_MIST_OFF_TYPE:
case EMC_COOLANT_FLOOD_ON_TYPE:
case EMC_COOLANT_FLOOD_OFF_TYPE:
case EMC_LUBE_ON_TYPE:
case EMC_LUBE_OFF_TYPE:
case EMC_TASK_SET_MODE_TYPE:
case EMC_TASK_SET_STATE_TYPE:
case EMC_TASK_ABORT_TYPE:
case EMC_TASK_PLAN_INIT_TYPE:
case EMC_TASK_PLAN_OPEN_TYPE:
case EMC_TASK_PLAN_CLOSE_TYPE:
case EMC_TASK_PLAN_RUN_TYPE:
case EMC_TASK_PLAN_EXECUTE_TYPE:
case EMC_TASK_PLAN_PAUSE_TYPE:
case EMC_TASK_PLAN_REVERSE_TYPE:
case EMC_TASK_PLAN_FORWARD_TYPE:
case EMC_TASK_PLAN_RESUME_TYPE:
case EMC_TASK_PLAN_SET_OPTIONAL_STOP_TYPE:
case EMC_TASK_PLAN_SET_BLOCK_DELETE_TYPE:
case EMC_TASK_PLAN_OPTIONAL_STOP_TYPE:
case EMC_TRAJ_CLEAR_PROBE_TRIPPED_FLAG_TYPE:
case EMC_TRAJ_PROBE_TYPE:
case EMC_AUX_INPUT_WAIT_TYPE:
case EMC_TRAJ_RIGID_TAP_TYPE:
case EMC_SET_DEBUG_TYPE:
retval = emcTaskIssueCommand(emcCommand);
break;
case EMC_TASK_PLAN_STEP_TYPE:
// handles case where first action is to step the program
taskPlanRunCmd.line = 0; // run from start
/*! \todo FIXME-- can have GUI set this; send a run instead of a
step */
retval = emcTaskIssueCommand(&taskPlanRunCmd);
if(retval != 0) break;
emcTrajPause();
if (emcStatus->task.interpState != EMC_TASK_INTERP_PAUSED) {
interpResumeState = emcStatus->task.interpState;
}
emcStatus->task.interpState = EMC_TASK_INTERP_PAUSED;
emcStatus->task.task_paused = 1;
retval = 0;
break;
case EMC_TOOL_LOAD_TOOL_TABLE_TYPE:
case EMC_TOOL_SET_OFFSET_TYPE:
// send to IO
emcTaskQueueCommand(emcCommand);
// signify no more reading
emcTaskPlanSetWait();
// then resynch interpreter
emcTaskQueueCommand(&taskPlanSynchCmd);
break;
// otherwise we can't handle it
default:
//EMC_TASK_MODE_AUTO(2) && EMC_TASK_INTERP_IDLE(1)
if ( allow_while_idle_type() ) {
retval = emcTaskIssueCommand(emcCommand);
break;
}
emcOperatorError(0, _
("can't do that (%s) in auto mode with the interpreter idle"),
emc_symbol_lookup(type));
retval = -1;
break;
} // switch (type) in ON, AUTO, IDLE
break; // EMC_TASK_INTERP_IDLE
case EMC_TASK_INTERP_READING: // ON, AUTO, READING
switch (type) {
case 0:
case EMC_NULL_TYPE:
// no command
break;
// immediate commands
case EMC_JOINT_SET_BACKLASH_TYPE:
case EMC_JOINT_SET_HOMING_PARAMS_TYPE:
case EMC_JOINT_SET_FERROR_TYPE:
case EMC_JOINT_SET_MIN_FERROR_TYPE:
case EMC_JOINT_UNHOME_TYPE:
case EMC_TRAJ_PAUSE_TYPE:
case EMC_TRAJ_RESUME_TYPE:
case EMC_TRAJ_ABORT_TYPE:
case EMC_TRAJ_SET_SCALE_TYPE:
case EMC_TRAJ_SET_RAPID_SCALE_TYPE:
case EMC_TRAJ_SET_MAX_VELOCITY_TYPE:
case EMC_TRAJ_SET_SPINDLE_SCALE_TYPE:
case EMC_TRAJ_SET_FO_ENABLE_TYPE:
case EMC_TRAJ_SET_FH_ENABLE_TYPE:
case EMC_TRAJ_SET_SO_ENABLE_TYPE:
case EMC_SPINDLE_INCREASE_TYPE:
case EMC_SPINDLE_DECREASE_TYPE:
case EMC_SPINDLE_CONSTANT_TYPE:
case EMC_TASK_PLAN_PAUSE_TYPE:
case EMC_TASK_PLAN_REVERSE_TYPE:
case EMC_TASK_PLAN_FORWARD_TYPE:
case EMC_TASK_PLAN_RESUME_TYPE:
case EMC_TASK_PLAN_SET_OPTIONAL_STOP_TYPE:
case EMC_TASK_PLAN_SET_BLOCK_DELETE_TYPE:
case EMC_TASK_PLAN_OPTIONAL_STOP_TYPE:
case EMC_TASK_SET_MODE_TYPE:
case EMC_TASK_SET_STATE_TYPE:
case EMC_TASK_ABORT_TYPE:
case EMC_TRAJ_CLEAR_PROBE_TRIPPED_FLAG_TYPE:
case EMC_TRAJ_PROBE_TYPE:
case EMC_AUX_INPUT_WAIT_TYPE:
case EMC_TRAJ_RIGID_TAP_TYPE:
case EMC_SET_DEBUG_TYPE:
case EMC_COOLANT_MIST_ON_TYPE:
case EMC_COOLANT_MIST_OFF_TYPE:
case EMC_COOLANT_FLOOD_ON_TYPE:
case EMC_COOLANT_FLOOD_OFF_TYPE:
case EMC_LUBE_ON_TYPE:
case EMC_LUBE_OFF_TYPE:
retval = emcTaskIssueCommand(emcCommand);
return retval;
break;
case EMC_TASK_PLAN_STEP_TYPE:
stepping = 1; // set stepping mode in case it's not
steppingWait = 0; // clear the wait
break;
// otherwise we can't handle it
default:
emcOperatorError(0, _
("can't do that (%s) in auto mode with the interpreter reading"),
emc_symbol_lookup(type));
retval = -1;
break;
} // switch (type) in ON, AUTO, READING
// handle interp readahead logic
readahead_reading();
break; // EMC_TASK_INTERP_READING
case EMC_TASK_INTERP_PAUSED: // ON, AUTO, PAUSED
switch (type) {
case 0:
case EMC_NULL_TYPE:
// no command
break;
// immediate commands
case EMC_JOINT_SET_BACKLASH_TYPE:
case EMC_JOINT_SET_HOMING_PARAMS_TYPE:
case EMC_JOINT_SET_FERROR_TYPE:
case EMC_JOINT_SET_MIN_FERROR_TYPE:
case EMC_JOINT_UNHOME_TYPE:
case EMC_TRAJ_PAUSE_TYPE:
case EMC_TRAJ_RESUME_TYPE:
case EMC_TRAJ_ABORT_TYPE:
case EMC_TRAJ_SET_SCALE_TYPE:
case EMC_TRAJ_SET_RAPID_SCALE_TYPE:
case EMC_TRAJ_SET_MAX_VELOCITY_TYPE:
case EMC_TRAJ_SET_SPINDLE_SCALE_TYPE:
case EMC_TRAJ_SET_FO_ENABLE_TYPE:
case EMC_TRAJ_SET_FH_ENABLE_TYPE:
case EMC_TRAJ_SET_SO_ENABLE_TYPE:
case EMC_SPINDLE_SPEED_TYPE:
case EMC_SPINDLE_ORIENT_TYPE:
case EMC_SPINDLE_WAIT_ORIENT_COMPLETE_TYPE:
case EMC_SPINDLE_ON_TYPE:
case EMC_SPINDLE_OFF_TYPE:
case EMC_SPINDLE_BRAKE_RELEASE_TYPE:
case EMC_SPINDLE_BRAKE_ENGAGE_TYPE:
case EMC_SPINDLE_INCREASE_TYPE:
case EMC_SPINDLE_DECREASE_TYPE:
case EMC_SPINDLE_CONSTANT_TYPE:
case EMC_COOLANT_MIST_ON_TYPE:
case EMC_COOLANT_MIST_OFF_TYPE:
case EMC_COOLANT_FLOOD_ON_TYPE:
case EMC_COOLANT_FLOOD_OFF_TYPE:
case EMC_LUBE_ON_TYPE:
case EMC_LUBE_OFF_TYPE:
case EMC_TASK_SET_MODE_TYPE:
case EMC_TASK_SET_STATE_TYPE:
case EMC_TASK_ABORT_TYPE:
case EMC_TASK_PLAN_EXECUTE_TYPE:
case EMC_TASK_PLAN_PAUSE_TYPE:
case EMC_TASK_PLAN_REVERSE_TYPE:
case EMC_TASK_PLAN_FORWARD_TYPE:
case EMC_TASK_PLAN_RESUME_TYPE:
case EMC_TASK_PLAN_SET_OPTIONAL_STOP_TYPE:
case EMC_TASK_PLAN_SET_BLOCK_DELETE_TYPE:
case EMC_TASK_PLAN_OPTIONAL_STOP_TYPE:
case EMC_TRAJ_CLEAR_PROBE_TRIPPED_FLAG_TYPE:
case EMC_TRAJ_PROBE_TYPE:
case EMC_AUX_INPUT_WAIT_TYPE:
case EMC_TRAJ_RIGID_TAP_TYPE:
case EMC_SET_DEBUG_TYPE:
retval = emcTaskIssueCommand(emcCommand);
break;
case EMC_TASK_PLAN_STEP_TYPE:
stepping = 1;
steppingWait = 0;
if (emcStatus->motion.traj.paused &&
emcStatus->motion.traj.queue > 0) {
// there are pending motions paused; step them
emcTrajStep();
} else {
emcStatus->task.interpState = (enum EMC_TASK_INTERP_ENUM) interpResumeState;
}
emcStatus->task.task_paused = 1;
break;
// otherwise we can't handle it
default:
emcOperatorError(0, _
("can't do that (%s) in auto mode with the interpreter paused"),
emc_symbol_lookup(type));
retval = -1;
break;
} // switch (type) in ON, AUTO, PAUSED
break; // EMC_TASK_INTERP_PAUSED
case EMC_TASK_INTERP_WAITING:
// interpreter ran to end
// handle input commands
switch (type) {
case 0:
case EMC_NULL_TYPE:
// no command
break;
// immediate commands
case EMC_JOINT_SET_BACKLASH_TYPE:
case EMC_JOINT_SET_HOMING_PARAMS_TYPE:
case EMC_JOINT_SET_FERROR_TYPE:
case EMC_JOINT_SET_MIN_FERROR_TYPE:
case EMC_JOINT_UNHOME_TYPE:
case EMC_TRAJ_PAUSE_TYPE:
case EMC_TRAJ_RESUME_TYPE:
case EMC_TRAJ_ABORT_TYPE:
case EMC_TRAJ_SET_SCALE_TYPE:
case EMC_TRAJ_SET_RAPID_SCALE_TYPE:
case EMC_TRAJ_SET_MAX_VELOCITY_TYPE:
case EMC_TRAJ_SET_SPINDLE_SCALE_TYPE:
case EMC_TRAJ_SET_FO_ENABLE_TYPE:
case EMC_TRAJ_SET_FH_ENABLE_TYPE:
case EMC_TRAJ_SET_SO_ENABLE_TYPE:
case EMC_SPINDLE_INCREASE_TYPE:
case EMC_SPINDLE_DECREASE_TYPE:
case EMC_SPINDLE_CONSTANT_TYPE:
case EMC_TASK_PLAN_EXECUTE_TYPE:
case EMC_TASK_PLAN_PAUSE_TYPE:
case EMC_TASK_PLAN_REVERSE_TYPE:
case EMC_TASK_PLAN_FORWARD_TYPE:
case EMC_TASK_PLAN_RESUME_TYPE:
case EMC_TASK_PLAN_SET_OPTIONAL_STOP_TYPE:
case EMC_TASK_PLAN_SET_BLOCK_DELETE_TYPE:
case EMC_TASK_PLAN_OPTIONAL_STOP_TYPE:
case EMC_TASK_SET_MODE_TYPE:
case EMC_TASK_SET_STATE_TYPE:
case EMC_TASK_ABORT_TYPE:
case EMC_TRAJ_CLEAR_PROBE_TRIPPED_FLAG_TYPE:
case EMC_TRAJ_PROBE_TYPE:
case EMC_AUX_INPUT_WAIT_TYPE:
case EMC_TRAJ_RIGID_TAP_TYPE:
case EMC_SET_DEBUG_TYPE:
case EMC_COOLANT_MIST_ON_TYPE:
case EMC_COOLANT_MIST_OFF_TYPE:
case EMC_COOLANT_FLOOD_ON_TYPE:
case EMC_COOLANT_FLOOD_OFF_TYPE:
case EMC_LUBE_ON_TYPE:
case EMC_LUBE_OFF_TYPE:
retval = emcTaskIssueCommand(emcCommand);
break;
case EMC_TASK_PLAN_STEP_TYPE:
stepping = 1; // set stepping mode in case it's not
steppingWait = 0; // clear the wait
break;
// otherwise we can't handle it
default:
emcOperatorError(0, _
("can't do that (%s) in auto mode with the interpreter waiting"),
emc_symbol_lookup(type));
retval = -1;
break;
} // switch (type) in ON, AUTO, WAITING
// handle interp readahead logic
readahead_waiting();
break; // end of case EMC_TASK_INTERP_WAITING
default:
// coding error
rcs_print_error("invalid mode(%d)", emcStatus->task.mode);
retval = -1;
break;
} // switch (mode) in ON, AUTO
break; // case EMC_TASK_MODE_AUTO
case EMC_TASK_MODE_MDI: // ON, MDI
switch (type) {
case 0:
case EMC_NULL_TYPE:
// no command
break;
// immediate commands
case EMC_JOINT_SET_BACKLASH_TYPE:
case EMC_JOINT_SET_HOMING_PARAMS_TYPE:
case EMC_JOINT_SET_FERROR_TYPE:
case EMC_JOINT_SET_MIN_FERROR_TYPE:
case EMC_JOINT_UNHOME_TYPE:
case EMC_TRAJ_SET_SCALE_TYPE:
case EMC_TRAJ_SET_RAPID_SCALE_TYPE:
case EMC_TRAJ_SET_MAX_VELOCITY_TYPE:
case EMC_TRAJ_SET_SPINDLE_SCALE_TYPE:
case EMC_TRAJ_SET_FO_ENABLE_TYPE:
case EMC_TRAJ_SET_FH_ENABLE_TYPE:
case EMC_TRAJ_SET_SO_ENABLE_TYPE:
case EMC_SPINDLE_SPEED_TYPE:
case EMC_SPINDLE_ORIENT_TYPE:
case EMC_SPINDLE_WAIT_ORIENT_COMPLETE_TYPE:
case EMC_SPINDLE_ON_TYPE:
case EMC_SPINDLE_OFF_TYPE:
case EMC_SPINDLE_BRAKE_RELEASE_TYPE:
case EMC_SPINDLE_BRAKE_ENGAGE_TYPE:
case EMC_SPINDLE_INCREASE_TYPE:
case EMC_SPINDLE_DECREASE_TYPE:
case EMC_SPINDLE_CONSTANT_TYPE:
case EMC_COOLANT_MIST_ON_TYPE:
case EMC_COOLANT_MIST_OFF_TYPE:
case EMC_COOLANT_FLOOD_ON_TYPE:
case EMC_COOLANT_FLOOD_OFF_TYPE:
case EMC_LUBE_ON_TYPE:
case EMC_LUBE_OFF_TYPE:
case EMC_TASK_SET_MODE_TYPE:
case EMC_TASK_SET_STATE_TYPE:
case EMC_TASK_PLAN_INIT_TYPE:
case EMC_TASK_PLAN_OPEN_TYPE:
case EMC_TASK_PLAN_CLOSE_TYPE:
case EMC_TASK_PLAN_PAUSE_TYPE:
case EMC_TASK_PLAN_REVERSE_TYPE:
case EMC_TASK_PLAN_FORWARD_TYPE:
case EMC_TASK_PLAN_SET_OPTIONAL_STOP_TYPE:
case EMC_TASK_PLAN_SET_BLOCK_DELETE_TYPE:
case EMC_TASK_PLAN_RESUME_TYPE:
case EMC_TASK_PLAN_OPTIONAL_STOP_TYPE:
case EMC_TASK_PLAN_SYNCH_TYPE:
case EMC_TASK_ABORT_TYPE:
case EMC_TRAJ_CLEAR_PROBE_TRIPPED_FLAG_TYPE:
case EMC_TRAJ_PROBE_TYPE:
case EMC_AUX_INPUT_WAIT_TYPE:
case EMC_MOTION_SET_DOUT_TYPE:
case EMC_MOTION_SET_AOUT_TYPE:
case EMC_MOTION_ADAPTIVE_TYPE:
case EMC_TRAJ_RIGID_TAP_TYPE:
case EMC_SET_DEBUG_TYPE:
retval = emcTaskIssueCommand(emcCommand);
break;
case EMC_TASK_PLAN_EXECUTE_TYPE:
// If there are no queued MDI commands, no commands in
// interp_list, and waitFlag isn't set, then this new
// incoming MDI command can just be issued directly.
// Otherwise we need to queue it and deal with it
// later.
if (
(mdi_execute_queue.len() == 0)
&& (interp_list.len() == 0)
&& (emcTaskCommand == NULL)
&& (emcTaskPlanIsWait() == 0)
) {
retval = emcTaskIssueCommand(emcCommand);
} else {
mdi_execute_queue.append(emcCommand);
emcStatus->task.queuedMDIcommands = mdi_execute_queue.len();
retval = 0;
}
break;
case EMC_TOOL_LOAD_TOOL_TABLE_TYPE:
case EMC_TOOL_SET_OFFSET_TYPE:
// send to IO
emcTaskQueueCommand(emcCommand);
// signify no more reading
emcTaskPlanSetWait();
// then resynch interpreter
emcTaskQueueCommand(&taskPlanSynchCmd);
break;
// otherwise we can't handle it
default:
//EMC_TASK_MODE_MDI(3) && EMC_TASK_INTERP_IDLE(1)
if ( allow_while_idle_type() ) {
retval = emcTaskIssueCommand(emcCommand);
break;
}
emcOperatorError(0, _("can't do that (%s:%d) in MDI mode"),
emc_symbol_lookup(type),(int) type);
retval = -1;
break;
} // switch (type) in ON, MDI
mdi_execute_hook();
break; // case EMC_TASK_MODE_MDI
default:
break;
} // switch (mode)
break; // case EMC_TASK_STATE_ON
default:
break;
} // switch (task.state)
return retval;
}
/*
emcTaskCheckPreconditions() is called for commands on the interp_list.
Immediate commands, i.e., commands sent from calls to emcTaskIssueCommand()
in emcTaskPlan() directly, are not handled here.
The return value is a state for emcTaskExecute() to wait on, e.g.,
EMC_TASK_EXEC_WAITING_FOR_MOTION, before the command can be sent out.
*/
static int emcTaskCheckPreconditions(NMLmsg * cmd)
{
if (0 == cmd) {
return EMC_TASK_EXEC_DONE;
}
switch (cmd->type) {
// operator messages, if queued, will go out when everything before
// them is done
case EMC_OPERATOR_ERROR_TYPE:
case EMC_OPERATOR_TEXT_TYPE:
case EMC_OPERATOR_DISPLAY_TYPE:
case EMC_SYSTEM_CMD_TYPE:
case EMC_TRAJ_PROBE_TYPE: // prevent blending of this
case EMC_TRAJ_RIGID_TAP_TYPE: //and this
case EMC_TRAJ_CLEAR_PROBE_TRIPPED_FLAG_TYPE: // and this
case EMC_AUX_INPUT_WAIT_TYPE:
case EMC_SPINDLE_WAIT_ORIENT_COMPLETE_TYPE:
return EMC_TASK_EXEC_WAITING_FOR_MOTION_AND_IO;
break;
case EMC_TRAJ_LINEAR_MOVE_TYPE:
case EMC_TRAJ_CIRCULAR_MOVE_TYPE:
case EMC_TRAJ_SET_VELOCITY_TYPE:
case EMC_TRAJ_SET_ACCELERATION_TYPE:
case EMC_TRAJ_SET_TERM_COND_TYPE:
case EMC_TRAJ_SET_SPINDLESYNC_TYPE:
case EMC_TRAJ_SET_FO_ENABLE_TYPE:
case EMC_TRAJ_SET_FH_ENABLE_TYPE:
case EMC_TRAJ_SET_SO_ENABLE_TYPE:
return EMC_TASK_EXEC_WAITING_FOR_IO;
break;
case EMC_TRAJ_SET_OFFSET_TYPE:
// this applies the tool length offset variable after previous
// motions
case EMC_TRAJ_SET_G5X_TYPE:
case EMC_TRAJ_SET_G92_TYPE:
case EMC_TRAJ_SET_ROTATION_TYPE:
// this applies the program origin after previous motions
return EMC_TASK_EXEC_WAITING_FOR_MOTION;
break;
case EMC_TOOL_LOAD_TYPE:
case EMC_TOOL_UNLOAD_TYPE:
case EMC_TOOL_START_CHANGE_TYPE:
case EMC_COOLANT_MIST_ON_TYPE:
case EMC_COOLANT_MIST_OFF_TYPE:
case EMC_COOLANT_FLOOD_ON_TYPE:
case EMC_COOLANT_FLOOD_OFF_TYPE:
case EMC_SPINDLE_SPEED_TYPE:
case EMC_SPINDLE_ON_TYPE:
case EMC_SPINDLE_OFF_TYPE:
case EMC_SPINDLE_ORIENT_TYPE: // not sure
return EMC_TASK_EXEC_WAITING_FOR_MOTION_AND_IO;
break;
case EMC_TOOL_PREPARE_TYPE:
case EMC_LUBE_ON_TYPE:
case EMC_LUBE_OFF_TYPE:
return EMC_TASK_EXEC_WAITING_FOR_IO;
break;
case EMC_TOOL_LOAD_TOOL_TABLE_TYPE:
case EMC_TOOL_SET_OFFSET_TYPE:
return EMC_TASK_EXEC_WAITING_FOR_MOTION_AND_IO;
break;
case EMC_TOOL_SET_NUMBER_TYPE:
return EMC_TASK_EXEC_WAITING_FOR_IO;
break;
case EMC_TASK_PLAN_PAUSE_TYPE:
case EMC_TASK_PLAN_OPTIONAL_STOP_TYPE:
/* pause on the interp list is queued, so wait until all are done */
return EMC_TASK_EXEC_WAITING_FOR_MOTION_AND_IO;
break;
case EMC_TASK_PLAN_END_TYPE:
return EMC_TASK_EXEC_WAITING_FOR_MOTION_AND_IO;
break;
case EMC_TASK_PLAN_INIT_TYPE:
case EMC_TASK_PLAN_RUN_TYPE:
case EMC_TASK_PLAN_SYNCH_TYPE:
case EMC_TASK_PLAN_EXECUTE_TYPE:
return EMC_TASK_EXEC_WAITING_FOR_MOTION_AND_IO;
break;
case EMC_TRAJ_DELAY_TYPE:
return EMC_TASK_EXEC_WAITING_FOR_MOTION_AND_IO;
break;
case EMC_MOTION_SET_AOUT_TYPE:
if (((EMC_MOTION_SET_AOUT *) cmd)->now) {
return EMC_TASK_EXEC_WAITING_FOR_MOTION;
}
return EMC_TASK_EXEC_DONE;
break;
case EMC_MOTION_SET_DOUT_TYPE:
if (((EMC_MOTION_SET_DOUT *) cmd)->now) {
return EMC_TASK_EXEC_WAITING_FOR_MOTION;
}
return EMC_TASK_EXEC_DONE;
break;
case EMC_MOTION_ADAPTIVE_TYPE:
return EMC_TASK_EXEC_WAITING_FOR_MOTION;
break;
case EMC_EXEC_PLUGIN_CALL_TYPE:
case EMC_IO_PLUGIN_CALL_TYPE:
return EMC_TASK_EXEC_DONE;
break;
default:
// unrecognized command
if (emc_debug & EMC_DEBUG_TASK_ISSUE) {
rcs_print_error("preconditions: unrecognized command %d:%s\n",
(int)cmd->type, emc_symbol_lookup(cmd->type));
}
return EMC_TASK_EXEC_ERROR;
break;
}
return EMC_TASK_EXEC_DONE;
}
// puts command on interp list
int emcTaskQueueCommand(NMLmsg * cmd)
{
if (0 == cmd) {
return 0;
}
interp_list.append(cmd);
return 0;
}
// issues command immediately
static int emcTaskIssueCommand(NMLmsg * cmd)
{
int retval = 0;
int execRetval = 0;
if (0 == cmd) {
if (emc_debug & EMC_DEBUG_TASK_ISSUE) {
rcs_print("emcTaskIssueCommand() null command\n");
}
return 0;
}
if (emc_debug & EMC_DEBUG_TASK_ISSUE) {
rcs_print("Issuing %s -- \t (%s)\n", emcSymbolLookup(cmd->type),
emcCommandBuffer->msg2str(cmd));
}
switch (cmd->type) {
// general commands
case EMC_OPERATOR_ERROR_TYPE:
retval = emcOperatorError(((EMC_OPERATOR_ERROR *) cmd)->id,
"%s", ((EMC_OPERATOR_ERROR *) cmd)->error);
break;
case EMC_OPERATOR_TEXT_TYPE:
retval = emcOperatorText(((EMC_OPERATOR_TEXT *) cmd)->id,
"%s", ((EMC_OPERATOR_TEXT *) cmd)->text);
break;
case EMC_OPERATOR_DISPLAY_TYPE:
retval = emcOperatorDisplay(((EMC_OPERATOR_DISPLAY *) cmd)->id,
"%s", ((EMC_OPERATOR_DISPLAY *) cmd)->
display);
break;
case EMC_SYSTEM_CMD_TYPE:
retval = emcSystemCmd(((EMC_SYSTEM_CMD *) cmd)->string);
break;
// joint commands
case EMC_JOINT_DISABLE_TYPE:
disable_msg = (EMC_JOINT_DISABLE *) cmd;
retval = emcJointDisable(disable_msg->joint);
break;
case EMC_JOINT_ENABLE_TYPE:
enable_msg = (EMC_JOINT_ENABLE *) cmd;
retval = emcJointEnable(enable_msg->joint);
break;
case EMC_JOINT_HOME_TYPE:
home_msg = (EMC_JOINT_HOME *) cmd;
retval = emcJointHome(home_msg->joint);
break;
case EMC_JOINT_UNHOME_TYPE:
unhome_msg = (EMC_JOINT_UNHOME *) cmd;
retval = emcJointUnhome(unhome_msg->joint);
break;
case EMC_JOG_CONT_TYPE:
jog_cont_msg = (EMC_JOG_CONT *) cmd;
retval = emcJogCont(jog_cont_msg->joint_or_axis,
jog_cont_msg->vel,
jog_cont_msg->jjogmode);
break;
case EMC_JOG_STOP_TYPE:
jog_stop_msg = (EMC_JOG_STOP *) cmd;
retval = emcJogStop(jog_stop_msg->joint_or_axis,
jog_stop_msg->jjogmode);
break;
case EMC_JOG_INCR_TYPE:
jog_incr_msg = (EMC_JOG_INCR *) cmd;
retval = emcJogIncr(jog_incr_msg->joint_or_axis,
jog_incr_msg->incr,
jog_incr_msg->vel,
jog_incr_msg->jjogmode);
break;
case EMC_JOG_ABS_TYPE:
jog_abs_msg = (EMC_JOG_ABS *) cmd;
retval = emcJogAbs(jog_abs_msg->joint_or_axis,
jog_abs_msg->pos,
jog_abs_msg->vel,
jog_abs_msg->jjogmode);
break;
case EMC_JOINT_SET_BACKLASH_TYPE:
set_backlash_msg = (EMC_JOINT_SET_BACKLASH *) cmd;
retval =
emcJointSetBacklash(set_backlash_msg->joint,
set_backlash_msg->backlash);
break;
case EMC_JOINT_SET_HOMING_PARAMS_TYPE:
set_homing_params_msg = (EMC_JOINT_SET_HOMING_PARAMS *) cmd;
retval = emcJointSetHomingParams(set_homing_params_msg->joint,
set_homing_params_msg->home,
set_homing_params_msg->offset,
set_homing_params_msg->home_final_vel,
set_homing_params_msg->search_vel,
set_homing_params_msg->latch_vel,
set_homing_params_msg->use_index,
set_homing_params_msg->encoder_does_not_reset,
set_homing_params_msg->ignore_limits,
set_homing_params_msg->is_shared,
set_homing_params_msg->home_sequence,
set_homing_params_msg->volatile_home,
set_homing_params_msg->locking_indexer,
set_homing_params_msg->absolute_encoder);
break;
case EMC_JOINT_SET_FERROR_TYPE:
set_ferror_msg = (EMC_JOINT_SET_FERROR *) cmd;
retval = emcJointSetFerror(set_ferror_msg->joint,
set_ferror_msg->ferror);
break;
case EMC_JOINT_SET_MIN_FERROR_TYPE:
set_min_ferror_msg = (EMC_JOINT_SET_MIN_FERROR *) cmd;
retval = emcJointSetMinFerror(set_min_ferror_msg->joint,
set_min_ferror_msg->ferror);
break;
case EMC_JOINT_SET_MAX_POSITION_LIMIT_TYPE:
set_max_limit_msg = (EMC_JOINT_SET_MAX_POSITION_LIMIT *) cmd;
retval = emcJointSetMaxPositionLimit(set_max_limit_msg->joint,
set_max_limit_msg->limit);
break;
case EMC_JOINT_SET_MIN_POSITION_LIMIT_TYPE:
set_min_limit_msg = (EMC_JOINT_SET_MIN_POSITION_LIMIT *) cmd;
retval = emcJointSetMinPositionLimit(set_min_limit_msg->joint,
set_min_limit_msg->limit);
break;
case EMC_JOINT_HALT_TYPE:
joint_halt_msg = (EMC_JOINT_HALT *) cmd;
retval = emcJointHalt(joint_halt_msg->joint);
break;
case EMC_JOINT_OVERRIDE_LIMITS_TYPE:
joint_lim_msg = (EMC_JOINT_OVERRIDE_LIMITS *) cmd;
retval = emcJointOverrideLimits(joint_lim_msg->joint);
break;
case EMC_JOINT_LOAD_COMP_TYPE:
joint_load_comp_msg = (EMC_JOINT_LOAD_COMP *) cmd;
retval = emcJointLoadComp(joint_load_comp_msg->joint,
joint_load_comp_msg->file,
joint_load_comp_msg->type);
break;
// traj commands
case EMC_TRAJ_SET_SCALE_TYPE:
emcTrajSetScaleMsg = (EMC_TRAJ_SET_SCALE *) cmd;
retval = emcTrajSetScale(emcTrajSetScaleMsg->scale);
break;
case EMC_TRAJ_SET_RAPID_SCALE_TYPE:
emcTrajSetRapidScaleMsg = (EMC_TRAJ_SET_RAPID_SCALE *) cmd;
retval = emcTrajSetRapidScale(emcTrajSetRapidScaleMsg->scale);
break;
case EMC_TRAJ_SET_MAX_VELOCITY_TYPE:
emcTrajSetMaxVelocityMsg = (EMC_TRAJ_SET_MAX_VELOCITY *) cmd;
retval = emcTrajSetMaxVelocity(emcTrajSetMaxVelocityMsg->velocity);
break;
case EMC_TRAJ_SET_SPINDLE_SCALE_TYPE:
emcTrajSetSpindleScaleMsg = (EMC_TRAJ_SET_SPINDLE_SCALE *) cmd;
retval = emcTrajSetSpindleScale(emcTrajSetSpindleScaleMsg->spindle,
emcTrajSetSpindleScaleMsg->scale);
break;
case EMC_TRAJ_SET_FO_ENABLE_TYPE:
retval = emcTrajSetFOEnable(((EMC_TRAJ_SET_FO_ENABLE *) cmd)->mode); // feed override enable/disable
break;
case EMC_TRAJ_SET_FH_ENABLE_TYPE:
retval = emcTrajSetFHEnable(((EMC_TRAJ_SET_FH_ENABLE *) cmd)->mode); //feed hold enable/disable
break;
case EMC_TRAJ_SET_SO_ENABLE_TYPE:
retval = emcTrajSetSOEnable(((EMC_TRAJ_SET_SO_ENABLE *) cmd)->mode); //spindle speed override enable/disable
break;
case EMC_TRAJ_SET_VELOCITY_TYPE:
emcTrajSetVelocityMsg = (EMC_TRAJ_SET_VELOCITY *) cmd;
retval = emcTrajSetVelocity(emcTrajSetVelocityMsg->velocity,
emcTrajSetVelocityMsg->ini_maxvel);
break;
case EMC_TRAJ_SET_ACCELERATION_TYPE:
emcTrajSetAccelerationMsg = (EMC_TRAJ_SET_ACCELERATION *) cmd;
retval = emcTrajSetAcceleration(emcTrajSetAccelerationMsg->acceleration);
break;
case EMC_TRAJ_LINEAR_MOVE_TYPE:
emcTrajUpdateTag(((EMC_TRAJ_LINEAR_MOVE *) cmd)->tag);
emcTrajLinearMoveMsg = (EMC_TRAJ_LINEAR_MOVE *) cmd;
retval = emcTrajLinearMove(emcTrajLinearMoveMsg->end,
emcTrajLinearMoveMsg->type, emcTrajLinearMoveMsg->vel,
emcTrajLinearMoveMsg->ini_maxvel, emcTrajLinearMoveMsg->acc,
emcTrajLinearMoveMsg->indexer_jnum);
break;
case EMC_TRAJ_CIRCULAR_MOVE_TYPE:
emcTrajUpdateTag(((EMC_TRAJ_LINEAR_MOVE *) cmd)->tag);
emcTrajCircularMoveMsg = (EMC_TRAJ_CIRCULAR_MOVE *) cmd;
retval = emcTrajCircularMove(emcTrajCircularMoveMsg->end,
emcTrajCircularMoveMsg->center, emcTrajCircularMoveMsg->normal,
emcTrajCircularMoveMsg->turn, emcTrajCircularMoveMsg->type,
emcTrajCircularMoveMsg->vel,
emcTrajCircularMoveMsg->ini_maxvel,
emcTrajCircularMoveMsg->acc);
break;
case EMC_TRAJ_PAUSE_TYPE:
emcStatus->task.task_paused = 1;
retval = emcTrajPause();
break;
case EMC_TRAJ_RESUME_TYPE:
emcStatus->task.task_paused = 0;
retval = emcTrajResume();
break;
case EMC_TRAJ_ABORT_TYPE:
retval = emcTrajAbort();
break;
case EMC_TRAJ_DELAY_TYPE:
emcTrajDelayMsg = (EMC_TRAJ_DELAY *) cmd;
// set the timeout clock to expire at 'now' + delay time
taskExecDelayTimeout = etime() + emcTrajDelayMsg->delay;
retval = 0;
break;
case EMC_TRAJ_SET_TERM_COND_TYPE:
emcTrajSetTermCondMsg = (EMC_TRAJ_SET_TERM_COND *) cmd;
retval = emcTrajSetTermCond(emcTrajSetTermCondMsg->cond, emcTrajSetTermCondMsg->tolerance);
break;
case EMC_TRAJ_SET_SPINDLESYNC_TYPE:
emcTrajSetSpindlesyncMsg = (EMC_TRAJ_SET_SPINDLESYNC *) cmd;
retval = emcTrajSetSpindleSync(emcTrajSetSpindlesyncMsg->spindle, emcTrajSetSpindlesyncMsg->feed_per_revolution, emcTrajSetSpindlesyncMsg->velocity_mode);
break;
case EMC_TRAJ_SET_OFFSET_TYPE:
// update tool offset
emcStatus->task.toolOffset = ((EMC_TRAJ_SET_OFFSET *) cmd)->offset;
retval = emcTrajSetOffset(emcStatus->task.toolOffset);
break;
case EMC_TRAJ_SET_ROTATION_TYPE:
emcStatus->task.rotation_xy = ((EMC_TRAJ_SET_ROTATION *) cmd)->rotation;
retval = 0;
break;
case EMC_TRAJ_SET_G5X_TYPE:
// struct-copy program origin
emcStatus->task.g5x_offset = ((EMC_TRAJ_SET_G5X *) cmd)->origin;
emcStatus->task.g5x_index = ((EMC_TRAJ_SET_G5X *) cmd)->g5x_index;
retval = 0;
break;
case EMC_TRAJ_SET_G92_TYPE:
// struct-copy program origin
emcStatus->task.g92_offset = ((EMC_TRAJ_SET_G92 *) cmd)->origin;
retval = 0;
break;
case EMC_TRAJ_CLEAR_PROBE_TRIPPED_FLAG_TYPE:
retval = emcTrajClearProbeTrippedFlag();
break;
case EMC_TRAJ_PROBE_TYPE:
retval = emcTrajProbe(
((EMC_TRAJ_PROBE *) cmd)->pos,
((EMC_TRAJ_PROBE *) cmd)->type,
((EMC_TRAJ_PROBE *) cmd)->vel,
((EMC_TRAJ_PROBE *) cmd)->ini_maxvel,
((EMC_TRAJ_PROBE *) cmd)->acc,
((EMC_TRAJ_PROBE *) cmd)->probe_type);
break;
case EMC_AUX_INPUT_WAIT_TYPE:
emcAuxInputWaitMsg = (EMC_AUX_INPUT_WAIT *) cmd;
if (emcAuxInputWaitMsg->timeout == WAIT_MODE_IMMEDIATE) { //nothing to do, CANON will get the needed value when asked by the interp
emcStatus->task.input_timeout = 0; // no timeout can occur
emcAuxInputWaitIndex = -1;
taskExecDelayTimeout = 0.0;
} else {
emcAuxInputWaitType = emcAuxInputWaitMsg->wait_type; // remember what we are waiting for
emcAuxInputWaitIndex = emcAuxInputWaitMsg->index; // remember the input to look at
emcStatus->task.input_timeout = 2; // set timeout flag, gets cleared if input changes before timeout happens
// set the timeout clock to expire at 'now' + delay time
taskExecDelayTimeout = etime() + emcAuxInputWaitMsg->timeout;
}
break;
case EMC_SPINDLE_WAIT_ORIENT_COMPLETE_TYPE:
wait_spindle_orient_complete_msg = (EMC_SPINDLE_WAIT_ORIENT_COMPLETE *) cmd;
taskExecDelayTimeout = etime() + wait_spindle_orient_complete_msg->timeout;
break;
case EMC_TRAJ_RIGID_TAP_TYPE:
emcTrajUpdateTag(((EMC_TRAJ_LINEAR_MOVE *) cmd)->tag);
retval = emcTrajRigidTap(((EMC_TRAJ_RIGID_TAP *) cmd)->pos,
((EMC_TRAJ_RIGID_TAP *) cmd)->vel,
((EMC_TRAJ_RIGID_TAP *) cmd)->ini_maxvel,
((EMC_TRAJ_RIGID_TAP *) cmd)->acc,
((EMC_TRAJ_RIGID_TAP *) cmd)->scale);
break;
case EMC_TRAJ_SET_TELEOP_ENABLE_TYPE:
if (((EMC_TRAJ_SET_TELEOP_ENABLE *) cmd)->enable) {
retval = emcTrajSetMode(EMC_TRAJ_MODE_TELEOP);
} else {
retval = emcTrajSetMode(EMC_TRAJ_MODE_FREE);
}
break;
case EMC_MOTION_SET_AOUT_TYPE:
retval = emcMotionSetAout(((EMC_MOTION_SET_AOUT *) cmd)->index,
((EMC_MOTION_SET_AOUT *) cmd)->start,
((EMC_MOTION_SET_AOUT *) cmd)->end,
((EMC_MOTION_SET_AOUT *) cmd)->now);
break;
case EMC_MOTION_SET_DOUT_TYPE:
retval = emcMotionSetDout(((EMC_MOTION_SET_DOUT *) cmd)->index,
((EMC_MOTION_SET_DOUT *) cmd)->start,
((EMC_MOTION_SET_DOUT *) cmd)->end,
((EMC_MOTION_SET_DOUT *) cmd)->now);
break;
case EMC_MOTION_ADAPTIVE_TYPE:
retval = emcTrajSetAFEnable(((EMC_MOTION_ADAPTIVE *) cmd)->status);
break;
case EMC_SET_DEBUG_TYPE:
/* set the debug level here */
emc_debug = ((EMC_SET_DEBUG *) cmd)->debug;
/* and in IO and motion */
emcIoSetDebug(emc_debug);
emcMotionSetDebug(emc_debug);
/* and reflect it in the status-- this isn't updated continually */
emcStatus->debug = emc_debug;
break;
// unimplemented ones
// IO commands
case EMC_SPINDLE_SPEED_TYPE:
spindle_speed_msg = (EMC_SPINDLE_SPEED *) cmd;
retval = emcSpindleSpeed(spindle_speed_msg->spindle, spindle_speed_msg->speed,
spindle_speed_msg->factor, spindle_speed_msg->xoffset);
break;
case EMC_SPINDLE_ORIENT_TYPE:
spindle_orient_msg = (EMC_SPINDLE_ORIENT *) cmd;
retval = emcSpindleOrient(spindle_orient_msg->spindle, spindle_orient_msg->orientation,
spindle_orient_msg->mode);
break;
case EMC_SPINDLE_ON_TYPE:
spindle_on_msg = (EMC_SPINDLE_ON *) cmd;
retval = emcSpindleOn(spindle_on_msg->spindle, spindle_on_msg->speed,
spindle_on_msg->factor, spindle_on_msg->xoffset, spindle_on_msg->wait_for_spindle_at_speed);
break;
case EMC_SPINDLE_OFF_TYPE:
spindle_off_msg = (EMC_SPINDLE_OFF *) cmd;
retval = emcSpindleOff(spindle_off_msg->spindle);
break;
case EMC_SPINDLE_BRAKE_RELEASE_TYPE:
spindle_brake_release_msg = (EMC_SPINDLE_BRAKE_RELEASE *) cmd;
retval = emcSpindleBrakeRelease(spindle_brake_release_msg->spindle);
break;
case EMC_SPINDLE_INCREASE_TYPE:
spindle_increase_msg = (EMC_SPINDLE_INCREASE *) cmd;
retval = emcSpindleIncrease(spindle_increase_msg->spindle);
break;
case EMC_SPINDLE_DECREASE_TYPE:
spindle_decrease_msg = (EMC_SPINDLE_DECREASE *) cmd;
retval = emcSpindleDecrease(spindle_decrease_msg->spindle);
break;
case EMC_SPINDLE_CONSTANT_TYPE:
spindle_constant_msg = (EMC_SPINDLE_CONSTANT *) cmd;
retval = emcSpindleConstant(spindle_constant_msg->spindle);
break;
case EMC_SPINDLE_BRAKE_ENGAGE_TYPE:
spindle_brake_engage_msg = (EMC_SPINDLE_BRAKE_ENGAGE *) cmd;
retval = emcSpindleBrakeEngage(spindle_brake_engage_msg->spindle);
break;
case EMC_COOLANT_MIST_ON_TYPE:
retval = emcCoolantMistOn();
break;
case EMC_COOLANT_MIST_OFF_TYPE:
retval = emcCoolantMistOff();
break;
case EMC_COOLANT_FLOOD_ON_TYPE:
retval = emcCoolantFloodOn();
break;
case EMC_COOLANT_FLOOD_OFF_TYPE:
retval = emcCoolantFloodOff();
break;
case EMC_LUBE_ON_TYPE:
retval = emcLubeOn();
break;
case EMC_LUBE_OFF_TYPE:
retval = emcLubeOff();
break;
case EMC_TOOL_PREPARE_TYPE:
tool_prepare_msg = (EMC_TOOL_PREPARE *) cmd;
retval = emcToolPrepare(tool_prepare_msg->tool);
break;
case EMC_TOOL_START_CHANGE_TYPE:
retval = emcToolStartChange();
break;
case EMC_TOOL_LOAD_TYPE:
retval = emcToolLoad();
break;
case EMC_TOOL_UNLOAD_TYPE:
retval = emcToolUnload();
break;
case EMC_TOOL_LOAD_TOOL_TABLE_TYPE:
load_tool_table_msg = (EMC_TOOL_LOAD_TOOL_TABLE *) cmd;
retval = emcToolLoadToolTable(load_tool_table_msg->file);
break;
case EMC_TOOL_SET_OFFSET_TYPE:
emc_tool_set_offset_msg = (EMC_TOOL_SET_OFFSET *) cmd;
retval = emcToolSetOffset(emc_tool_set_offset_msg->pocket,
emc_tool_set_offset_msg->toolno,
emc_tool_set_offset_msg->offset,
emc_tool_set_offset_msg->diameter,
emc_tool_set_offset_msg->frontangle,
emc_tool_set_offset_msg->backangle,
emc_tool_set_offset_msg->orientation);
break;
case EMC_TOOL_SET_NUMBER_TYPE:
emc_tool_set_number_msg = (EMC_TOOL_SET_NUMBER *) cmd;
retval = emcToolSetNumber(emc_tool_set_number_msg->tool);
break;
// task commands
case EMC_TASK_INIT_TYPE:
retval = emcTaskInit();
break;
case EMC_TASK_ABORT_TYPE:
// abort everything
emcTaskAbort();
// KLUDGE call motion abort before state restore to make absolutely sure no
// stray restore commands make it down to motion
emcMotionAbort();
// Then call state restore to update the interpreter
emcTaskStateRestore();
emcIoAbort(EMC_ABORT_TASK_ABORT);
for (int s = 0; s < emcStatus->motion.traj.spindles; s++) emcSpindleAbort(s);
mdi_execute_abort();
emcAbortCleanup(EMC_ABORT_TASK_ABORT);
retval = 0;
break;
// mode and state commands
case EMC_TASK_SET_MODE_TYPE:
mode_msg = (EMC_TASK_SET_MODE *) cmd;
if (emcStatus->task.mode == EMC_TASK_MODE_AUTO &&
emcStatus->task.interpState != EMC_TASK_INTERP_IDLE &&
mode_msg->mode != EMC_TASK_MODE_AUTO) {
emcOperatorError(0, _("Can't switch mode while mode is AUTO and interpreter is not IDLE"));
} else { // we can honour the modeswitch
if (mode_msg->mode == EMC_TASK_MODE_MANUAL &&
emcStatus->task.mode != EMC_TASK_MODE_MANUAL) {
// leaving auto or mdi mode for manual
/*! \todo FIXME-- duplicate code for abort,
also near end of main, when aborting on subordinate errors,
and in emcTaskExecute() */
// abort motion
emcTaskAbort();
mdi_execute_abort();
// without emcTaskPlanClose(), a new run command resumes at
// aborted line-- feature that may be considered later
{
int was_open = taskplanopen;
emcTaskPlanClose();
if (emc_debug & EMC_DEBUG_INTERP && was_open) {
rcs_print("emcTaskPlanClose() called at %s:%d\n",
__FILE__, __LINE__);
}
}
// clear out the pending command
emcTaskCommand = 0;
interp_list.clear();
emcStatus->task.currentLine = 0;
// clear out the interpreter state
emcStatus->task.interpState = EMC_TASK_INTERP_IDLE;
emcStatus->task.execState = EMC_TASK_EXEC_DONE;
stepping = 0;
steppingWait = 0;
// now queue up command to resynch interpreter
emcTaskQueueCommand(&taskPlanSynchCmd);
}
retval = emcTaskSetMode(mode_msg->mode);
}
break;
case EMC_TASK_SET_STATE_TYPE:
state_msg = (EMC_TASK_SET_STATE *) cmd;
retval = emcTaskSetState(state_msg->state);
break;
// interpreter commands
case EMC_TASK_PLAN_CLOSE_TYPE:
retval = emcTaskPlanClose();
if (retval > INTERP_MIN_ERROR) {
emcOperatorError(0, _("failed to close file"));
retval = -1;
} else {
retval = 0;
}
break;
case EMC_TASK_PLAN_OPEN_TYPE:
open_msg = (EMC_TASK_PLAN_OPEN *) cmd;
retval = emcTaskPlanOpen(open_msg->file);
if (retval > INTERP_MIN_ERROR) {
retval = -1;
}
if (-1 == retval) {
emcOperatorError(0, _("can't open %s"), open_msg->file);
} else {
rtapi_strxcpy(emcStatus->task.file, open_msg->file);
retval = 0;
}
break;
case EMC_TASK_PLAN_EXECUTE_TYPE:
stepping = 0;
steppingWait = 0;
execute_msg = (EMC_TASK_PLAN_EXECUTE *) cmd;
if (!all_homed() && !no_force_homing) { //!no_force_homing = force homing before MDI
emcOperatorError(0, _("Can't issue MDI command when not homed"));
retval = -1;
break;
}
if (emcStatus->task.mode != EMC_TASK_MODE_MDI) {
emcOperatorError(0, _("Must be in MDI mode to issue MDI command"));
retval = -1;
break;
}
// track interpState also during MDI - it might be an oword sub call
emcStatus->task.interpState = EMC_TASK_INTERP_READING;
if (execute_msg->command[0] != 0) {
char * command = execute_msg->command;
if (command[0] == (char) 0xff) {
// Empty command received. Consider it is NULL
command = NULL;
} else {
// record initial MDI command
rtapi_strxcpy(emcStatus->task.command, execute_msg->command);
}
int level = emcTaskPlanLevel();
if (emcStatus->task.mode == EMC_TASK_MODE_MDI) {
if (mdi_execute_level < 0)
mdi_execute_level = level;
}
execRetval = emcTaskPlanExecute(command, 0);
level = emcTaskPlanLevel();
if (emcStatus->task.mode == EMC_TASK_MODE_MDI) {
if (mdi_execute_level == level) {
mdi_execute_level = -1;
} else if (level > 0) {
// Still insude call. Need another execute(0) call
// but only if we didnt encounter an error
if (execRetval == INTERP_ERROR) {
mdi_execute_next = 0;
} else {
mdi_execute_next = 1;
}
}
}
switch (execRetval) {
case INTERP_EXECUTE_FINISH:
// Flag MDI wait
mdi_execute_wait = 1;
// need to flush execution, so signify no more reading
// until all is done
emcTaskPlanSetWait();
// and resynch the interpreter WM
emcTaskQueueCommand(&taskPlanSynchCmd);
// it's success, so retval really is 0
retval = 0;
break;
case INTERP_ERROR:
// emcStatus->task.interpState = EMC_TASK_INTERP_WAITING;
interp_list.clear();
// abort everything
emcTaskAbort();
emcIoAbort(EMC_ABORT_INTERPRETER_ERROR_MDI);
for (int s = 0; s < emcStatus->motion.traj.spindles; s++) emcSpindleAbort(s);
mdi_execute_abort(); // sets emcStatus->task.interpState to EMC_TASK_INTERP_IDLE
emcAbortCleanup(EMC_ABORT_INTERPRETER_ERROR_MDI, "interpreter error during MDI");
retval = -1;
break;
case INTERP_EXIT:
case INTERP_ENDFILE:
case INTERP_FILE_NOT_OPEN:
// this caused the error msg on M2 in MDI mode - execRetval == INTERP_EXIT which is would be ok (I think). mah
retval = -1;
break;
default:
// other codes are OK
retval = 0;
}
}
break;
case EMC_TASK_PLAN_RUN_TYPE:
if (!all_homed() && !no_force_homing) { //!no_force_homing = force homing before Auto
emcOperatorError(0, _("Can't run a program when not homed"));
retval = -1;
break;
}
stepping = 0;
steppingWait = 0;
if (!taskplanopen && emcStatus->task.file[0] != 0) {
emcTaskPlanOpen(emcStatus->task.file);
}
run_msg = (EMC_TASK_PLAN_RUN *) cmd;
programStartLine = run_msg->line;
emcStatus->task.interpState = EMC_TASK_INTERP_READING;
emcStatus->task.task_paused = 0;
retval = 0;
break;
case EMC_TASK_PLAN_PAUSE_TYPE:
emcTrajPause();
if (emcStatus->task.interpState != EMC_TASK_INTERP_PAUSED) {
interpResumeState = emcStatus->task.interpState;
}
emcStatus->task.interpState = EMC_TASK_INTERP_PAUSED;
emcStatus->task.task_paused = 1;
retval = 0;
break;
case EMC_TASK_PLAN_OPTIONAL_STOP_TYPE:
if (GET_OPTIONAL_PROGRAM_STOP() == ON) {
emcTrajPause();
if (emcStatus->task.interpState != EMC_TASK_INTERP_PAUSED) {
interpResumeState = emcStatus->task.interpState;
}
emcStatus->task.interpState = EMC_TASK_INTERP_PAUSED;
emcStatus->task.task_paused = 1;
}
retval = 0;
break;
case EMC_TASK_PLAN_REVERSE_TYPE:
emcTrajReverse();
retval = 0;
break;
case EMC_TASK_PLAN_FORWARD_TYPE:
emcTrajForward();
retval = 0;
break;
case EMC_TASK_PLAN_RESUME_TYPE:
emcTrajResume();
emcStatus->task.interpState =
(enum EMC_TASK_INTERP_ENUM) interpResumeState;
emcStatus->task.task_paused = 0;
stepping = 0;
steppingWait = 0;
retval = 0;
break;
case EMC_TASK_PLAN_END_TYPE:
retval = 0;
break;
case EMC_TASK_PLAN_INIT_TYPE:
retval = emcTaskPlanInit();
if (retval > INTERP_MIN_ERROR) {
retval = -1;
}
break;
case EMC_TASK_PLAN_SYNCH_TYPE:
retval = emcTaskPlanSynch();
if (retval > INTERP_MIN_ERROR) {
retval = -1;
}
break;
case EMC_TASK_PLAN_SET_OPTIONAL_STOP_TYPE:
os_msg = (EMC_TASK_PLAN_SET_OPTIONAL_STOP *) cmd;
emcTaskPlanSetOptionalStop(os_msg->state);
retval = 0;
break;
case EMC_TASK_PLAN_SET_BLOCK_DELETE_TYPE:
bd_msg = (EMC_TASK_PLAN_SET_BLOCK_DELETE *) cmd;
emcTaskPlanSetBlockDelete(bd_msg->state);
retval = 0;
break;
case EMC_EXEC_PLUGIN_CALL_TYPE:
retval = emcPluginCall( (EMC_EXEC_PLUGIN_CALL *) cmd);
break;
case EMC_IO_PLUGIN_CALL_TYPE:
retval = emcIoPluginCall( (EMC_IO_PLUGIN_CALL *) cmd);
break;
default:
// unrecognized command
if (emc_debug & EMC_DEBUG_TASK_ISSUE) {
rcs_print_error("ignoring issue of unknown command %d:%s\n",
(int)cmd->type, emc_symbol_lookup(cmd->type));
}
retval = 0; // don't consider this an error
break;
}
if (retval == -1) {
if (emc_debug & EMC_DEBUG_TASK_ISSUE) {
rcs_print_error("error executing command %d:%s\n", (int)cmd->type,
emc_symbol_lookup(cmd->type));
}
}
/* debug */
if ((emc_debug & EMC_DEBUG_TASK_ISSUE) && retval) {
rcs_print("emcTaskIssueCommand() returning: %d\n", retval);
}
return retval;
}
/*
emcTaskCheckPostconditions() is called for commands on the interp_list.
Immediate commands, i.e., commands sent from calls to emcTaskIssueCommand()
in emcTaskPlan() directly, are not handled here.
The return value is a state for emcTaskExecute() to wait on, e.g.,
EMC_TASK_EXEC_WAITING_FOR_MOTION, after the command has finished and
before any other commands can be sent out.
*/
static int emcTaskCheckPostconditions(NMLmsg * cmd)
{
if (0 == cmd) {
return EMC_TASK_EXEC_DONE;
}
switch (cmd->type) {
case EMC_OPERATOR_ERROR_TYPE:
case EMC_OPERATOR_TEXT_TYPE:
case EMC_OPERATOR_DISPLAY_TYPE:
return EMC_TASK_EXEC_DONE;
break;
case EMC_SYSTEM_CMD_TYPE:
return EMC_TASK_EXEC_WAITING_FOR_SYSTEM_CMD;
break;
case EMC_TRAJ_LINEAR_MOVE_TYPE:
case EMC_TRAJ_CIRCULAR_MOVE_TYPE:
case EMC_TRAJ_SET_VELOCITY_TYPE:
case EMC_TRAJ_SET_ACCELERATION_TYPE:
case EMC_TRAJ_SET_TERM_COND_TYPE:
case EMC_TRAJ_SET_SPINDLESYNC_TYPE:
case EMC_TRAJ_SET_OFFSET_TYPE:
case EMC_TRAJ_SET_G5X_TYPE:
case EMC_TRAJ_SET_G92_TYPE:
case EMC_TRAJ_SET_ROTATION_TYPE:
case EMC_TRAJ_PROBE_TYPE:
case EMC_TRAJ_RIGID_TAP_TYPE:
case EMC_TRAJ_CLEAR_PROBE_TRIPPED_FLAG_TYPE:
case EMC_TRAJ_SET_TELEOP_ENABLE_TYPE:
case EMC_TRAJ_SET_FO_ENABLE_TYPE:
case EMC_TRAJ_SET_FH_ENABLE_TYPE:
case EMC_TRAJ_SET_SO_ENABLE_TYPE:
return EMC_TASK_EXEC_DONE;
break;
case EMC_TOOL_PREPARE_TYPE:
case EMC_TOOL_LOAD_TYPE:
case EMC_TOOL_UNLOAD_TYPE:
case EMC_TOOL_LOAD_TOOL_TABLE_TYPE:
case EMC_TOOL_START_CHANGE_TYPE:
case EMC_TOOL_SET_OFFSET_TYPE:
case EMC_TOOL_SET_NUMBER_TYPE:
case EMC_SPINDLE_SPEED_TYPE:
case EMC_SPINDLE_ON_TYPE:
case EMC_SPINDLE_OFF_TYPE:
case EMC_SPINDLE_ORIENT_TYPE:
case EMC_COOLANT_MIST_ON_TYPE:
case EMC_COOLANT_MIST_OFF_TYPE:
case EMC_COOLANT_FLOOD_ON_TYPE:
case EMC_COOLANT_FLOOD_OFF_TYPE:
case EMC_LUBE_ON_TYPE:
case EMC_LUBE_OFF_TYPE:
return EMC_TASK_EXEC_DONE;
break;
case EMC_TASK_PLAN_RUN_TYPE:
case EMC_TASK_PLAN_PAUSE_TYPE:
case EMC_TASK_PLAN_END_TYPE:
case EMC_TASK_PLAN_INIT_TYPE:
case EMC_TASK_PLAN_SYNCH_TYPE:
case EMC_TASK_PLAN_EXECUTE_TYPE:
case EMC_TASK_PLAN_OPTIONAL_STOP_TYPE:
return EMC_TASK_EXEC_DONE;
break;
case EMC_SPINDLE_WAIT_ORIENT_COMPLETE_TYPE:
return EMC_TASK_EXEC_WAITING_FOR_SPINDLE_ORIENTED;
break;
case EMC_TRAJ_DELAY_TYPE:
case EMC_AUX_INPUT_WAIT_TYPE:
return EMC_TASK_EXEC_WAITING_FOR_DELAY;
break;
case EMC_MOTION_SET_AOUT_TYPE:
case EMC_MOTION_SET_DOUT_TYPE:
case EMC_MOTION_ADAPTIVE_TYPE:
return EMC_TASK_EXEC_DONE;
break;
case EMC_EXEC_PLUGIN_CALL_TYPE:
case EMC_IO_PLUGIN_CALL_TYPE:
return EMC_TASK_EXEC_DONE;
break;
default:
// unrecognized command
if (emc_debug & EMC_DEBUG_TASK_ISSUE) {
rcs_print_error("postconditions: unrecognized command %d:%s\n",
(int)cmd->type, emc_symbol_lookup(cmd->type));
}
return EMC_TASK_EXEC_DONE;
break;
}
return EMC_TASK_EXEC_DONE; // unreached
}
/*
STEPPING_CHECK() is a macro that prefaces a switch-case with a check
for stepping. If stepping is active, it waits until the step has been
given, then falls through to the rest of the case statement.
*/
#define STEPPING_CHECK() \
if (stepping) { \
if (! steppingWait) { \
steppingWait = 1; \
steppedLine = emcStatus->task.currentLine; \
} \
else { \
if (emcStatus->task.currentLine != steppedLine) { \
break; \
} \
} \
}
// executor function
static int emcTaskExecute(void)
{
int retval = 0;
int status; // status of child from EMC_SYSTEM_CMD
pid_t pid; // pid returned from waitpid()
// first check for an abandoned system command and abort it
if (emcSystemCmdPid != 0 &&
emcStatus->task.execState !=
EMC_TASK_EXEC_WAITING_FOR_SYSTEM_CMD) {
if (emc_debug & EMC_DEBUG_TASK_ISSUE) {
rcs_print("emcSystemCmd: abandoning process %d\n",
emcSystemCmdPid);
}
kill(emcSystemCmdPid, SIGINT);
emcSystemCmdPid = 0;
}
switch (emcStatus->task.execState) {
case EMC_TASK_EXEC_ERROR:
/*! \todo FIXME-- duplicate code for abort,
also near end of main, when aborting on subordinate errors,
and in emcTaskIssueCommand() */
// abort everything
emcTaskAbort();
emcIoAbort(EMC_ABORT_TASK_EXEC_ERROR);
for (int s = 0; s < emcStatus->motion.traj.spindles; s++) emcSpindleAbort(s);
mdi_execute_abort();
// without emcTaskPlanClose(), a new run command resumes at
// aborted line-- feature that may be considered later
{
int was_open = taskplanopen;
emcTaskPlanClose();
emcTaskPlanReset(); // Flush any unflushed segments
if (emc_debug & EMC_DEBUG_INTERP && was_open) {
rcs_print("emcTaskPlanClose() called at %s:%d\n", __FILE__,
__LINE__);
}
}
// clear out pending command
emcTaskCommand = 0;
interp_list.clear();
emcAbortCleanup(EMC_ABORT_TASK_EXEC_ERROR);
emcStatus->task.currentLine = 0;
// clear out the interpreter state
emcStatus->task.interpState = EMC_TASK_INTERP_IDLE;
emcStatus->task.execState = EMC_TASK_EXEC_DONE;
stepping = 0;
steppingWait = 0;
// now queue up command to resynch interpreter
emcTaskQueueCommand(&taskPlanSynchCmd);
retval = -1;
break;
case EMC_TASK_EXEC_DONE:
STEPPING_CHECK();
if (!emcStatus->motion.traj.queueFull &&
emcStatus->task.interpState != EMC_TASK_INTERP_PAUSED) {
if (0 == emcTaskCommand) {
// need a new command
emcTaskCommand = interp_list.get();
// interp_list now has line number associated with this-- get
// it
if (0 != emcTaskCommand) {
emcTaskEager = 1;
emcStatus->task.currentLine =
interp_list.get_line_number();
emcStatus->task.callLevel = emcTaskPlanLevel();
// and set it for all subsystems which use queued ids
emcTrajSetMotionId(emcStatus->task.currentLine);
if (emcStatus->motion.traj.queueFull) {
emcStatus->task.execState =
EMC_TASK_EXEC_WAITING_FOR_MOTION_QUEUE;
} else {
emcStatus->task.execState =
(enum EMC_TASK_EXEC_ENUM)
emcTaskCheckPreconditions(emcTaskCommand);
}
}
} else {
// have an outstanding command
if (0 != emcTaskIssueCommand(emcTaskCommand)) {
emcStatus->task.execState = EMC_TASK_EXEC_ERROR;
retval = -1;
} else {
emcStatus->task.execState = (enum EMC_TASK_EXEC_ENUM)
emcTaskCheckPostconditions(emcTaskCommand);
emcTaskEager = 1;
}
emcTaskCommand = 0; // reset it
}
}
break;
case EMC_TASK_EXEC_WAITING_FOR_MOTION_QUEUE:
STEPPING_CHECK();
if (!emcStatus->motion.traj.queueFull) {
if (0 != emcTaskCommand) {
emcStatus->task.execState = (enum EMC_TASK_EXEC_ENUM)
emcTaskCheckPreconditions(emcTaskCommand);
emcTaskEager = 1;
} else {
emcStatus->task.execState = EMC_TASK_EXEC_DONE;
emcTaskEager = 1;
}
}
break;
case EMC_TASK_EXEC_WAITING_FOR_MOTION:
STEPPING_CHECK();
if (emcStatus->motion.status == RCS_ERROR) {
// emcOperatorError(0, "error in motion controller");
emcStatus->task.execState = EMC_TASK_EXEC_ERROR;
} else if (emcStatus->motion.status == RCS_DONE) {
emcStatus->task.execState = EMC_TASK_EXEC_DONE;
emcTaskEager = 1;
}
break;
case EMC_TASK_EXEC_WAITING_FOR_IO:
STEPPING_CHECK();
if (emcStatus->io.status == RCS_ERROR) {
// emcOperatorError(0, "error in IO controller");
emcStatus->task.execState = EMC_TASK_EXEC_ERROR;
} else if (emcStatus->io.status == RCS_DONE) {
emcStatus->task.execState = EMC_TASK_EXEC_DONE;
emcTaskEager = 1;
}
break;
case EMC_TASK_EXEC_WAITING_FOR_MOTION_AND_IO:
STEPPING_CHECK();
if (emcStatus->motion.status == RCS_ERROR) {
// emcOperatorError(0, "error in motion controller");
emcStatus->task.execState = EMC_TASK_EXEC_ERROR;
} else if (emcStatus->io.status == RCS_ERROR) {
// emcOperatorError(0, "error in IO controller");
emcStatus->task.execState = EMC_TASK_EXEC_ERROR;
} else if (emcStatus->motion.status == RCS_DONE &&
emcStatus->io.status == RCS_DONE) {
emcStatus->task.execState = EMC_TASK_EXEC_DONE;
emcTaskEager = 1;
}
break;
case EMC_TASK_EXEC_WAITING_FOR_SPINDLE_ORIENTED:
STEPPING_CHECK(); // not sure
{int state = 0;
for (int n = 0; n < emcStatus->motion.traj.spindles; n++){
if (emcStatus->motion.spindle[n].orient_state > state)
state = emcStatus->motion.spindle[n].orient_state;
}
switch (state) {
case EMCMOT_ORIENT_NONE:
case EMCMOT_ORIENT_COMPLETE:
emcStatus->task.execState = EMC_TASK_EXEC_DONE;
emcStatus->task.delayLeft = 0;
emcTaskEager = 1;
rcs_print("wait for orient complete: nothing to do\n");
break;
case EMCMOT_ORIENT_IN_PROGRESS:
emcStatus->task.delayLeft = taskExecDelayTimeout - etime();
if (etime() >= taskExecDelayTimeout) {
emcStatus->task.execState = EMC_TASK_EXEC_ERROR;
emcStatus->task.delayLeft = 0;
emcTaskEager = 1;
emcOperatorError(0, "wait for orient complete: TIMED OUT");
}
break;
case EMCMOT_ORIENT_FAULTED:
// actually the code in main() should trap this before we get here
emcStatus->task.execState = EMC_TASK_EXEC_ERROR;
emcStatus->task.delayLeft = 0;
emcTaskEager = 1;
for (int n = 0; n < emcStatus->motion.traj.spindles; n++){
if (emcStatus->motion.spindle[n].orient_fault)
emcOperatorError(0, "wait for orient complete: FAULTED code=%d",
emcStatus->motion.spindle[n].orient_fault);
}
}
}
break;
case EMC_TASK_EXEC_WAITING_FOR_DELAY:
STEPPING_CHECK();
// check if delay has passed
emcStatus->task.delayLeft = taskExecDelayTimeout - etime();
if (etime() >= taskExecDelayTimeout) {
emcStatus->task.execState = EMC_TASK_EXEC_DONE;
emcStatus->task.delayLeft = 0;
if (emcStatus->task.input_timeout != 0)
emcStatus->task.input_timeout = 1; // timeout occurred
emcTaskEager = 1;
}
// delay can be also be because we wait for an input
// if the index is set (not -1)
if (emcAuxInputWaitIndex >= 0) {
switch (emcAuxInputWaitType) {
case WAIT_MODE_HIGH:
if (emcStatus->motion.synch_di[emcAuxInputWaitIndex] != 0) {
emcStatus->task.input_timeout = 0; // clear timeout flag
emcAuxInputWaitIndex = -1;
emcStatus->task.execState = EMC_TASK_EXEC_DONE;
emcStatus->task.delayLeft = 0;
}
break;
case WAIT_MODE_RISE:
if (emcStatus->motion.synch_di[emcAuxInputWaitIndex] == 0) {
emcAuxInputWaitType = WAIT_MODE_HIGH;
}
break;
case WAIT_MODE_LOW:
if (emcStatus->motion.synch_di[emcAuxInputWaitIndex] == 0) {
emcStatus->task.input_timeout = 0; // clear timeout flag
emcAuxInputWaitIndex = -1;
emcStatus->task.execState = EMC_TASK_EXEC_DONE;
emcStatus->task.delayLeft = 0;
}
break;
case WAIT_MODE_FALL: //FIXME: implement different fall mode if needed
if (emcStatus->motion.synch_di[emcAuxInputWaitIndex] != 0) {
emcAuxInputWaitType = WAIT_MODE_LOW;
}
break;
case WAIT_MODE_IMMEDIATE:
emcStatus->task.input_timeout = 0; // clear timeout flag
emcAuxInputWaitIndex = -1;
emcStatus->task.execState = EMC_TASK_EXEC_DONE;
emcStatus->task.delayLeft = 0;
break;
default:
emcOperatorError(0, "Unknown Wait Mode");
}
}
break;
case EMC_TASK_EXEC_WAITING_FOR_SYSTEM_CMD:
STEPPING_CHECK();
// if we got here without a system command pending, say we're done
if (0 == emcSystemCmdPid) {
emcStatus->task.execState = EMC_TASK_EXEC_DONE;
break;
}
// check the status of the system command
pid = waitpid(emcSystemCmdPid, &status, WNOHANG);
if (0 == pid) {
// child is still executing
break;
}
if (-1 == pid) {
// execution error
if (emc_debug & EMC_DEBUG_TASK_ISSUE) {
rcs_print("emcSystemCmd: error waiting for %d\n",
emcSystemCmdPid);
}
emcSystemCmdPid = 0;
emcStatus->task.execState = EMC_TASK_EXEC_ERROR;
break;
}
if (emcSystemCmdPid != pid) {
// somehow some other child finished, which is a coding error
if (emc_debug & EMC_DEBUG_TASK_ISSUE) {
rcs_print
("emcSystemCmd: error waiting for system command %d, we got %d\n",
emcSystemCmdPid, pid);
}
emcSystemCmdPid = 0;
emcStatus->task.execState = EMC_TASK_EXEC_ERROR;
break;
}
// else child has finished
if (WIFEXITED(status)) {
if (0 == WEXITSTATUS(status)) {
// child exited normally
emcSystemCmdPid = 0;
emcStatus->task.execState = EMC_TASK_EXEC_DONE;
emcTaskEager = 1;
} else {
// child exited with non-zero status
if (emc_debug & EMC_DEBUG_TASK_ISSUE) {
rcs_print
("emcSystemCmd: system command %d exited abnormally with value %d\n",
emcSystemCmdPid, WEXITSTATUS(status));
}
emcSystemCmdPid = 0;
emcStatus->task.execState = EMC_TASK_EXEC_ERROR;
}
} else if (WIFSIGNALED(status)) {
// child exited with an uncaught signal
if (emc_debug & EMC_DEBUG_TASK_ISSUE) {
rcs_print("system command %d terminated with signal %d\n",
emcSystemCmdPid, WTERMSIG(status));
}
emcSystemCmdPid = 0;
emcStatus->task.execState = EMC_TASK_EXEC_ERROR;
} else if (WIFSTOPPED(status)) {
// child is currently being traced, so keep waiting
} else {
// some other status, we'll call this an error
emcSystemCmdPid = 0;
emcStatus->task.execState = EMC_TASK_EXEC_ERROR;
}
break;
default:
// coding error
if (emc_debug & EMC_DEBUG_TASK_ISSUE) {
rcs_print_error("invalid execState");
}
retval = -1;
break;
}
return retval;
}
// called to allocate and init resources
static int emctask_startup()
{
double end;
int good;
#define RETRY_TIME 10.0 // seconds to wait for subsystems to come up
#define RETRY_INTERVAL 1.0 // seconds between wait tries for a subsystem
// moved up so it can be exposed in taskmodule at init time
// // get our status data structure
// emcStatus = new EMC_STAT;
// get the NML command buffer
if (!(emc_debug & EMC_DEBUG_NML)) {
set_rcs_print_destination(RCS_PRINT_TO_NULL); // inhibit diag
// messages
}
end = RETRY_TIME;
good = 0;
do {
if (NULL != emcCommandBuffer) {
delete emcCommandBuffer;
}
emcCommandBuffer =
new RCS_CMD_CHANNEL(emcFormat, "emcCommand", "emc",
emc_nmlfile);
if (emcCommandBuffer->valid()) {
good = 1;
break;
}
esleep(RETRY_INTERVAL);
end -= RETRY_INTERVAL;
if (done) {
emctask_shutdown();
exit(1);
}
} while (end > 0.0);
set_rcs_print_destination(RCS_PRINT_TO_STDOUT); // restore diag
// messages
if (!good) {
rcs_print_error("can't get emcCommand buffer\n");
return -1;
}
// get our command data structure
emcCommand = emcCommandBuffer->get_address();
// get the NML status buffer
if (!(emc_debug & EMC_DEBUG_NML)) {
set_rcs_print_destination(RCS_PRINT_TO_NULL); // inhibit diag
// messages
}
end = RETRY_TIME;
good = 0;
do {
if (NULL != emcStatusBuffer) {
delete emcStatusBuffer;
}
emcStatusBuffer =
new RCS_STAT_CHANNEL(emcFormat, "emcStatus", "emc",
emc_nmlfile);
if (emcStatusBuffer->valid()) {
good = 1;
break;
}
esleep(RETRY_INTERVAL);
end -= RETRY_INTERVAL;
if (done) {
emctask_shutdown();
exit(1);
}
} while (end > 0.0);
set_rcs_print_destination(RCS_PRINT_TO_STDOUT); // restore diag
// messages
if (!good) {
rcs_print_error("can't get emcStatus buffer\n");
return -1;
}
if (!(emc_debug & EMC_DEBUG_NML)) {
set_rcs_print_destination(RCS_PRINT_TO_NULL); // inhibit diag
// messages
}
end = RETRY_TIME;
good = 0;
do {
if (NULL != emcErrorBuffer) {
delete emcErrorBuffer;
}
emcErrorBuffer =
new NML(nmlErrorFormat, "emcError", "emc", emc_nmlfile);
if (emcErrorBuffer->valid()) {
good = 1;
break;
}
esleep(RETRY_INTERVAL);
end -= RETRY_INTERVAL;
if (done) {
emctask_shutdown();
exit(1);
}
} while (end > 0.0);
set_rcs_print_destination(RCS_PRINT_TO_STDOUT); // restore diag
// messages
if (!good) {
rcs_print_error("can't get emcError buffer\n");
return -1;
}
// get the timer
if (!emcTaskNoDelay) {
timer = new RCS_TIMER(emc_task_cycle_time, "", "");
}
// initialize the subsystems
// IO first
if (!(emc_debug & EMC_DEBUG_NML)) {
set_rcs_print_destination(RCS_PRINT_TO_NULL); // inhibit diag
// messages
}
end = RETRY_TIME;
good = 0;
do {
if (0 == emcIoInit()) {
good = 1;
break;
}
esleep(RETRY_INTERVAL);
end -= RETRY_INTERVAL;
if (done) {
emctask_shutdown();
exit(1);
}
} while (end > 0.0);
set_rcs_print_destination(RCS_PRINT_TO_STDOUT); // restore diag
// messages
if (!good) {
rcs_print_error("can't initialize IO\n");
return -1;
}
end = RETRY_TIME;
good = 0;
do {
if (0 == emcIoUpdate(&emcStatus->io)) {
good = 1;
break;
}
esleep(RETRY_INTERVAL);
end -= RETRY_INTERVAL;
if (done) {
emctask_shutdown();
exit(1);
}
} while (end > 0.0);
if (!good) {
rcs_print_error("can't read IO status\n");
return -1;
}
// now motion
end = RETRY_TIME;
good = 0;
do {
if (0 == emcMotionInit()) {
good = 1;
break;
}
esleep(RETRY_INTERVAL);
end -= RETRY_INTERVAL;
if (done) {
emctask_shutdown();
exit(1);
}
} while (end > 0.0);
if (!good) {
rcs_print_error("can't initialize motion\n");
return -1;
}
if (setup_inihal() != 0) {
rcs_print_error("%s: failed to setup inihal\n", __FUNCTION__);
return -1;
}
end = RETRY_TIME;
good = 0;
do {
if (0 == emcMotionUpdate(&emcStatus->motion)) {
good = 1;
break;
}
esleep(RETRY_INTERVAL);
end -= RETRY_INTERVAL;
if (done) {
emctask_shutdown();
exit(1);
}
} while (end > 0.0);
if (!good) {
rcs_print_error("can't read motion status\n");
return -1;
}
// now the interpreter
if (0 != emcTaskPlanInit()) {
rcs_print_error("can't initialize interpreter\n");
return -1;
}
if (done ) {
emctask_shutdown();
exit(1);
}
// now task
if (0 != emcTaskInit()) {
rcs_print_error("can't initialize task\n");
return -1;
}
emcTaskUpdate(&emcStatus->task);
return 0;
}
// called to deallocate resources
static int emctask_shutdown(void)
{
// shut down the subsystems
if (0 != emcStatus) {
emcTaskHalt();
emcTaskPlanExit();
emcMotionHalt();
emcIoHalt();
}
// delete the timer
if (0 != timer) {
delete timer;
timer = 0;
}
// delete the NML channels
if (0 != emcErrorBuffer) {
delete emcErrorBuffer;
emcErrorBuffer = 0;
}
if (0 != emcStatusBuffer) {
delete emcStatusBuffer;
emcStatusBuffer = 0;
emcStatus = 0;
}
if (0 != emcCommandBuffer) {
delete emcCommandBuffer;
emcCommandBuffer = 0;
emcCommand = 0;
}
if (0 != emcStatus) {
delete emcStatus;
emcStatus = 0;
}
return 0;
}
static int iniLoad(const char *filename)
{
IniFile inifile;
const char *inistring;
char version[LINELEN], machine[LINELEN];
double saveDouble;
int saveInt;
// open it
if (inifile.Open(filename) == false) {
return -1;
}
if (NULL != (inistring = inifile.Find("DEBUG", "EMC"))) {
// copy to global
if (1 != sscanf(inistring, "%i", &emc_debug)) {
emc_debug = 0;
}
} else {
// not found, use default
emc_debug = 0;
}
if (emc_debug & EMC_DEBUG_RCS) {
// set_rcs_print_flag(PRINT_EVERYTHING);
max_rcs_errors_to_print = -1;
}
if (emc_debug & EMC_DEBUG_VERSIONS) {
if (NULL != (inistring = inifile.Find("VERSION", "EMC"))) {
if(sscanf(inistring, "$Revision: %s", version) != 1) {
strncpy(version, "unknown", LINELEN-1);
}
} else {
strncpy(version, "unknown", LINELEN-1);
}
if (NULL != (inistring = inifile.Find("MACHINE", "EMC"))) {
strncpy(machine, inistring, LINELEN-1);
} else {
strncpy(machine, "unknown", LINELEN-1);
}
rcs_print("task: machine: '%s' version '%s'\n", machine, version);
}
if (NULL != (inistring = inifile.Find("NML_FILE", "EMC"))) {
// copy to global
rtapi_strxcpy(emc_nmlfile, inistring);
} else {
// not found, use default
}
saveInt = emc_task_interp_max_len; //remember default or previously set value
if (NULL != (inistring = inifile.Find("INTERP_MAX_LEN", "TASK"))) {
if (1 == sscanf(inistring, "%d", &emc_task_interp_max_len)) {
if (emc_task_interp_max_len <= 0) {
emc_task_interp_max_len = saveInt;
}
} else {
emc_task_interp_max_len = saveInt;
}
}
if (NULL != (inistring = inifile.Find("RS274NGC_STARTUP_CODE", "RS274NGC"))) {
// copy to global
rtapi_strxcpy(rs274ngc_startup_code, inistring);
} else {
//FIXME-AJ: this is the old (unpreferred) location. just for compatibility purposes
//it will be dropped in v2.4
if (NULL != (inistring = inifile.Find("RS274NGC_STARTUP_CODE", "EMC"))) {
// copy to global
rtapi_strxcpy(rs274ngc_startup_code, inistring);
} else {
// not found, use default
}
}
saveDouble = emc_task_cycle_time;
EMC_TASK_CYCLE_TIME_ORIG = emc_task_cycle_time;
emcTaskNoDelay = 0;
if (NULL != (inistring = inifile.Find("CYCLE_TIME", "TASK"))) {
if (1 == sscanf(inistring, "%lf", &emc_task_cycle_time)) {
// found it
// if it's <= 0.0, then flag that we don't want to
// wait at all, which will set the EMC_TASK_CYCLE_TIME
// global to the actual time deltas
if (emc_task_cycle_time <= 0.0) {
emcTaskNoDelay = 1;
}
} else {
// found, but invalid
emc_task_cycle_time = saveDouble;
rcs_print
("invalid [TASK] CYCLE_TIME in %s (%s); using default %f\n",
filename, inistring, emc_task_cycle_time);
}
} else {
// not found, using default
rcs_print("[TASK] CYCLE_TIME not found in %s; using default %f\n",
filename, emc_task_cycle_time);
}
if (NULL != (inistring = inifile.Find("NO_FORCE_HOMING", "TRAJ"))) {
if (1 == sscanf(inistring, "%d", &no_force_homing)) {
// found it
// if it's <= 0.0, then set it 0 so that homing is required before MDI or Auto
if (no_force_homing <= 0) {
no_force_homing = 0;
}
} else {
// found, but invalid
no_force_homing = 0;
rcs_print
("invalid [TRAJ] NO_FORCE_HOMING in %s (%s); using default %d\n",
filename, inistring, no_force_homing);
}
} else {
// not found, using default
no_force_homing = 0;
}
// configurable template for iocontrol reason display
if (NULL != (inistring = inifile.Find("IO_ERROR", "TASK"))) {
io_error = strdup(inistring);
}
// max number of queued MDI commands
if (NULL != (inistring = inifile.Find("MDI_QUEUED_COMMANDS", "TASK"))) {
max_mdi_queued_commands = atoi(inistring);
}
// close it
inifile.Close();
return 0;
}
/*
syntax: a.out {-d -ini <inifile>} {-nml <nmlfile>} {-shm <key>}
*/
int main(int argc, char *argv[])
{
int taskPlanError = 0;
int taskExecuteError = 0;
double startTime, endTime, deltaTime;
double first_start_time;
int num_latency_warnings = 0;
int latency_excursion_factor = 10; // if latency is worse than (factor * expected), it's an excursion
double minTime, maxTime;
bindtextdomain("linuxcnc", EMC2_PO_DIR);
setlocale(LC_MESSAGES,"");
setlocale(LC_CTYPE,"");
textdomain("linuxcnc");
// loop until done
done = 0;
// trap ^C
signal(SIGINT, emctask_quit);
// and SIGTERM (used by runscript to shut down)
signal(SIGTERM, emctask_quit);
// create a backtrace on stderr
signal(SIGSEGV, backtrace);
signal(SIGFPE, backtrace);
signal(SIGUSR1, backtrace);
// set print destination to stdout, for console apps
set_rcs_print_destination(RCS_PRINT_TO_STDOUT);
// process command line args
if (0 != emcGetArgs(argc, argv)) {
rcs_print_error("error in argument list\n");
exit(1);
}
if (done) {
emctask_shutdown();
exit(1);
}
if (done) {
emctask_shutdown();
exit(1);
}
// get configuration information
iniLoad(emc_inifile);
if (done) {
emctask_shutdown();
exit(1);
}
// get our status data structure
// moved up from emc_startup so we can expose it in Python right away
emcStatus = new EMC_STAT;
// get the Python plugin going
// inistantiate task methods object, too
emcTaskOnce(emc_inifile);
if (task_methods == NULL) {
set_rcs_print_destination(RCS_PRINT_TO_STDOUT); // restore diag
rcs_print_error("can't initialize Task methods\n");
emctask_shutdown();
exit(1);
}
// this is the place to run any post-HAL-creation halcmd files
emcRunHalFiles(emc_inifile);
// initialize everything
if (0 != emctask_startup()) {
emctask_shutdown();
exit(1);
}
// set the default startup modes
emcMotionAbort();
for (int s = 0; s < emcStatus->motion.traj.spindles; s++) emcSpindleAbort(s);
emcAuxEstopOn();
for (int t = 0; t < emcStatus->motion.traj.joints; t++) {
emcJointDisable(t);
}
emcTrajDisable();
emcLubeOff();
emcIoAbort(EMC_ABORT_TASK_STATE_ESTOP);
emcJointUnhome(-2);
emcTrajSetMode(EMC_TRAJ_MODE_FREE);
// reflect the initial value of EMC_DEBUG in emcStatus->debug
emcStatus->debug = emc_debug;
startTime = etime(); // set start time before entering loop;
first_start_time = startTime;
endTime = startTime;
// it will be set at end of loop from now on
minTime = DBL_MAX; // set to value that can never be exceeded
maxTime = 0.0; // set to value that can never be underset
if (0 != usrmotReadEmcmotConfig(&emcmotConfig)) {
rcs_print("%s failed usrmotReadEmcmotconfig()\n",__FILE__);
}
while (!done) {
static int gave_soft_limit_message = 0;
check_ini_hal_items(emcStatus->motion.traj.joints);
// read command
if (0 != emcCommandBuffer->read()) {
// got a new command, so clear out errors
taskPlanError = 0;
taskExecuteError = 0;
}
// run control cycle
if (0 != emcTaskPlan()) {
taskPlanError = 1;
}
if (0 != emcTaskExecute()) {
taskExecuteError = 1;
}
// update subordinate status
emcIoUpdate(&emcStatus->io);
emcMotionUpdate(&emcStatus->motion);
// synchronize subordinate states
if (emcStatus->io.aux.estop) {
if (emcStatus->motion.traj.enabled) {
emcTrajDisable();
emcTaskAbort();
emcIoAbort(EMC_ABORT_AUX_ESTOP);
for (int s = 0; s < emcStatus->motion.traj.spindles; s++) emcSpindleAbort(s);
emcJointUnhome(-2); // only those joints which are volatile_home
mdi_execute_abort();
emcAbortCleanup(EMC_ABORT_AUX_ESTOP);
emcTaskPlanSynch();
}
if (emcStatus->io.coolant.mist) {
emcCoolantMistOff();
}
if (emcStatus->io.coolant.flood) {
emcCoolantFloodOff();
}
if (emcStatus->io.lube.on) {
emcLubeOff();
}
for (int n = 0; n < emcStatus->motion.traj.spindles; n++){
if (emcStatus->motion.spindle[n].enabled) {
emcSpindleOff(n);
}
}
}
// toolchanger indicated fault code > 0
if ((emcStatus->io.status == RCS_ERROR) &&
emcStatus->io.fault) {
static int reported = -1;
if (emcStatus->io.reason > 0) {
if (reported ^ emcStatus->io.fault) {
rcs_print("M6: toolchanger soft fault=%d, reason=%d\n",
emcStatus->io.fault, emcStatus->io.reason);
reported = emcStatus->io.fault;
}
emcStatus->io.status = RCS_DONE; // let program continue
} else {
rcs_print("M6: toolchanger hard fault, reason=%d\n",
emcStatus->io.reason);
// abort since io.status is RCS_ERROR
}
}
if (!emcStatus->motion.on_soft_limit) {gave_soft_limit_message = 0;}
// check for subordinate errors, and halt task if so
if ( emcStatus->motion.status == RCS_ERROR
&& emcStatus->motion.on_soft_limit) {
if (!gave_soft_limit_message) {
emcOperatorError(0, "On Soft Limit");
// if gui does not provide a means to switch to joint mode
// the machine may be stuck (a misconfiguration)
if (emcmotConfig.kinType == KINEMATICS_IDENTITY) {
emcOperatorError(0,"Identity kinematics are MISCONFIGURED");
}
gave_soft_limit_message = 1;
}
} else if (emcStatus->motion.status == RCS_ERROR ||
((emcStatus->io.status == RCS_ERROR) &&
(emcStatus->io.reason <= 0))) {
/*! \todo FIXME-- duplicate code for abort,
also in emcTaskExecute()
and in emcTaskIssueCommand() */
if (emcStatus->io.status == RCS_ERROR) {
// this is an aborted M6.
if (emc_debug & EMC_DEBUG_RCS ) {
rcs_print("io.status=RCS_ERROR, fault=%d reason=%d\n",
emcStatus->io.fault, emcStatus->io.reason);
}
if (emcStatus->io.reason < 0) {
emcOperatorError(0, io_error, emcStatus->io.reason);
}
}
// motion already should have reported this condition (and set RCS_ERROR?)
// an M19 orient failed to complete within timeout
// if ((emcStatus->motion.status == RCS_ERROR) &&
// (emcStatus->motion.spindle.orient_state == EMCMOT_ORIENT_FAULTED) &&
// (emcStatus->motion.spindle.orient_fault != 0)) {
// emcOperatorError(0, "wait for orient complete timed out");
// }
// abort everything
emcTaskAbort();
emcIoAbort(EMC_ABORT_MOTION_OR_IO_RCS_ERROR);
for (int s = 0; s < emcStatus->motion.traj.spindles; s++) emcSpindleAbort(s);;
mdi_execute_abort();
// without emcTaskPlanClose(), a new run command resumes at
// aborted line-- feature that may be considered later
{
int was_open = taskplanopen;
emcTaskPlanClose();
emcTaskPlanReset(); // Flush any unflushed segments
if (emc_debug & EMC_DEBUG_INTERP && was_open) {
rcs_print("emcTaskPlanClose() called at %s:%d\n",
__FILE__, __LINE__);
}
}
// clear out the pending command
emcTaskCommand = 0;
interp_list.clear();
emcStatus->task.currentLine = 0;
emcAbortCleanup(EMC_ABORT_MOTION_OR_IO_RCS_ERROR);
// clear out the interpreter state
emcStatus->task.interpState = EMC_TASK_INTERP_IDLE;
emcStatus->task.execState = EMC_TASK_EXEC_DONE;
stepping = 0;
steppingWait = 0;
// now queue up command to resynch interpreter
emcTaskQueueCommand(&taskPlanSynchCmd);
}
// update task-specific status
emcTaskUpdate(&emcStatus->task);
// handle RCS_STAT_MSG base class members explicitly, since this
// is not an NML_MODULE and they won't be set automatically
// do task
emcStatus->task.command_type = emcCommand->type;
emcStatus->task.echo_serial_number = emcCommand->serial_number;
// do top level
emcStatus->command_type = emcCommand->type;
emcStatus->echo_serial_number = emcCommand->serial_number;
if (taskPlanError || taskExecuteError ||
emcStatus->task.execState == EMC_TASK_EXEC_ERROR ||
emcStatus->motion.status == RCS_ERROR ||
emcStatus->io.status == RCS_ERROR) {
emcStatus->status = RCS_ERROR;
emcStatus->task.status = RCS_ERROR;
} else if (!taskPlanError && !taskExecuteError &&
emcStatus->task.execState == EMC_TASK_EXEC_DONE &&
emcStatus->motion.status == RCS_DONE &&
emcStatus->io.status == RCS_DONE &&
mdi_execute_queue.len() == 0 &&
interp_list.len() == 0 &&
emcTaskCommand == 0 &&
emcStatus->task.interpState == EMC_TASK_INTERP_IDLE) {
emcStatus->status = RCS_DONE;
emcStatus->task.status = RCS_DONE;
} else {
emcStatus->status = RCS_EXEC;
emcStatus->task.status = RCS_EXEC;
}
// write it
// since emcStatus was passed to the WM init functions, it
// will be updated in the _update() functions above. There's
// no need to call the individual functions on all WM items.
emcStatusBuffer->write(emcStatus);
// wait on timer cycle, if specified, or calculate actual
// interval if ini file says to run full out via
// [TASK] CYCLE_TIME <= 0.0d
// emcTaskEager = 0;
endTime = etime();
deltaTime = endTime - startTime;
if (deltaTime < minTime)
minTime = deltaTime;
else if (deltaTime > maxTime)
maxTime = deltaTime;
startTime = endTime;
if (deltaTime > (latency_excursion_factor * emc_task_cycle_time)) {
if (num_latency_warnings < 10) {
rcs_print("task: main loop took %.6f seconds\n", deltaTime);
}
num_latency_warnings ++;
}
if ((emcTaskNoDelay) || (emcTaskEager)) {
emcTaskEager = 0;
} else {
timer->wait();
}
}
// end of while (! done)
rcs_print(
"task: %u cycles, min=%.6f, max=%.6f, avg=%.6f, %u latency excursions (> %dx expected cycle time of %.6fs)\n",
emcStatus->task.heartbeat,
minTime,
maxTime,
(emcStatus->task.heartbeat != 0) ? (endTime - first_start_time) / emcStatus->task.heartbeat : -1.0,
num_latency_warnings,
latency_excursion_factor,
emc_task_cycle_time
);
// clean up everything
emctask_shutdown();
// and leave
exit(0);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment