Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions src/emc/task/emctaskmain.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions tests/abort/exec-error-modes/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
sim.var*
6 changes: 6 additions & 0 deletions tests/abort/exec-error-modes/README
Original file line number Diff line number Diff line change
@@ -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.
2 changes: 2 additions & 0 deletions tests/abort/exec-error-modes/checkresult
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#!/bin/sh
exit 0 # test failure is indicated by test.sh exit value
12 changes: 12 additions & 0 deletions tests/abort/exec-error-modes/core_sim.hal
Original file line number Diff line number Diff line change
@@ -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
1 change: 1 addition & 0 deletions tests/abort/exec-error-modes/simpockets.tbl
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
T1 P1 ;
80 changes: 80 additions & 0 deletions tests/abort/exec-error-modes/test-ui.py
Original file line number Diff line number Diff line change
@@ -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)
115 changes: 115 additions & 0 deletions tests/abort/exec-error-modes/test.ini
Original file line number Diff line number Diff line change
@@ -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
5 changes: 5 additions & 0 deletions tests/abort/exec-error-modes/test.ngc
Original file line number Diff line number Diff line change
@@ -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
4 changes: 4 additions & 0 deletions tests/abort/exec-error-modes/test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/bin/bash

rm -f sim.var
linuxcnc -r test.ini