diff --git a/src/emc/task/emctaskmain.cc b/src/emc/task/emctaskmain.cc index 246d200c23d..56c03b2f8d6 100644 --- a/src/emc/task/emctaskmain.cc +++ b/src/emc/task/emctaskmain.cc @@ -2593,6 +2593,9 @@ static int emcTaskExecute(void) // clear out pending command emcTaskCommand = 0; interp_list.clear(); + // the interpreter read ahead of the move that failed; bring back the + // modes of the last executed move, as an operator abort does + emcTaskStateRestore(); emcAbortCleanup(EMC_ABORT_TASK_EXEC_ERROR); emcStatus->task.currentLine = 0; @@ -3524,6 +3527,8 @@ int main(int argc, char *argv[]) interp_list.clear(); emcStatus->task.currentLine = 0; + // as for an operator abort, undo the modes read ahead + emcTaskStateRestore(); emcAbortCleanup(EMC_ABORT_MOTION_OR_IO_RCS_ERROR); // clear out the interpreter state diff --git a/tests/abort/exec-error-modes/.gitignore b/tests/abort/exec-error-modes/.gitignore new file mode 100644 index 00000000000..b4bf49eb08f --- /dev/null +++ b/tests/abort/exec-error-modes/.gitignore @@ -0,0 +1 @@ +sim.var* diff --git a/tests/abort/exec-error-modes/README b/tests/abort/exec-error-modes/README new file mode 100644 index 00000000000..dd8d27fc26e --- /dev/null +++ b/tests/abort/exec-error-modes/README @@ -0,0 +1,6 @@ +Issue #4715: a move that motion rejects (here a soft limit) aborts the +program with an error, but the interpreter had already read ahead past it, +here to a G56 G19 and the M2 that resets to G54 G17. The abort left those +modes active although the machine never reached them. This sets G55 G18 in +MDI, runs test.ngc and checks that G55 G18 are active after the error, as +after an operator abort. diff --git a/tests/abort/exec-error-modes/checkresult b/tests/abort/exec-error-modes/checkresult new file mode 100755 index 00000000000..24dc9aa53e3 --- /dev/null +++ b/tests/abort/exec-error-modes/checkresult @@ -0,0 +1,2 @@ +#!/bin/sh +exit 0 # test failure is indicated by test.sh exit value diff --git a/tests/abort/exec-error-modes/core_sim.hal b/tests/abort/exec-error-modes/core_sim.hal new file mode 100644 index 00000000000..f33a3ccf7f4 --- /dev/null +++ b/tests/abort/exec-error-modes/core_sim.hal @@ -0,0 +1,12 @@ +loadrt [KINS]KINEMATICS +loadrt [EMCMOT]EMCMOT base_period_nsec=[EMCMOT]BASE_PERIOD servo_period_nsec=[EMCMOT]SERVO_PERIOD num_joints=[KINS]JOINTS +addf motion-command-handler servo-thread +addf motion-controller servo-thread + +net Xpos joint.0.motor-pos-cmd => joint.0.motor-pos-fb +net Ypos joint.1.motor-pos-cmd => joint.1.motor-pos-fb +net Zpos joint.2.motor-pos-cmd => joint.2.motor-pos-fb + +net estop-loop iocontrol.0.user-enable-out iocontrol.0.emc-enable-in +net tool-prepare-loop iocontrol.0.tool-prepare iocontrol.0.tool-prepared +net tool-change-loop iocontrol.0.tool-change iocontrol.0.tool-changed diff --git a/tests/abort/exec-error-modes/simpockets.tbl b/tests/abort/exec-error-modes/simpockets.tbl new file mode 100644 index 00000000000..1371faeee58 --- /dev/null +++ b/tests/abort/exec-error-modes/simpockets.tbl @@ -0,0 +1 @@ +T1 P1 ; diff --git a/tests/abort/exec-error-modes/test-ui.py b/tests/abort/exec-error-modes/test-ui.py new file mode 100755 index 00000000000..a91409ef702 --- /dev/null +++ b/tests/abort/exec-error-modes/test-ui.py @@ -0,0 +1,80 @@ +#!/usr/bin/env python3 + +import linuxcnc +import linuxcnc_util +import time +import sys + + +l = linuxcnc_util.LinuxCNC() +c, s = l.command, l.status +l.wait_for_linuxcnc_startup() +e = linuxcnc.error_channel() + +c.state(linuxcnc.STATE_ESTOP_RESET) +c.state(linuxcnc.STATE_ON) +c.mode(linuxcnc.MODE_MDI) +c.wait_complete() +c.mdi('G55 G18') +c.wait_complete() +l.wait_for_interp_state(linuxcnc.INTERP_IDLE) + + +def modes(): + s.poll() + return s.gcodes[3], s.gcodes[8] # plane, coordinate system + + +if modes() != (180, 550): + print('FAIL: MDI did not set G55 G18: %s' % (modes(),)) + sys.exit(1) + +c.mode(linuxcnc.MODE_AUTO) +c.wait_complete() +c.program_open('test.ngc') +c.wait_complete() +c.auto(linuxcnc.AUTO_RUN, 0) + +# Wait for the program to start (no fixed delay: a loaded machine may take a while). +start = time.time() +while time.time() - start < 10: + s.poll() + if s.interp_state != linuxcnc.INTERP_IDLE: + break + time.sleep(0.005) +else: + print('FAIL: the program did not start within 10 s') + sys.exit(1) + +errors = [] +start = time.time() +while time.time() - start < 30: + s.poll() + msg = e.poll() + if msg: + errors.append(msg[1]) + if s.interp_state == linuxcnc.INTERP_IDLE: + break + time.sleep(0.005) +else: + print('FAIL: the program did not stop within 30 s') + sys.exit(1) + +time.sleep(0.5) +while True: + msg = e.poll() + if not msg: + break + errors.append(msg[1]) +for m in errors: + print('error channel: %s' % (m,)) + +if not any('would exceed' in m for m in errors): + print('FAIL: motion did not reject the move beyond the limit') + sys.exit(1) + +print('after the error: plane %d, coordinate system %d' % modes()) +if modes() != (180, 550): + print('FAIL: the error left the modes the interpreter read ahead') + sys.exit(1) +sys.exit(0) diff --git a/tests/abort/exec-error-modes/test.ini b/tests/abort/exec-error-modes/test.ini new file mode 100644 index 00000000000..d6d15ef0394 --- /dev/null +++ b/tests/abort/exec-error-modes/test.ini @@ -0,0 +1,115 @@ +# Simulated machine for tests/abort/exec-error-modes (issue #4715), based on tests/program-units. + +[EMC] +# The version string for this INI file. +VERSION = 1.1 + +DEBUG = 0 +RCS_DEBUG = 0x05400f01 + +[DISPLAY] +DISPLAY = ./test-ui.py + +[FILTER] +#No Content + +[RS274NGC] +PARAMETER_FILE = sim.var + +[EMCMOT] +EMCMOT = motmod +COMM_TIMEOUT = 4.0 +BASE_PERIOD = 0 +SERVO_PERIOD = 1000000 + +[TASK] +TASK = milltask +CYCLE_TIME = 0.001 + +[HAL] +HALFILE = core_sim.hal + +[TRAJ] + +NO_FORCE_HOMING=1 +AXES = 3 +COORDINATES = X Y Z +HOME = 0 0 0 +LINEAR_UNITS = inch +ANGULAR_UNITS = degree +DEFAULT_LINEAR_VELOCITY = 1.2 +MAX_LINEAR_ACCELERATION = 123.45 +MAX_LINEAR_VELOCITY = 45.67 + +[EMCIO] +EMCIO = io +TOOL_TABLE = simpockets.tbl +TOOL_CHANGE_QUILL_UP = 1 +RANDOM_TOOLCHANGER = 0 + + + +[KINS] +KINEMATICS = trivkins +#This is a best-guess at the number of joints, it should be checked +JOINTS = 3 + +[AXIS_X] +MIN_LIMIT = -40.0 +MAX_LIMIT = 40.0 +MAX_VELOCITY = 4 +MAX_ACCELERATION = 1000.0 + +[JOINT_0] + +TYPE = LINEAR +HOME = 0.000 +MAX_VELOCITY = 4 +MAX_ACCELERATION = 1000.0 +BACKLASH = 0.000 +INPUT_SCALE = 4000 +OUTPUT_SCALE = 1.000 +MIN_LIMIT = -40.0 +MAX_LIMIT = 40.0 +FERROR = 0.050 +MIN_FERROR = 0.010 + +[AXIS_Y] +MIN_LIMIT = -40.0 +MAX_LIMIT = 40.0 +MAX_VELOCITY = 4 +MAX_ACCELERATION = 1000.0 + +[JOINT_1] + +TYPE = LINEAR +HOME = 0.000 +MAX_VELOCITY = 4 +MAX_ACCELERATION = 1000.0 +BACKLASH = 0.000 +INPUT_SCALE = 4000 +OUTPUT_SCALE = 1.000 +MIN_LIMIT = -40.0 +MAX_LIMIT = 40.0 +FERROR = 0.050 +MIN_FERROR = 0.010 + +[AXIS_Z] +MIN_LIMIT = -40.0 +MAX_LIMIT = 40.0 +MAX_VELOCITY = 4 +MAX_ACCELERATION = 1000.0 + +[JOINT_2] + +TYPE = LINEAR +HOME = 0.0 +MAX_VELOCITY = 4 +MAX_ACCELERATION = 1000.0 +BACKLASH = 0.000 +INPUT_SCALE = 4000 +OUTPUT_SCALE = 1.000 +MIN_LIMIT = -40.0 +MAX_LIMIT = 40.0 +FERROR = 0.050 +MIN_FERROR = 0.010 diff --git a/tests/abort/exec-error-modes/test.ngc b/tests/abort/exec-error-modes/test.ngc new file mode 100644 index 00000000000..f4b79f50e69 --- /dev/null +++ b/tests/abort/exec-error-modes/test.ngc @@ -0,0 +1,5 @@ +(the moves start on line 2: a state tag from line 1 is never restored) +G1 X1 F20 (about 3 s: the interpreter reads past it to the G56 G19 and the M2) +G56 G19 +G0 X100 (beyond MAX_LIMIT: motion rejects it while the move above runs) +M2 diff --git a/tests/abort/exec-error-modes/test.sh b/tests/abort/exec-error-modes/test.sh new file mode 100755 index 00000000000..6edf34d77ca --- /dev/null +++ b/tests/abort/exec-error-modes/test.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +rm -f sim.var +linuxcnc -r test.ini