From 606313a3d2ff1ad877d380ac4dc35f5783ae24f8 Mon Sep 17 00:00:00 2001 From: Rene Hopf Date: Sun, 20 Sep 2026 17:31:18 +0200 Subject: [PATCH 01/21] add halui tests --- tests/halui/.gitignore | 5 + tests/halui/_lib/coverage.py | 60 +++ tests/halui/_lib/halui_test.py | 347 ++++++++++++++++ tests/halui/_lib/launch.sh | 8 + tests/halui/_lib/tool.tbl | 3 + tests/halui/axes/checkresult | 2 + tests/halui/axes/halui.ini | 100 +++++ tests/halui/axes/test-ui.py | 324 +++++++++++++++ tests/halui/axes/test.sh | 2 + tests/halui/config-9axis/checkresult | 2 + tests/halui/config-9axis/halui.ini | 194 +++++++++ tests/halui/config-9axis/nine.hal | 19 + tests/halui/config-9axis/test-ui.py | 130 ++++++ tests/halui/config-9axis/test.sh | 2 + tests/halui/config-minimal/checkresult | 2 + tests/halui/config-minimal/halui.ini | 74 ++++ tests/halui/config-minimal/minimal.hal | 12 + tests/halui/config-minimal/test-ui.py | 172 ++++++++ tests/halui/config-minimal/test.sh | 2 + tests/halui/joints/checkresult | 2 + tests/halui/joints/halui.ini | 100 +++++ tests/halui/joints/test-ui.py | 442 +++++++++++++++++++++ tests/halui/joints/test.sh | 2 + tests/halui/machine-state/checkresult | 2 + tests/halui/machine-state/halui.ini | 100 +++++ tests/halui/machine-state/test-ui.py | 188 +++++++++ tests/halui/machine-state/test.sh | 2 + tests/halui/mdi-commands/checkresult | 2 + tests/halui/mdi-commands/halui.ini | 102 +++++ tests/halui/mdi-commands/long.ngc | 5 + tests/halui/mdi-commands/test-ui.py | 182 +++++++++ tests/halui/mdi-commands/test.sh | 2 + tests/halui/overrides/checkresult | 2 + tests/halui/overrides/halui.ini | 100 +++++ tests/halui/overrides/test-ui.py | 230 +++++++++++ tests/halui/overrides/test.sh | 2 + tests/halui/program/block-delete.ngc | 4 + tests/halui/program/checkresult | 2 + tests/halui/program/halui.ini | 100 +++++ tests/halui/program/long.ngc | 5 + tests/halui/program/optional-stop.ngc | 5 + tests/halui/program/step.ngc | 5 + tests/halui/program/test-ui.py | 295 ++++++++++++++ tests/halui/program/test.sh | 2 + tests/halui/spindle-coolant/checkresult | 2 + tests/halui/spindle-coolant/halui.ini | 100 +++++ tests/halui/spindle-coolant/test-ui.py | 171 ++++++++ tests/halui/spindle-coolant/test.sh | 2 + tests/halui/startup-halfile/checkresult | 2 + tests/halui/startup-halfile/halui-nets.hal | 7 + tests/halui/startup-halfile/halui.ini | 102 +++++ tests/halui/startup-halfile/test-ui.py | 67 ++++ tests/halui/startup-halfile/test.sh | 2 + tests/halui/tool/checkresult | 2 + tests/halui/tool/halui.ini | 100 +++++ tests/halui/tool/test-ui.py | 112 ++++++ tests/halui/tool/test.sh | 2 + 57 files changed, 4014 insertions(+) create mode 100644 tests/halui/_lib/coverage.py create mode 100644 tests/halui/_lib/halui_test.py create mode 100755 tests/halui/_lib/launch.sh create mode 100644 tests/halui/_lib/tool.tbl create mode 100755 tests/halui/axes/checkresult create mode 100644 tests/halui/axes/halui.ini create mode 100755 tests/halui/axes/test-ui.py create mode 100755 tests/halui/axes/test.sh create mode 100755 tests/halui/config-9axis/checkresult create mode 100644 tests/halui/config-9axis/halui.ini create mode 100644 tests/halui/config-9axis/nine.hal create mode 100755 tests/halui/config-9axis/test-ui.py create mode 100755 tests/halui/config-9axis/test.sh create mode 100755 tests/halui/config-minimal/checkresult create mode 100644 tests/halui/config-minimal/halui.ini create mode 100644 tests/halui/config-minimal/minimal.hal create mode 100755 tests/halui/config-minimal/test-ui.py create mode 100755 tests/halui/config-minimal/test.sh create mode 100755 tests/halui/joints/checkresult create mode 100644 tests/halui/joints/halui.ini create mode 100755 tests/halui/joints/test-ui.py create mode 100755 tests/halui/joints/test.sh create mode 100755 tests/halui/machine-state/checkresult create mode 100644 tests/halui/machine-state/halui.ini create mode 100755 tests/halui/machine-state/test-ui.py create mode 100755 tests/halui/machine-state/test.sh create mode 100755 tests/halui/mdi-commands/checkresult create mode 100644 tests/halui/mdi-commands/halui.ini create mode 100644 tests/halui/mdi-commands/long.ngc create mode 100755 tests/halui/mdi-commands/test-ui.py create mode 100755 tests/halui/mdi-commands/test.sh create mode 100755 tests/halui/overrides/checkresult create mode 100644 tests/halui/overrides/halui.ini create mode 100755 tests/halui/overrides/test-ui.py create mode 100755 tests/halui/overrides/test.sh create mode 100644 tests/halui/program/block-delete.ngc create mode 100755 tests/halui/program/checkresult create mode 100644 tests/halui/program/halui.ini create mode 100644 tests/halui/program/long.ngc create mode 100644 tests/halui/program/optional-stop.ngc create mode 100644 tests/halui/program/step.ngc create mode 100755 tests/halui/program/test-ui.py create mode 100755 tests/halui/program/test.sh create mode 100755 tests/halui/spindle-coolant/checkresult create mode 100644 tests/halui/spindle-coolant/halui.ini create mode 100755 tests/halui/spindle-coolant/test-ui.py create mode 100755 tests/halui/spindle-coolant/test.sh create mode 100755 tests/halui/startup-halfile/checkresult create mode 100644 tests/halui/startup-halfile/halui-nets.hal create mode 100644 tests/halui/startup-halfile/halui.ini create mode 100755 tests/halui/startup-halfile/test-ui.py create mode 100755 tests/halui/startup-halfile/test.sh create mode 100755 tests/halui/tool/checkresult create mode 100644 tests/halui/tool/halui.ini create mode 100755 tests/halui/tool/test-ui.py create mode 100755 tests/halui/tool/test.sh diff --git a/tests/halui/.gitignore b/tests/halui/.gitignore index b23febc81d7..31d40592f97 100644 --- a/tests/halui/.gitignore +++ b/tests/halui/.gitignore @@ -1,2 +1,7 @@ sim.var.bak sim.var +# the halui pin tests copy _lib/tool.tbl in fresh on every run +*/tool.tbl +!_lib/tool.tbl +# per-run list of the halui pins a test touched +*/touched-pins.txt diff --git a/tests/halui/_lib/coverage.py b/tests/halui/_lib/coverage.py new file mode 100644 index 00000000000..8cf13f34b6a --- /dev/null +++ b/tests/halui/_lib/coverage.py @@ -0,0 +1,60 @@ +#!/usr/bin/env python3 +"""Report which halui pins the halui test suite exercises. + +Each test run leaves touched-pins.txt in its directory. This merges them and +matches them against every pin name pattern in halui.cc, so the report stays +honest when halui gains or loses pins. + + python3 tests/halui/_lib/coverage.py +""" + +import glob +import os +import re +import sys + +HERE = os.path.dirname(os.path.abspath(__file__)) +SUITE = os.path.dirname(HERE) +HALUI_CC = os.path.join(SUITE, '..', '..', 'src', 'emc', 'usr_intf', 'halui.cc') + +SPEC = re.compile(r'%[-+ #0]*\d*(?:\.\d+)?[diouxXcs]') + + +def pattern_regex(pattern): + parts = SPEC.split(pattern) + out = re.escape(parts[0]) + for rest in parts[1:]: + out += r'[A-Za-z0-9_]+' + re.escape(rest) + return re.compile('^' + out + '$') + + +def main(): + with open(HALUI_CC) as f: + patterns = sorted(set(p[len('halui.'):] for p in + re.findall(r'"(halui\.[A-Za-z0-9_.%\-]+)"', f.read()))) + + touched, runs = set(), [] + for path in sorted(glob.glob(os.path.join(SUITE, '*', 'touched-pins.txt'))): + runs.append(os.path.basename(os.path.dirname(path))) + with open(path) as f: + touched.update(line.strip() for line in f if line.strip()) + + if not runs: + print('no touched-pins.txt found; run the halui tests first') + return 1 + + covered = [p for p in patterns if any(pattern_regex(p).match(t) for t in touched)] + missing = [p for p in patterns if p not in covered] + + print('halui pin coverage from %d test runs: %s' % (len(runs), ', '.join(runs))) + print('%d of %d pin patterns exercised (%.0f%%)' + % (len(covered), len(patterns), 100.0 * len(covered) / len(patterns))) + if missing: + print('not exercised:') + for p in missing: + print(' halui.' + p) + return 0 + + +if __name__ == '__main__': + sys.exit(main()) diff --git a/tests/halui/_lib/halui_test.py b/tests/halui/_lib/halui_test.py new file mode 100644 index 00000000000..6911f786a02 --- /dev/null +++ b/tests/halui/_lib/halui_test.py @@ -0,0 +1,347 @@ +"""Shared harness for the halui pin tests. + +Each test directory runs linuxcnc with its test-ui.py as the [DISPLAY] +program, so the harness starts once halui and task are both up. It: + + - Finds every pin halui exported and creates a mirror pin with the opposite + direction on its own HAL component, wired straight to it. Tests drive + halui's inputs and read its outputs by suffix: + h.set('machine.on', 1) + h.get('machine.is-on') + + - Talks to task through the stock linuxcnc python module. That is used only + for test setup (opening a program, homing before a jog test, ...) and as + ground truth for what task actually did -- never as the thing under test. + + - Records every check. A failed check is reported and the run carries on, + so one run shows everything that is broken. The process exits non-zero at + the end if anything failed. + +The tests assert what halui does today. Where today's behaviour is a bug, the +check goes through known_bug() with an explanation: the suite is a baseline +that flags any change in behaviour, and fixing one of those bugs has to +update its test deliberately. + +The tests only look at pins and task state, so the same suite applies +whether halui runs as its own process or inside task. +""" + +import math +import os +import sys +import time +import traceback + +import hal +import linuxcnc + +# halui polls its pins and task's status every 20 ms. Holding an input for a +# few of those guarantees halui samples both edges. +HALUI_PERIOD = 0.02 +HOLD = 0.15 +TIMEOUT = 5.0 + +COMP = 'halui-test' + + +class Halui: + + def __init__(self): + self.t0 = time.time() + self.checks = 0 + self.failures = [] + self.known_bugs = [] + self.touched = set() + + # Every pin halui exported, by suffix: {'machine.on': (type, dir)}, + # and the value each input had before we wired it (halui's default). + self.pins = {} + self.defaults = {} + for p in hal.get_info_pins(): + if p['NAME'].startswith('halui.'): + sfx = p['NAME'][len('halui.'):] + self.pins[sfx] = (p['TYPE'], p['DIRECTION']) + if p['DIRECTION'] == hal.HAL_IN: + self.defaults[sfx] = p['VALUE'] + if not self.pins: + raise RuntimeError('no halui pins found -- is halui running?') + + self.comp = hal.component(COMP) + for sfx, (typ, d) in sorted(self.pins.items()): + mirror = hal.HAL_OUT if d == hal.HAL_IN else hal.HAL_IN + self.comp.newpin(sfx, typ, mirror) + # Wiring our output to halui's input makes the signal carry our + # value, so start from halui's own default (scales, deadbands, + # count-enable...) rather than silently replacing it with 0. + if d == hal.HAL_IN: + self.comp[sfx] = self.defaults[sfx] + self.comp.ready() + + # Pins the config already wired elsewhere cannot be driven from here. + self.external = set() + for sfx, (typ, d) in sorted(self.pins.items()): + # hal.connect() does not raise when the link fails: it returns + # True (hal_link() != 0). A failed link here means the config + # already wired this halui pin. + sig = 'ht.' + sfx + hal.new_sig(sig, typ) + if hal.connect('halui.' + sfx, sig): + self.external.add(sfx) + continue + if hal.connect(COMP + '.' + sfx, sig): + raise RuntimeError('could not wire %s.%s' % (COMP, sfx)) + + self.stat = linuxcnc.stat() + self.cmd = linuxcnc.command() + self.errors = linuxcnc.error_channel() + self.poll() + self.log('harness up: %d halui pins, %d wired externally' + % (len(self.pins), len(self.external))) + + # -- reporting --------------------------------------------------------- + + def log(self, msg): + print('%7.3f: %s' % (time.time() - self.t0, msg), flush=True) + + def section(self, name): + self.log('') + self.log('==== %s ====' % name) + + def check(self, name, ok, detail=''): + self.checks += 1 + self.log('%s %s%s' % ('PASS' if ok else 'FAIL', name, + (' -- ' + detail) if detail else '')) + if not ok: + self.failures.append(name) + return ok + + def known_bug(self, name, ok, explanation): + """Assert today's buggy behaviour, and say why it is a bug.""" + self.known_bugs.append(name) + return self.check('KNOWN-BUG ' + name, ok, explanation) + + def finish(self): + here = os.path.dirname(os.path.abspath(sys.argv[0])) + with open(os.path.join(here, 'touched-pins.txt'), 'w') as f: + for p in sorted(self.touched): + f.write(p + '\n') + self.log('') + self.log('%d checks, %d failed, %d known bugs, %d/%d halui pins exercised' + % (self.checks, len(self.failures), len(self.known_bugs), + len(self.touched & set(self.pins)), len(self.pins))) + for f in self.failures: + self.log(' FAILED: ' + f) + sys.exit(1 if self.failures else 0) + + # -- halui pins -------------------------------------------------------- + + def has(self, sfx): + return sfx in self.pins + + def _pin(self, sfx, want_input): + if sfx not in self.pins: + raise KeyError('halui has no pin %r' % sfx) + is_input = self.pins[sfx][1] == hal.HAL_IN + if is_input != want_input: + raise KeyError('halui.%s is an %s pin' % (sfx, 'input' if is_input else 'output')) + self.touched.add(sfx) + + def set(self, sfx, value): + self._pin(sfx, want_input=True) + if sfx in self.external: + raise KeyError('halui.%s is wired by the config; cannot drive it' % sfx) + self.comp[sfx] = value + + def get(self, sfx): + self._pin(sfx, want_input=False) + return self.comp[sfx] + + def default(self, sfx): + """halui's value for an input pin before the harness wired it.""" + self._pin(sfx, want_input=True) + return self.defaults[sfx] + + def pulse(self, sfx, hold=HOLD): + """Rising edge, held long enough for halui to see it, then released.""" + self.set(sfx, 1) + time.sleep(hold) + self.set(sfx, 0) + time.sleep(hold) + + def settle(self, t=HOLD): + time.sleep(t) + + # -- waiting ----------------------------------------------------------- + + def poll(self): + self.stat.poll() + return self.stat + + def wait_for(self, fn, timeout=TIMEOUT): + end = time.time() + timeout + while True: + self.poll() + try: + if fn(): + return True + except Exception: + pass + if time.time() > end: + return False + time.sleep(HALUI_PERIOD / 2) + + def expect(self, name, fn, timeout=TIMEOUT, detail=None): + ok = self.wait_for(fn, timeout) + return self.check(name, ok, detail() if callable(detail) else (detail or '')) + + def stays(self, fn, duration=0.5): + """True if fn holds for the whole duration (records nothing).""" + end = time.time() + duration + while time.time() < end: + self.poll() + if not fn(): + return False + time.sleep(HALUI_PERIOD / 2) + return True + + def expect_steady(self, name, fn, duration=0.5, detail=None): + """fn must stay true for the whole duration.""" + ok = self.stays(fn, duration) + return self.check(name, ok, detail() if callable(detail) else (detail or '')) + + def expect_pin(self, name, sfx, want, timeout=TIMEOUT, tol=1e-6): + is_float = self.pins[sfx][0] == hal.HAL_FLOAT + + def match(): + v = self.get(sfx) + if is_float: + return abs(v - want) <= tol + return v == want + return self.expect(name, match, timeout, + detail=lambda: 'halui.%s = %r, want %r' % (sfx, self.get(sfx), want)) + + def drain_errors(self): + out = [] + while True: + e = self.errors.poll() + if not e: + return out + out.append(e[1]) + + def reset_between_sections(self): + for sfx in sorted(self.touched): + if self.pins[sfx][1] == hal.HAL_IN and sfx not in self.external: + self.comp[sfx] = self.defaults[sfx] + time.sleep(0.3) + self.nml_abort() + + # -- task setup, via NML (not under test) ------------------------------ + + def nml_abort(self): + self.cmd.abort() + self.cmd.wait_complete() + self.wait_for(lambda: self.stat.interp_state == linuxcnc.INTERP_IDLE) + + def nml_state(self, state): + # task has no distinct OFF state: a request for OFF reads back as + # ESTOP_RESET + want = linuxcnc.STATE_ESTOP_RESET if state == linuxcnc.STATE_OFF else state + self.cmd.state(state) + self.cmd.wait_complete() + return self.wait_for(lambda: self.stat.task_state == want) + + def machine_on(self): + if self.poll().task_state == linuxcnc.STATE_ON: + return + if self.stat.task_state == linuxcnc.STATE_ESTOP: + self.nml_state(linuxcnc.STATE_ESTOP_RESET) + if not self.nml_state(linuxcnc.STATE_ON): + raise RuntimeError('setup: could not turn the machine on') + + def machine_estop(self): + self.nml_state(linuxcnc.STATE_ESTOP) + + def nml_mode(self, mode): + self.cmd.mode(mode) + self.cmd.wait_complete() + if not self.wait_for(lambda: self.stat.task_mode == mode): + raise RuntimeError('setup: could not switch to mode %d' % mode) + + def nml_teleop(self, enable): + self.cmd.teleop_enable(enable) + self.cmd.wait_complete() + want = linuxcnc.TRAJ_MODE_TELEOP if enable else linuxcnc.TRAJ_MODE_FREE + if not self.wait_for(lambda: self.stat.motion_mode == want): + raise RuntimeError('setup: could not set teleop=%d' % enable) + + def nml_home_all(self): + # Note: once every joint is homed, task switches an identity-kins + # machine to teleop by itself. + self.nml_mode(linuxcnc.MODE_MANUAL) + self.cmd.home(-1) + self.cmd.wait_complete() + if not self.wait_for(lambda: all(self.stat.homed[:self.stat.joints]), 20): + raise RuntimeError('setup: homing failed') + + def nml_unhome_all(self): + # motion refuses to unhome in teleop ("must be in joint mode or + # disabled to unhome"), which is where homing leaves the machine + self.nml_mode(linuxcnc.MODE_MANUAL) + if self.poll().motion_mode == linuxcnc.TRAJ_MODE_TELEOP: + self.nml_teleop(0) + self.cmd.unhome(-1) + self.cmd.wait_complete() + if not self.wait_for(lambda: not any(self.stat.homed[:self.stat.joints])): + raise RuntimeError('setup: unhoming failed') + + def wait_idle(self, timeout=20): + return self.wait_for(lambda: self.stat.interp_state == linuxcnc.INTERP_IDLE + and self.stat.exec_state == linuxcnc.EXEC_DONE, timeout) + + def nml_mdi(self, code, timeout=20): + self.nml_mode(linuxcnc.MODE_MDI) + self.cmd.mdi(code) + self.cmd.wait_complete() + if not self.wait_idle(timeout): + raise RuntimeError('setup: MDI %r did not finish' % code) + + def joint_pos(self, j): + return self.stat.joint_actual_position[j] + + def axis_pos(self, a): + return self.stat.actual_position['xyzabcuvw'.index(a)] + + def wait_joint_still(self, j, timeout=10): + last = [None] + def still(): + p = self.joint_pos(j) + done = last[0] is not None and abs(p - last[0]) < 1e-9 and self.stat.inpos + last[0] = p + return done + return self.wait_for(still, timeout) + + +def run(*sections): + """Run each section function against one harness; report at the end. + + Between sections every input a test drove goes back to halui's default and + task is aborted, so a section cannot leave a held jog, a paused program or + a half-finished MDI behind for the next one. + """ + h = Halui() + for fn in sections: + h.section(fn.__name__) + try: + fn(h) + except Exception: + h.log(traceback.format_exc()) + h.check('%s ran to completion' % fn.__name__, False, 'exception, see above') + h.reset_between_sections() + h.finish() + + +def close(a, b, tol=1e-6): + return abs(a - b) <= tol + + +INCH_PER_MM = 1 / 25.4 diff --git a/tests/halui/_lib/launch.sh b/tests/halui/_lib/launch.sh new file mode 100755 index 00000000000..abb5f798f01 --- /dev/null +++ b/tests/halui/_lib/launch.sh @@ -0,0 +1,8 @@ +#!/bin/bash +# Shared launcher for the halui pin tests. Each test directory's test.sh +# execs this from inside that directory. +# +# task rewrites the tool table (G10 L1, tool changes), so every run starts +# from a fresh copy of the shared one; tool.tbl is ignored by git. +cp ../_lib/tool.tbl tool.tbl +exec linuxcnc -r halui.ini diff --git a/tests/halui/_lib/tool.tbl b/tests/halui/_lib/tool.tbl new file mode 100644 index 00000000000..25496163e24 --- /dev/null +++ b/tests/halui/_lib/tool.tbl @@ -0,0 +1,3 @@ +T1 P1 Z0.5 D0.25 ;tool one +T2 P2 Z1.0 D0.5 ;tool two +T3 P3 Z0.0 D0.125 ;tool three diff --git a/tests/halui/axes/checkresult b/tests/halui/axes/checkresult new file mode 100755 index 00000000000..73e90a43dfc --- /dev/null +++ b/tests/halui/axes/checkresult @@ -0,0 +1,2 @@ +#!/bin/sh +exit 0 # test failure is indicated by test.sh exit value diff --git a/tests/halui/axes/halui.ini b/tests/halui/axes/halui.ini new file mode 100644 index 00000000000..4d21b0429ec --- /dev/null +++ b/tests/halui/axes/halui.ini @@ -0,0 +1,100 @@ +# Test machine shared by the halui pin tests: XYZ trivkins, one spindle, +# a tool table, a home sequence (so halui.home-all exists) and two MDI +# commands (so halui.halui-mdi-is-running and halui.mdi-command-NN exist). + +[EMC] +VERSION = 1.1 +DEBUG = 0 + +[DISPLAY] +DISPLAY = ./test-ui.py +MAX_FEED_OVERRIDE = 1.5 +MIN_SPINDLE_OVERRIDE = 0.5 +MAX_SPINDLE_OVERRIDE = 1.2 + +[TASK] +TASK = milltask +CYCLE_TIME = 0.001 + +[RS274NGC] +PARAMETER_FILE = sim.var + +[EMCMOT] +EMCMOT = motmod +COMM_TIMEOUT = 4.0 +BASE_PERIOD = 0 +SERVO_PERIOD = 1000000 + +[EMCIO] +TOOL_TABLE = tool.tbl + +[HAL] +HALFILE = LIB:core_sim.hal + +[HALUI] +MDI_COMMAND = G0 X1 Y0 Z0 +MDI_COMMAND = G0 X0 Y0 Z0 + +[TRAJ] +COORDINATES = X Y Z +LINEAR_UNITS = inch +ANGULAR_UNITS = degree +DEFAULT_LINEAR_VELOCITY = 1.2 +MAX_LINEAR_VELOCITY = 4 +SPINDLES = 1 +NO_FORCE_HOMING = 1 + +[KINS] +KINEMATICS = trivkins +JOINTS = 3 + +[AXIS_X] +MIN_LIMIT = -40.0 +MAX_LIMIT = 40.0 +MAX_VELOCITY = 4 +MAX_ACCELERATION = 1000.0 + +[AXIS_Y] +MIN_LIMIT = -40.0 +MAX_LIMIT = 40.0 +MAX_VELOCITY = 4 +MAX_ACCELERATION = 1000.0 + +[AXIS_Z] +MIN_LIMIT = -4.0 +MAX_LIMIT = 4.0 +MAX_VELOCITY = 4 +MAX_ACCELERATION = 1000.0 + +[JOINT_0] +TYPE = LINEAR +HOME = 0.0 +MAX_VELOCITY = 4 +MAX_ACCELERATION = 1000.0 +MIN_LIMIT = -40.0 +MAX_LIMIT = 40.0 +FERROR = 0.050 +MIN_FERROR = 0.010 +HOME_SEQUENCE = 0 + +[JOINT_1] +TYPE = LINEAR +HOME = 0.0 +MAX_VELOCITY = 4 +MAX_ACCELERATION = 1000.0 +MIN_LIMIT = -40.0 +MAX_LIMIT = 40.0 +FERROR = 0.050 +MIN_FERROR = 0.010 +HOME_SEQUENCE = 0 + +[JOINT_2] +TYPE = LINEAR +HOME = 0.0 +MAX_VELOCITY = 4 +MAX_ACCELERATION = 1000.0 +MIN_LIMIT = -4.0 +MAX_LIMIT = 4.0 +FERROR = 0.050 +MIN_FERROR = 0.010 +HOME_SEQUENCE = 0 diff --git a/tests/halui/axes/test-ui.py b/tests/halui/axes/test-ui.py new file mode 100755 index 00000000000..83217d91b8d --- /dev/null +++ b/tests/halui/axes/test-ui.py @@ -0,0 +1,324 @@ +#!/usr/bin/env python3 +"""halui: axis selection, teleop jogging and axis positions. + +Pins: axis.L.select, axis.L.is-selected, axis.selected, + axis.jog-speed, axis.jog-deadband, + axis.L.plus, axis.L.minus, axis.L.analog, + axis.L.increment, axis.L.increment-plus, axis.L.increment-minus, + axis.selected.plus, axis.selected.minus, axis.selected.increment, + axis.selected.increment-plus, axis.selected.increment-minus, + axis.L.pos-commanded, axis.L.pos-feedback, axis.L.pos-relative + +The machine is XYZ trivkins, so axis x/y/z is joint 0/1/2 one to one and +axis motion is measured through the joint velocities. Axis jog speed is in +units per minute; halui divides it by 60. +""" + +import math +import os +import sys + +sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', '_lib')) +from halui_test import run, close # noqa: E402 + +import linuxcnc as L # noqa: E402 + +LETTERS = 'xyzabcuvw' +CONFIGURED = 'xyz' + + +def idx(a): + return LETTERS.index(a) + + +def av(h, a): + return h.stat.joint[idx(a)]['velocity'] + + +def pos(h, a): + return h.stat.actual_position[idx(a)] + + +def expect_velocity(h, a, v, why): + return h.expect('axis %s moves at %+.2f %s' % (a, v, why), + lambda: close(av(h, a), v, 1e-3), + detail=lambda: 'velocity %+.4f' % av(h, a)) + + +def expect_stopped(h, a, why): + h.expect('axis %s stops %s' % (a, why), lambda: close(av(h, a), 0.0, 1e-9) and h.stat.inpos, + detail=lambda: 'velocity %+.4f' % av(h, a)) + + +def expect_not_moving(h, a, why): + h.expect_steady('axis %s does not move %s' % (a, why), + lambda: close(av(h, a), 0.0, 1e-9), + detail=lambda: 'velocity %+.4f' % av(h, a)) + + +def expect_at(h, a, p, why): + return h.expect('axis %s ends at %+.3f %s' % (a, p, why), + lambda: close(pos(h, a), p, 1e-4) and h.stat.inpos, + timeout=10, detail=lambda: 'position %+.4f' % pos(h, a)) + + +def teleop(h): + h.machine_on() + h.nml_mode(L.MODE_MANUAL) + if not all(h.poll().homed[:3]): + h.nml_home_all() + if h.stat.motion_mode != L.TRAJ_MODE_TELEOP: + h.nml_teleop(1) + + +def to_zero(h): + h.machine_on() + if not all(h.poll().homed[:3]): + h.nml_home_all() + h.nml_mdi('G20 G90 G53 G0 X0 Y0 Z0') + teleop(h) + + +def expect_selected(h, a, why): + h.expect_pin('axis.selected is %d (%s) %s' % (idx(a), a, why), 'axis.selected', idx(a)) + for b in CONFIGURED: + h.expect_pin('axis.%s.is-selected is %s %s' % (b, a == b, why), + 'axis.%s.is-selected' % b, a == b) + + +def pins_and_defaults(h): + # input pins exist for all nine axes; status pins only for configured ones + for a in LETTERS: + for p in ('select', 'plus', 'minus', 'analog', 'increment', + 'increment-plus', 'increment-minus'): + if not h.has('axis.%s.%s' % (a, p)): + h.check('axis.%s.%s exists' % (a, p), False) + for p in ('is-selected', 'pos-commanded', 'pos-feedback', 'pos-relative'): + if h.has('axis.%s.%s' % (a, p)) != (a in CONFIGURED): + h.check('axis.%s.%s exists only if %s is configured' % (a, p, a), False) + h.check('axis input pins exist for all nine axes', True) + h.check('axis.jog-speed defaults to 0', close(h.default('axis.jog-speed'), 0.0)) + h.check('axis.jog-deadband defaults to 0.2', close(h.default('axis.jog-deadband'), 0.2)) + expect_selected(h, 'x', 'at startup') + + +def select(h): + h.pulse('axis.z.select') + expect_selected(h, 'z', 'after axis.z.select') + h.pulse('axis.y.select') + expect_selected(h, 'y', 'after axis.y.select') + h.pulse('axis.a.select') + expect_selected(h, 'y', 'after axis.a.select (A is not configured, ignored)') + h.set('axis.x.select', 1) + expect_selected(h, 'x', 'while axis.x.select is held') + h.pulse('axis.z.select') + expect_selected(h, 'z', 'after axis.z.select while axis.x.select is still held') + h.set('axis.x.select', 0) + h.settle() + expect_selected(h, 'z', 'after releasing axis.x.select') + + +def continuous_jog(h): + to_zero(h) + h.set('axis.jog-speed', 60) + for a in CONFIGURED: + h.set('axis.%s.plus' % a, 1) + expect_velocity(h, a, 1.0, 'while axis.%s.plus is held at jog-speed 60' % a) + h.set('axis.%s.plus' % a, 0) + expect_stopped(h, a, 'when axis.%s.plus is released' % a) + h.set('axis.%s.minus' % a, 1) + expect_velocity(h, a, -1.0, 'while axis.%s.minus is held' % a) + h.set('axis.%s.minus' % a, 0) + expect_stopped(h, a, 'when axis.%s.minus is released' % a) + + to_zero(h) + h.set('axis.jog-speed', 60) + h.set('axis.x.plus', 1) + expect_velocity(h, 'x', 1.0, 'at jog-speed 60') + h.set('axis.jog-speed', 120) + expect_velocity(h, 'x', 2.0, 'after jog-speed changes to 120 mid-jog') + h.set('axis.x.plus', 0) + expect_stopped(h, 'x', 'on release') + h.set('axis.jog-speed', 60) + + # pins for an axis the machine does not have do nothing + h.set('axis.b.plus', 1) + for a in CONFIGURED: + expect_not_moving(h, a, 'while axis.b.plus is held') + h.set('axis.b.plus', 0) + + +def jog_is_gated(h): + to_zero(h) + h.set('axis.jog-speed', 60) + h.nml_teleop(0) + h.set('axis.x.plus', 1) + expect_not_moving(h, 'x', 'in joint (free) mode') + h.set('axis.x.plus', 0) + + h.nml_state(L.STATE_OFF) + h.set('axis.y.plus', 1) + expect_not_moving(h, 'y', 'when the machine is off') + h.set('axis.y.plus', 0) + + +def analog_jog(h): + to_zero(h) + h.set('axis.jog-speed', 60) + h.set('axis.x.analog', 0.5) + expect_velocity(h, 'x', 0.5, 'at analog 0.5') + h.set('axis.x.analog', -0.8) + expect_velocity(h, 'x', -0.8, 'at analog -0.8') + h.set('axis.x.analog', 0.15) + expect_stopped(h, 'x', 'at analog 0.15, inside the 0.2 deadband') + h.set('axis.x.analog', 0.0) + h.set('axis.jog-deadband', 0.6) + h.set('axis.y.analog', 0.5) + expect_not_moving(h, 'y', 'at analog 0.5 with a 0.6 deadband') + h.set('axis.y.analog', 0.9) + expect_velocity(h, 'y', 0.9, 'at analog 0.9 with a 0.6 deadband') + h.set('axis.jog-speed', 30) + expect_velocity(h, 'y', 0.45, 'at analog 0.9 after jog-speed changes to 30') + h.set('axis.y.analog', 0.0) + expect_stopped(h, 'y', 'at analog 0') + h.set('axis.jog-deadband', 0.2) + h.set('axis.jog-speed', 60) + h.set('axis.z.analog', -0.4) + expect_velocity(h, 'z', -0.4, 'at analog -0.4') + h.set('axis.z.analog', 0.0) + expect_stopped(h, 'z', 'at analog 0') + + +def incremental_jog(h): + to_zero(h) + h.set('axis.jog-speed', 60) + for a in CONFIGURED: + h.set('axis.%s.increment' % a, 0.25) + h.pulse('axis.%s.increment-plus' % a) + expect_at(h, a, 0.25, 'after increment-plus') + h.pulse('axis.%s.increment-minus' % a) + expect_at(h, a, 0.0, 'after increment-minus') + + h.pulse('axis.y.select') + h.set('axis.selected.increment', 0.5) + h.pulse('axis.selected.increment-plus') + expect_at(h, 'y', 0.5, 'after axis.selected.increment-plus with y selected') + h.pulse('axis.selected.increment-minus') + expect_at(h, 'y', 0.0, 'after axis.selected.increment-minus') + h.check('the selected increment moved only y', + close(pos(h, 'x'), 0.0, 1e-4) and close(pos(h, 'z'), 0.0, 1e-4), + 'x=%+.4f z=%+.4f' % (pos(h, 'x'), pos(h, 'z'))) + + +def selected_jog(h): + to_zero(h) + h.set('axis.jog-speed', 60) + h.pulse('axis.x.select') + h.set('axis.selected.plus', 1) + expect_velocity(h, 'x', 1.0, 'while axis.selected.plus is held with x selected') + h.set('axis.selected.plus', 0) + expect_stopped(h, 'x', 'on release') + h.set('axis.selected.minus', 1) + expect_velocity(h, 'x', -1.0, 'while axis.selected.minus is held') + h.set('axis.selected.minus', 0) + expect_stopped(h, 'x', 'on release') + + # Changing the selection mid-jog should stop the old axis and start the + # new one, as it does for joints. For axes the restart looks at + # ajog_plus[num_axes] / ajog_minus[num_axes] -- the pins of the axis whose + # index equals the number of configured axes (A on this XYZ machine) -- + # instead of the selected slot ajog_*[EMCMOT_MAX_AXIS]. + h.set('axis.selected.plus', 1) + expect_velocity(h, 'x', 1.0, 'before the selection changes') + h.pulse('axis.y.select') + expect_stopped(h, 'x', 'when the selection moves to y mid-jog') + h.known_bug('a selected jog does not carry over to the newly selected axis', + h.stays(lambda: close(av(h, 'y'), 0.0, 1e-9), 0.8), + 'halui.cc check_hal_changes(): axis reselect reads ajog_plus[num_axes] ' + 'instead of ajog_plus[EMCMOT_MAX_AXIS]; y should be jogging at +1') + h.set('axis.selected.plus', 0) + h.nml_abort() + to_zero(h) + + # the same index error from the other side: A's pin (inert on this + # machine) starts a jog on whichever axis gets selected + h.pulse('axis.x.select') + h.set('axis.a.plus', 1) + expect_not_moving(h, 'x', 'while only axis.a.plus is held (A is not configured)') + h.pulse('axis.z.select') + h.known_bug('holding axis.a.plus makes a newly selected axis jog', + h.wait_for(lambda: close(av(h, 'z'), 1.0, 1e-3), 1.0), + 'same ajog_plus[num_axes] index: num_axes is 3 here, which is axis A; ' + 'z should stay still') + h.set('axis.a.plus', 0) + h.nml_abort() + + +def expected_relative(s): + """halui's own formula (modify_hal_pins) from task's offsets.""" + ax, ay, az = s.actual_position[:3] + g5x, g92, tlo, rot = s.g5x_offset, s.g92_offset, s.tool_offset, s.rotation_xy + x = ax - g5x[0] - tlo[0] + y = ay - g5x[1] - tlo[1] + c, sn = math.cos(-rot * math.pi / 180), math.sin(-rot * math.pi / 180) + return (x * c - y * sn - g92[0], + y * c + x * sn - g92[1], + az - g5x[2] - g92[2] - tlo[2]) + + +def expect_positions(h, machine, relative, why): + for i, a in enumerate(CONFIGURED): + h.expect_pin('axis.%s.pos-commanded is %+.3f %s' % (a, machine[i], why), + 'axis.%s.pos-commanded' % a, machine[i], tol=1e-6) + h.expect_pin('axis.%s.pos-feedback is %+.3f %s' % (a, machine[i], why), + 'axis.%s.pos-feedback' % a, machine[i], tol=1e-6) + h.expect_pin('axis.%s.pos-relative is %+.3f %s' % (a, relative[i], why), + 'axis.%s.pos-relative' % a, relative[i], tol=1e-6) + + +def positions(h): + h.machine_on() + h.nml_home_all() + for code in ('G20 G90 G54', 'G92.1', 'G49', 'G10 L2 P1 X0 Y0 Z0 R0', 'M61 Q0', + 'G53 G0 X1 Y2 Z0.5'): + h.nml_mdi(code) + expect_positions(h, (1, 2, 0.5), (1, 2, 0.5), 'with no offsets') + + for code in ('G10 L2 P1 X1 Y2 Z0.5 R30', 'M61 Q1', 'G43', 'G53 G0 X3 Y4 Z1', + 'G92 X0.5 Y-0.5'): + h.nml_mdi(code) + s = h.poll() + h.check('setup: task has a G54 offset, G92 offset, rotation and tool offset', + close(s.g5x_offset[0], 1) and close(s.rotation_xy, 30) and close(s.tool_offset[2], 0.5) + and not close(s.g92_offset[0], 0), + 'g5x=%s g92=%s rot=%s tlo=%s' % (s.g5x_offset[:3], s.g92_offset[:3], + s.rotation_xy, s.tool_offset[:3])) + rel = expected_relative(s) + expect_positions(h, (3, 4, 1), rel, 'with G54 + G92 + R30 + G43') + # G92 X0.5 Y-0.5 defines the current point as X0.5 Y-0.5 in program + # coordinates, and Z is machine 1 - G54 0.5 - tool 0.5 = 0 + for a, want in (('x', 0.5), ('y', -0.5), ('z', 0.0)): + h.expect_pin('axis.%s.pos-relative agrees with program coordinates (%+.2f)' % (a, want), + 'axis.%s.pos-relative' % a, want, tol=1e-6) + + # the pins follow motion + teleop(h) + h.set('axis.jog-speed', 60) + h.set('axis.x.increment', 0.5) + h.pulse('axis.x.increment-plus') + expect_at(h, 'x', 3.5, 'after an increment in teleop') + rel = expected_relative(h.poll()) + expect_positions(h, (3.5, 4, 1), rel, 'after moving X by 0.5') + + for code in ('G92.1', 'G49', 'G10 L2 P1 X0 Y0 Z0 R0', 'M61 Q0'): + h.nml_mdi(code) + + +run(pins_and_defaults, + select, + continuous_jog, + jog_is_gated, + analog_jog, + incremental_jog, + selected_jog, + positions) diff --git a/tests/halui/axes/test.sh b/tests/halui/axes/test.sh new file mode 100755 index 00000000000..fd122f82169 --- /dev/null +++ b/tests/halui/axes/test.sh @@ -0,0 +1,2 @@ +#!/bin/bash +exec ../_lib/launch.sh diff --git a/tests/halui/config-9axis/checkresult b/tests/halui/config-9axis/checkresult new file mode 100755 index 00000000000..73e90a43dfc --- /dev/null +++ b/tests/halui/config-9axis/checkresult @@ -0,0 +1,2 @@ +#!/bin/sh +exit 0 # test failure is indicated by test.sh exit value diff --git a/tests/halui/config-9axis/halui.ini b/tests/halui/config-9axis/halui.ini new file mode 100644 index 00000000000..e7501e2a64d --- /dev/null +++ b/tests/halui/config-9axis/halui.ini @@ -0,0 +1,194 @@ +# Nine-axis machine for the halui pin tests: trivkins XYZABCUVW, one joint +# per axis, so every per-axis halui pin exists and does something. + +[EMC] +VERSION = 1.1 +DEBUG = 0 + +[DISPLAY] +DISPLAY = ./test-ui.py + +[TASK] +TASK = milltask +CYCLE_TIME = 0.001 + +[RS274NGC] +PARAMETER_FILE = sim.var + +[EMCMOT] +EMCMOT = motmod +COMM_TIMEOUT = 4.0 +BASE_PERIOD = 0 +SERVO_PERIOD = 1000000 + +[EMCIO] +TOOL_TABLE = tool.tbl + +[HAL] +HALFILE = nine.hal + +[TRAJ] +COORDINATES = X Y Z A B C U V W +LINEAR_UNITS = inch +ANGULAR_UNITS = degree +DEFAULT_LINEAR_VELOCITY = 1.2 +MAX_LINEAR_VELOCITY = 4 +MAX_ANGULAR_VELOCITY = 60 +NO_FORCE_HOMING = 1 + +[KINS] +KINEMATICS = trivkins coordinates=XYZABCUVW +JOINTS = 9 + +[AXIS_X] +MIN_LIMIT = -40.0 +MAX_LIMIT = 40.0 +MAX_VELOCITY = 4 +MAX_ACCELERATION = 1000.0 + +[AXIS_Y] +MIN_LIMIT = -40.0 +MAX_LIMIT = 40.0 +MAX_VELOCITY = 4 +MAX_ACCELERATION = 1000.0 + +[AXIS_Z] +MIN_LIMIT = -40.0 +MAX_LIMIT = 40.0 +MAX_VELOCITY = 4 +MAX_ACCELERATION = 1000.0 + +[AXIS_A] +MIN_LIMIT = -360.0 +MAX_LIMIT = 360.0 +MAX_VELOCITY = 60 +MAX_ACCELERATION = 1000.0 + +[AXIS_B] +MIN_LIMIT = -360.0 +MAX_LIMIT = 360.0 +MAX_VELOCITY = 60 +MAX_ACCELERATION = 1000.0 + +[AXIS_C] +MIN_LIMIT = -360.0 +MAX_LIMIT = 360.0 +MAX_VELOCITY = 60 +MAX_ACCELERATION = 1000.0 + +[AXIS_U] +MIN_LIMIT = -40.0 +MAX_LIMIT = 40.0 +MAX_VELOCITY = 4 +MAX_ACCELERATION = 1000.0 + +[AXIS_V] +MIN_LIMIT = -40.0 +MAX_LIMIT = 40.0 +MAX_VELOCITY = 4 +MAX_ACCELERATION = 1000.0 + +[AXIS_W] +MIN_LIMIT = -40.0 +MAX_LIMIT = 40.0 +MAX_VELOCITY = 4 +MAX_ACCELERATION = 1000.0 + +[JOINT_0] +TYPE = LINEAR +HOME = 0.0 +MAX_VELOCITY = 4 +MAX_ACCELERATION = 1000.0 +MIN_LIMIT = -40.0 +MAX_LIMIT = 40.0 +FERROR = 1.0 +MIN_FERROR = 0.5 +HOME_SEQUENCE = 0 + +[JOINT_1] +TYPE = LINEAR +HOME = 0.0 +MAX_VELOCITY = 4 +MAX_ACCELERATION = 1000.0 +MIN_LIMIT = -40.0 +MAX_LIMIT = 40.0 +FERROR = 1.0 +MIN_FERROR = 0.5 +HOME_SEQUENCE = 0 + +[JOINT_2] +TYPE = LINEAR +HOME = 0.0 +MAX_VELOCITY = 4 +MAX_ACCELERATION = 1000.0 +MIN_LIMIT = -40.0 +MAX_LIMIT = 40.0 +FERROR = 1.0 +MIN_FERROR = 0.5 +HOME_SEQUENCE = 0 + +[JOINT_3] +TYPE = ANGULAR +HOME = 0.0 +MAX_VELOCITY = 60 +MAX_ACCELERATION = 1000.0 +MIN_LIMIT = -360.0 +MAX_LIMIT = 360.0 +FERROR = 1.0 +MIN_FERROR = 0.5 +HOME_SEQUENCE = 0 + +[JOINT_4] +TYPE = ANGULAR +HOME = 0.0 +MAX_VELOCITY = 60 +MAX_ACCELERATION = 1000.0 +MIN_LIMIT = -360.0 +MAX_LIMIT = 360.0 +FERROR = 1.0 +MIN_FERROR = 0.5 +HOME_SEQUENCE = 0 + +[JOINT_5] +TYPE = ANGULAR +HOME = 0.0 +MAX_VELOCITY = 60 +MAX_ACCELERATION = 1000.0 +MIN_LIMIT = -360.0 +MAX_LIMIT = 360.0 +FERROR = 1.0 +MIN_FERROR = 0.5 +HOME_SEQUENCE = 0 + +[JOINT_6] +TYPE = LINEAR +HOME = 0.0 +MAX_VELOCITY = 4 +MAX_ACCELERATION = 1000.0 +MIN_LIMIT = -40.0 +MAX_LIMIT = 40.0 +FERROR = 1.0 +MIN_FERROR = 0.5 +HOME_SEQUENCE = 0 + +[JOINT_7] +TYPE = LINEAR +HOME = 0.0 +MAX_VELOCITY = 4 +MAX_ACCELERATION = 1000.0 +MIN_LIMIT = -40.0 +MAX_LIMIT = 40.0 +FERROR = 1.0 +MIN_FERROR = 0.5 +HOME_SEQUENCE = 0 + +[JOINT_8] +TYPE = LINEAR +HOME = 0.0 +MAX_VELOCITY = 4 +MAX_ACCELERATION = 1000.0 +MIN_LIMIT = -40.0 +MAX_LIMIT = 40.0 +FERROR = 1.0 +MIN_FERROR = 0.5 +HOME_SEQUENCE = 0 diff --git a/tests/halui/config-9axis/nine.hal b/tests/halui/config-9axis/nine.hal new file mode 100644 index 00000000000..e90685ec8ab --- /dev/null +++ b/tests/halui/config-9axis/nine.hal @@ -0,0 +1,19 @@ +# nine joints, looped back +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 j0pos joint.0.motor-pos-cmd => joint.0.motor-pos-fb +net j1pos joint.1.motor-pos-cmd => joint.1.motor-pos-fb +net j2pos joint.2.motor-pos-cmd => joint.2.motor-pos-fb +net j3pos joint.3.motor-pos-cmd => joint.3.motor-pos-fb +net j4pos joint.4.motor-pos-cmd => joint.4.motor-pos-fb +net j5pos joint.5.motor-pos-cmd => joint.5.motor-pos-fb +net j6pos joint.6.motor-pos-cmd => joint.6.motor-pos-fb +net j7pos joint.7.motor-pos-cmd => joint.7.motor-pos-fb +net j8pos joint.8.motor-pos-cmd => joint.8.motor-pos-fb + +net estop-loop iocontrol.0.user-enable-out iocontrol.0.emc-enable-in +net tool-prep-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/halui/config-9axis/test-ui.py b/tests/halui/config-9axis/test-ui.py new file mode 100755 index 00000000000..25f33eb7c03 --- /dev/null +++ b/tests/halui/config-9axis/test-ui.py @@ -0,0 +1,130 @@ +#!/usr/bin/env python3 +"""halui on a nine-axis machine (trivkins XYZABCUVW, joint N drives axis N). + +Every per-axis halui pin exists here, so this covers selection, jogging, +positions and tool length offsets for A, B, C, U, V and W too. +""" + +import os +import sys + +sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', '_lib')) +from halui_test import run, close # noqa: E402 + +import linuxcnc as L # noqa: E402 + +LETTERS = 'xyzabcuvw' + + +def jv(h, j): + return h.stat.joint[j]['velocity'] + + +def teleop(h): + h.machine_on() + h.nml_mode(L.MODE_MANUAL) + if not all(h.poll().homed[:9]): + h.nml_home_all() + if h.stat.motion_mode != L.TRAJ_MODE_TELEOP: + h.nml_teleop(1) + + +def pins(h): + missing = ['axis.%s.%s' % (a, p) for a in LETTERS + for p in ('is-selected', 'pos-commanded', 'pos-feedback', 'pos-relative', + 'select', 'plus', 'minus', 'analog', 'increment', + 'increment-plus', 'increment-minus') + if not h.has('axis.%s.%s' % (a, p))] + h.check('every axis has its full set of pins', not missing, 'missing: %s' % missing) + h.check('joint pins exist for all nine joints', + all(h.has('joint.%d.is-homed' % j) for j in range(9))) + + +def select_every_axis(h): + for i, a in enumerate(LETTERS): + h.pulse('axis.%s.select' % a) + h.expect_pin('axis.selected is %d after axis.%s.select' % (i, a), 'axis.selected', i) + wrong = [b for b in LETTERS if h.get('axis.%s.is-selected' % b) != (a == b)] + h.check('only axis.%s.is-selected is set' % a, not wrong, 'also set/unset: %s' % wrong) + + +def jog_every_axis(h): + teleop(h) + h.set('axis.jog-speed', 60) + for i, a in enumerate(LETTERS): + h.set('axis.%s.plus' % a, 1) + h.expect('axis.%s.plus jogs joint %d' % (a, i), lambda i=i: close(jv(h, i), 1.0, 1e-3), + detail=lambda i=i: 'joint %d velocity %+.4f' % (i, jv(h, i))) + others = [j for j in range(9) if j != i and not close(jv(h, j), 0.0, 1e-9)] + h.check('only joint %d moves' % i, not others, 'also moving: %s' % others) + h.set('axis.%s.plus' % a, 0) + h.expect('axis %s stops on release' % a, + lambda i=i: close(jv(h, i), 0.0, 1e-9) and h.stat.inpos) + + +def reselect_carries_over(h): + # On an XYZ machine this is a known bug (see tests/halui/axes): the + # restart reads ajog_plus[num_axes]. Here num_axes == EMCMOT_MAX_AXIS == 9, + # which happens to be the right slot, so the jog does carry over. + teleop(h) + h.set('axis.jog-speed', 60) + h.pulse('axis.x.select') + h.set('axis.selected.plus', 1) + h.expect('x jogs as the selected axis', lambda: close(jv(h, 0), 1.0, 1e-3)) + h.pulse('axis.y.select') + h.expect('x stops when the selection moves to y', lambda: close(jv(h, 0), 0.0, 1e-9)) + h.expect('y picks up the selected jog (correct only because num_axes is 9 here)', + lambda: close(jv(h, 1), 1.0, 1e-3)) + h.set('axis.selected.plus', 0) + h.expect('y stops on release', lambda: close(jv(h, 1), 0.0, 1e-9) and h.stat.inpos) + + +def expect_positions(h, machine, relative, why): + for i, a in enumerate(LETTERS): + h.expect_pin('axis.%s.pos-commanded is %g %s' % (a, machine[i], why), + 'axis.%s.pos-commanded' % a, machine[i], tol=1e-6) + h.expect_pin('axis.%s.pos-feedback is %g %s' % (a, machine[i], why), + 'axis.%s.pos-feedback' % a, machine[i], tol=1e-6) + h.expect_pin('axis.%s.pos-relative is %g %s' % (a, relative[i], why), + 'axis.%s.pos-relative' % a, relative[i], tol=1e-6) + + +def expect_tool_offsets(h, offsets, why): + for i, a in enumerate(LETTERS): + h.expect_pin('tool.length_offset.%s is %g %s' % (a, offsets[i], why), + 'tool.length_offset.' + a, offsets[i], tol=1e-6) + + +def positions_and_offsets(h): + h.machine_on() + h.nml_home_all() + for code in ('G20 G90 G54 G49', 'G92.1', 'G10 L2 P1 X0 Y0 Z0 A0 B0 C0 U0 V0 W0 R0'): + h.nml_mdi(code) + + machine = [i + 2 for i in range(9)] + h.nml_mdi('G53 G0 X2 Y3 Z4 A5 B6 C7 U8 V9 W10') + expect_positions(h, machine, machine, 'with no offsets') + expect_tool_offsets(h, [0] * 9, 'with no tool offset') + + h.nml_mdi('G10 L2 P1 X1 Y2 Z3 A4 B5 C6 U7 V8 W9') + work = [1 + i for i in range(9)] + expect_positions(h, machine, [m - w for m, w in zip(machine, work)], 'with a G54 offset on every axis') + + tlo = [round(0.1 * (i + 1), 1) for i in range(9)] + h.nml_mdi('G43.1 X0.1 Y0.2 Z0.3 A0.4 B0.5 C0.6 U0.7 V0.8 W0.9') + expect_tool_offsets(h, tlo, 'after G43.1 on every axis') + expect_positions(h, machine, [m - w - t for m, w, t in zip(machine, work, tlo)], + 'with G54 and a tool offset on every axis') + + h.nml_mdi('G92 A0 U0 W0') + s = h.poll() + for i, a in ((3, 'a'), (6, 'u'), (8, 'w')): + h.expect_pin('axis.%s.pos-relative is 0 after G92 %s0' % (a, a.upper()), + 'axis.%s.pos-relative' % a, 0.0, tol=1e-6) + h.check('setup: G92 left the other axes alone', close(s.g92_offset[4], 0.0)) + + for code in ('G92.1', 'G49', 'G10 L2 P1 X0 Y0 Z0 A0 B0 C0 U0 V0 W0'): + h.nml_mdi(code) + + +run(pins, select_every_axis, jog_every_axis, reselect_carries_over, positions_and_offsets) diff --git a/tests/halui/config-9axis/test.sh b/tests/halui/config-9axis/test.sh new file mode 100755 index 00000000000..fd122f82169 --- /dev/null +++ b/tests/halui/config-9axis/test.sh @@ -0,0 +1,2 @@ +#!/bin/bash +exec ../_lib/launch.sh diff --git a/tests/halui/config-minimal/checkresult b/tests/halui/config-minimal/checkresult new file mode 100755 index 00000000000..73e90a43dfc --- /dev/null +++ b/tests/halui/config-minimal/checkresult @@ -0,0 +1,2 @@ +#!/bin/sh +exit 0 # test failure is indicated by test.sh exit value diff --git a/tests/halui/config-minimal/halui.ini b/tests/halui/config-minimal/halui.ini new file mode 100644 index 00000000000..f6e70986383 --- /dev/null +++ b/tests/halui/config-minimal/halui.ini @@ -0,0 +1,74 @@ +# Minimal/odd machine for the halui pin tests: two joints driving Y and Z, +# two spindles, no home sequence and no MDI commands -- so halui.home-all, +# halui.halui-mdi-is-running and halui.mdi-command-NN must not exist. + +[EMC] +VERSION = 1.1 +DEBUG = 0 + +[DISPLAY] +DISPLAY = ./test-ui.py + +[TASK] +TASK = milltask +CYCLE_TIME = 0.001 + +[RS274NGC] +PARAMETER_FILE = sim.var + +[EMCMOT] +EMCMOT = motmod +COMM_TIMEOUT = 4.0 +BASE_PERIOD = 0 +SERVO_PERIOD = 1000000 + +[EMCIO] +TOOL_TABLE = tool.tbl + +[HAL] +HALFILE = minimal.hal + +[TRAJ] +COORDINATES = Y Z +LINEAR_UNITS = inch +ANGULAR_UNITS = degree +DEFAULT_LINEAR_VELOCITY = 1.2 +MAX_LINEAR_VELOCITY = 4 +SPINDLES = 2 +NO_FORCE_HOMING = 1 + +[KINS] +KINEMATICS = trivkins coordinates=YZ +JOINTS = 2 + +[AXIS_Y] +MIN_LIMIT = -40.0 +MAX_LIMIT = 40.0 +MAX_VELOCITY = 4 +MAX_ACCELERATION = 1000.0 + +[AXIS_Z] +MIN_LIMIT = -4.0 +MAX_LIMIT = 4.0 +MAX_VELOCITY = 4 +MAX_ACCELERATION = 1000.0 + +[JOINT_0] +TYPE = LINEAR +HOME = 0.0 +MAX_VELOCITY = 4 +MAX_ACCELERATION = 1000.0 +MIN_LIMIT = -40.0 +MAX_LIMIT = 40.0 +FERROR = 0.050 +MIN_FERROR = 0.010 + +[JOINT_1] +TYPE = LINEAR +HOME = 0.0 +MAX_VELOCITY = 4 +MAX_ACCELERATION = 1000.0 +MIN_LIMIT = -4.0 +MAX_LIMIT = 4.0 +FERROR = 0.050 +MIN_FERROR = 0.010 diff --git a/tests/halui/config-minimal/minimal.hal b/tests/halui/config-minimal/minimal.hal new file mode 100644 index 00000000000..c9cbd1effbf --- /dev/null +++ b/tests/halui/config-minimal/minimal.hal @@ -0,0 +1,12 @@ +# two joints, two spindles, everything looped back +loadrt [KINS]KINEMATICS +loadrt [EMCMOT]EMCMOT base_period_nsec=[EMCMOT]BASE_PERIOD servo_period_nsec=[EMCMOT]SERVO_PERIOD num_joints=[KINS]JOINTS num_spindles=[TRAJ]SPINDLES +addf motion-command-handler servo-thread +addf motion-controller servo-thread + +net j0pos joint.0.motor-pos-cmd => joint.0.motor-pos-fb +net j1pos joint.1.motor-pos-cmd => joint.1.motor-pos-fb + +net estop-loop iocontrol.0.user-enable-out iocontrol.0.emc-enable-in +net tool-prep-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/halui/config-minimal/test-ui.py b/tests/halui/config-minimal/test-ui.py new file mode 100755 index 00000000000..69d8488810b --- /dev/null +++ b/tests/halui/config-minimal/test-ui.py @@ -0,0 +1,172 @@ +#!/usr/bin/env python3 +"""halui on a two-joint YZ machine with two spindles, no home sequence and +no MDI commands. + +Checks which pins exist for this configuration, that a second spindle is +driven independently, and how axis selection starts up when the first +configured axis is not X. Joint 0 drives Y and joint 1 drives Z. +""" + +import os +import sys + +sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', '_lib')) +from halui_test import run, close # noqa: E402 + +import linuxcnc as L # noqa: E402 + +LETTERS = 'xyzabcuvw' +CONFIGURED = 'yz' +JOINT_OF = {'y': 0, 'z': 1} + + +def jv(h, j): + return h.stat.joint[j]['velocity'] + + +def home_each(h): + # there is no home sequence, so home-all is not an option: one at a time + h.machine_on() + h.nml_mode(L.MODE_MANUAL) + for j in (0, 1): + if not h.poll().homed[j]: + h.cmd.home(j) + h.cmd.wait_complete() + if not h.wait_for(lambda j=j: h.stat.homed[j]): + raise RuntimeError('setup: could not home joint %d' % j) + + +def teleop(h): + home_each(h) + if h.poll().motion_mode != L.TRAJ_MODE_TELEOP: + h.nml_teleop(1) + + +def pins(h): + h.check('no home-all pin without [JOINT_n]HOME_SEQUENCE', not h.has('home-all')) + h.check('no halui-mdi-is-running pin without [HALUI]MDI_COMMAND', + not h.has('halui-mdi-is-running')) + h.check('no mdi-command pins without [HALUI]MDI_COMMAND', + not any(p.startswith('mdi-command-') for p in h.pins)) + h.check('joint pins exist for joints 0 and 1', + all(h.has('joint.%d.%s' % (j, p)) for j in (0, 1) for p in ('home', 'is-homed', 'plus'))) + h.check('no pins for joint 2', not any(p.startswith('joint.2.') for p in h.pins)) + h.check('spindle pins exist for spindles 0 and 1', + all(h.has('spindle.%d.%s' % (s, p)) for s in (0, 1) + for p in ('start', 'is-on', 'brake-on', 'override.value'))) + h.check('no pins for spindle 2', not any(p.startswith('spindle.2.') for p in h.pins)) + wrong = [a for a in LETTERS + for p in ('is-selected', 'pos-commanded', 'pos-feedback', 'pos-relative') + if h.has('axis.%s.%s' % (a, p)) != (a in CONFIGURED)] + h.check('axis status pins exist only for Y and Z', not wrong, 'wrong: %s' % wrong) + h.check('axis input pins exist for all nine axes', + all(h.has('axis.%s.plus' % a) for a in LETTERS)) + + +def startup_selection(h): + h.expect_pin('joint.0.is-selected is true at startup', 'joint.0.is-selected', True) + h.expect_pin('axis.y.is-selected marks the first configured axis', 'axis.y.is-selected', True) + h.expect_pin('axis.z.is-selected is false at startup', 'axis.z.is-selected', False) + h.known_bug('axis.selected is 0 (X, not on this machine) at startup', + h.get('axis.selected') == 0, + 'hal_init_pins() sets axis_selected to 0 while halui_hal_init() marks the ' + 'first configured axis (Y, index 1) as selected; should be 1') + + teleop(h) + h.set('axis.jog-speed', 60) + h.set('axis.selected.plus', 1) + h.known_bug('axis.selected.plus at startup does not jog the axis shown as selected', + h.stays(lambda: close(jv(h, JOINT_OF['y']), 0.0, 1e-9), 0.8), + 'the jog goes to axis index 0 (X), which halui then drops as not configured') + h.set('axis.selected.plus', 0) + h.settle() + + h.pulse('axis.y.select') + h.expect_pin('pressing axis.y.select makes axis.selected 1', 'axis.selected', 1) + h.set('axis.selected.plus', 1) + h.expect('after that, axis.selected.plus jogs Y', + lambda: close(jv(h, JOINT_OF['y']), 1.0, 1e-3), + detail=lambda: 'joint 0 velocity %+.4f' % jv(h, 0)) + h.set('axis.selected.plus', 0) + h.expect('Y stops on release', lambda: close(jv(h, 0), 0.0, 1e-9) and h.stat.inpos) + + +def second_spindle(h): + h.machine_on() + h.nml_mode(L.MODE_MANUAL) + + def sp(s): + return h.stat.spindle[s] + + h.pulse('spindle.1.start') + h.expect('spindle.1.start turns spindle 1 on', + lambda: sp(1)['enabled'] and sp(1)['speed'] == 1) + h.check('spindle 0 stays off', not sp(0)['enabled']) + h.expect_pin('spindle.1.is-on sets', 'spindle.1.is-on', True) + h.expect_pin('spindle.1.runs-forward sets', 'spindle.1.runs-forward', True) + h.expect_pin('spindle.0.is-on stays false', 'spindle.0.is-on', False) + + h.pulse('spindle.1.reverse') + h.expect('spindle.1.reverse reverses spindle 1', lambda: sp(1)['direction'] == -1) + h.expect_pin('spindle.1.runs-backward sets', 'spindle.1.runs-backward', True) + h.pulse('spindle.1.stop') + h.expect('spindle.1.stop stops spindle 1', lambda: not sp(1)['enabled']) + h.expect_pin('spindle.1.is-on clears', 'spindle.1.is-on', False) + + brake0 = sp(0)['brake'] + h.pulse('spindle.1.brake-on') + h.expect('spindle.1.brake-on engages brake 1', lambda: sp(1)['brake'] == 1) + h.expect_pin('spindle.1.brake-is-on sets', 'spindle.1.brake-is-on', True) + h.check('brake 0 is untouched', sp(0)['brake'] == brake0, + 'brake 0 was %d, now %d' % (brake0, sp(0)['brake'])) + h.pulse('spindle.1.brake-off') + h.expect_pin('spindle.1.brake-is-on clears', 'spindle.1.brake-is-on', False) + + # no [DISPLAY] spindle override limits here: halui clamps to 0 .. 1.0 + h.pulse('spindle.1.override.decrease') + h.expect('spindle.1.override.decrease lowers override 1', + lambda: close(sp(1)['override'], 0.9)) + h.check('override 0 is untouched', close(sp(0)['override'], 1.0)) + h.expect_pin('spindle.1.override.value follows', 'spindle.1.override.value', 0.9) + h.pulse('spindle.1.override.increase') + h.pulse('spindle.1.override.increase') + h.expect('spindle 1 override is clamped at the default maximum of 1.0', + lambda: close(sp(1)['override'], 1.0)) + h.set('spindle.1.override.counts', -3) + h.expect('spindle.1.override.counts moves override 1', lambda: close(sp(1)['override'], 0.7)) + h.pulse('spindle.1.override.reset') + h.expect('spindle.1.override.reset puts it back to 1.0', lambda: close(sp(1)['override'], 1.0)) + + +def motion(h): + home_each(h) + if h.poll().motion_mode != L.TRAJ_MODE_FREE: + h.nml_teleop(0) + h.set('joint.jog-speed', 60) + h.set('joint.1.plus', 1) + h.expect('joint.1.plus jogs joint 1', lambda: close(jv(h, 1), 1.0, 1e-3)) + h.set('joint.1.plus', 0) + h.expect('joint 1 stops on release', lambda: close(jv(h, 1), 0.0, 1e-9) and h.stat.inpos) + + teleop(h) + h.set('axis.jog-speed', 60) + h.set('axis.z.plus', 1) + h.expect('axis.z.plus moves joint 1 (Z)', lambda: close(jv(h, 1), 1.0, 1e-3)) + h.set('axis.z.plus', 0) + h.expect('Z stops on release', lambda: close(jv(h, 1), 0.0, 1e-9) and h.stat.inpos) + h.set('axis.y.minus', 1) + h.expect('axis.y.minus moves joint 0 (Y) backwards', lambda: close(jv(h, 0), -1.0, 1e-3)) + h.set('axis.y.minus', 0) + h.expect('Y stops on release', lambda: close(jv(h, 0), 0.0, 1e-9) and h.stat.inpos) + + h.set('axis.x.plus', 1) + h.expect_steady('axis.x.plus moves nothing on a machine without X', + lambda: close(jv(h, 0), 0.0, 1e-9) and close(jv(h, 1), 0.0, 1e-9)) + h.set('axis.x.plus', 0) + + h.nml_mdi('G20 G90 G53 G0 Y1.5 Z-0.5') + h.expect_pin('axis.y.pos-feedback shows Y', 'axis.y.pos-feedback', 1.5) + h.expect_pin('axis.z.pos-feedback shows Z', 'axis.z.pos-feedback', -0.5) + + +run(pins, startup_selection, second_spindle, motion) diff --git a/tests/halui/config-minimal/test.sh b/tests/halui/config-minimal/test.sh new file mode 100755 index 00000000000..fd122f82169 --- /dev/null +++ b/tests/halui/config-minimal/test.sh @@ -0,0 +1,2 @@ +#!/bin/bash +exec ../_lib/launch.sh diff --git a/tests/halui/joints/checkresult b/tests/halui/joints/checkresult new file mode 100755 index 00000000000..73e90a43dfc --- /dev/null +++ b/tests/halui/joints/checkresult @@ -0,0 +1,2 @@ +#!/bin/sh +exit 0 # test failure is indicated by test.sh exit value diff --git a/tests/halui/joints/halui.ini b/tests/halui/joints/halui.ini new file mode 100644 index 00000000000..4d21b0429ec --- /dev/null +++ b/tests/halui/joints/halui.ini @@ -0,0 +1,100 @@ +# Test machine shared by the halui pin tests: XYZ trivkins, one spindle, +# a tool table, a home sequence (so halui.home-all exists) and two MDI +# commands (so halui.halui-mdi-is-running and halui.mdi-command-NN exist). + +[EMC] +VERSION = 1.1 +DEBUG = 0 + +[DISPLAY] +DISPLAY = ./test-ui.py +MAX_FEED_OVERRIDE = 1.5 +MIN_SPINDLE_OVERRIDE = 0.5 +MAX_SPINDLE_OVERRIDE = 1.2 + +[TASK] +TASK = milltask +CYCLE_TIME = 0.001 + +[RS274NGC] +PARAMETER_FILE = sim.var + +[EMCMOT] +EMCMOT = motmod +COMM_TIMEOUT = 4.0 +BASE_PERIOD = 0 +SERVO_PERIOD = 1000000 + +[EMCIO] +TOOL_TABLE = tool.tbl + +[HAL] +HALFILE = LIB:core_sim.hal + +[HALUI] +MDI_COMMAND = G0 X1 Y0 Z0 +MDI_COMMAND = G0 X0 Y0 Z0 + +[TRAJ] +COORDINATES = X Y Z +LINEAR_UNITS = inch +ANGULAR_UNITS = degree +DEFAULT_LINEAR_VELOCITY = 1.2 +MAX_LINEAR_VELOCITY = 4 +SPINDLES = 1 +NO_FORCE_HOMING = 1 + +[KINS] +KINEMATICS = trivkins +JOINTS = 3 + +[AXIS_X] +MIN_LIMIT = -40.0 +MAX_LIMIT = 40.0 +MAX_VELOCITY = 4 +MAX_ACCELERATION = 1000.0 + +[AXIS_Y] +MIN_LIMIT = -40.0 +MAX_LIMIT = 40.0 +MAX_VELOCITY = 4 +MAX_ACCELERATION = 1000.0 + +[AXIS_Z] +MIN_LIMIT = -4.0 +MAX_LIMIT = 4.0 +MAX_VELOCITY = 4 +MAX_ACCELERATION = 1000.0 + +[JOINT_0] +TYPE = LINEAR +HOME = 0.0 +MAX_VELOCITY = 4 +MAX_ACCELERATION = 1000.0 +MIN_LIMIT = -40.0 +MAX_LIMIT = 40.0 +FERROR = 0.050 +MIN_FERROR = 0.010 +HOME_SEQUENCE = 0 + +[JOINT_1] +TYPE = LINEAR +HOME = 0.0 +MAX_VELOCITY = 4 +MAX_ACCELERATION = 1000.0 +MIN_LIMIT = -40.0 +MAX_LIMIT = 40.0 +FERROR = 0.050 +MIN_FERROR = 0.010 +HOME_SEQUENCE = 0 + +[JOINT_2] +TYPE = LINEAR +HOME = 0.0 +MAX_VELOCITY = 4 +MAX_ACCELERATION = 1000.0 +MIN_LIMIT = -4.0 +MAX_LIMIT = 4.0 +FERROR = 0.050 +MIN_FERROR = 0.010 +HOME_SEQUENCE = 0 diff --git a/tests/halui/joints/test-ui.py b/tests/halui/joints/test-ui.py new file mode 100755 index 00000000000..77affb3603f --- /dev/null +++ b/tests/halui/joints/test-ui.py @@ -0,0 +1,442 @@ +#!/usr/bin/env python3 +"""halui: joint selection, homing, joint status and joint jogging. + +Pins: joint.N.select, joint.N.is-selected, joint.selected, + joint.N.home, joint.N.unhome, joint.selected.home, joint.selected.unhome, + home-all, joint.N.is-homed, joint.selected.is-homed, + joint.N.on-{soft,hard}-{min,max}-limit, joint.N.has-fault, + joint.N.override-limits and the joint.selected.* mirrors of those, + joint.jog-speed, joint.jog-deadband, + joint.N.plus, joint.N.minus, joint.N.analog, + joint.N.increment, joint.N.increment-plus, joint.N.increment-minus, + joint.selected.plus, joint.selected.minus, joint.selected.increment, + joint.selected.increment-plus, joint.selected.increment-minus + +Joint jog speed is in units per minute; halui divides it by 60. +""" + +import os +import sys +import time + +sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', '_lib')) +from halui_test import run, close # noqa: E402 + +import hal # noqa: E402 +import linuxcnc as L # noqa: E402 + +JOINTS = 3 + + +def jv(h, j): + return h.stat.joint[j]['velocity'] + + +def expect_velocity(h, j, v, why): + return h.expect('joint %d moves at %+.2f %s' % (j, v, why), + lambda: close(jv(h, j), v, 1e-3), + detail=lambda: 'velocity %+.4f' % jv(h, j)) + + +def expect_stopped(h, j, why): + # per joint: the global in-position flag stays false while another joint + # is still moving + ok = h.wait_for(lambda: close(jv(h, j), 0.0, 1e-9)) and \ + h.stays(lambda: close(jv(h, j), 0.0, 1e-9), 0.2) + h.check('joint %d stops %s' % (j, why), ok, 'velocity %+.4f' % jv(h, j)) + + +def expect_not_moving(h, j, why): + h.expect_steady('joint %d does not move %s' % (j, why), + lambda: close(jv(h, j), 0.0, 1e-9), + detail=lambda: 'velocity %+.4f' % jv(h, j)) + + +def manual_joint_mode(h, homed=False): + h.machine_on() + h.nml_mode(L.MODE_MANUAL) + if homed: + h.nml_home_all() + if h.poll().motion_mode != L.TRAJ_MODE_FREE: + h.nml_teleop(0) + + +def to_zero(h): + manual_joint_mode(h) + h.nml_mdi('G20 G90 G53 G0 X0 Y0 Z0') + h.nml_mode(L.MODE_MANUAL) + if h.poll().motion_mode != L.TRAJ_MODE_FREE: + h.nml_teleop(0) + + +def expect_selected(h, j, why): + h.expect_pin('joint.selected is %d %s' % (j, why), 'joint.selected', j) + for k in range(JOINTS): + h.expect_pin('joint.%d.is-selected is %s %s' % (k, k == j, why), + 'joint.%d.is-selected' % k, k == j) + + +def pins_and_defaults(h): + for j in range(JOINTS): + for p in ('select', 'is-selected', 'home', 'unhome', 'is-homed', 'plus', 'minus', + 'analog', 'increment', 'increment-plus', 'increment-minus', + 'on-soft-min-limit', 'on-soft-max-limit', 'on-hard-min-limit', + 'on-hard-max-limit', 'has-fault', 'override-limits'): + if not h.has('joint.%d.%s' % (j, p)): + h.check('joint.%d.%s exists' % (j, p), False) + h.check('there are no pins for a joint the machine does not have', + not any(s.startswith('joint.%d.' % JOINTS) for s in h.pins)) + h.check('home-all exists because [JOINT_0]HOME_SEQUENCE is set', h.has('home-all')) + h.check('joint.jog-speed defaults to 0', close(h.default('joint.jog-speed'), 0.0)) + h.check('joint.jog-deadband defaults to 0.2', close(h.default('joint.jog-deadband'), 0.2)) + expect_selected(h, 0, 'at startup') + + +def select(h): + h.pulse('joint.2.select') + expect_selected(h, 2, 'after joint.2.select') + h.pulse('joint.1.select') + expect_selected(h, 1, 'after joint.1.select') + + # selection follows the latest rising edge, even while another select is held + h.set('joint.0.select', 1) + expect_selected(h, 0, 'while joint.0.select is held') + h.pulse('joint.2.select') + expect_selected(h, 2, 'after joint.2.select while joint.0.select is still held') + h.set('joint.0.select', 0) + h.settle() + expect_selected(h, 2, 'after releasing joint.0.select (falling edges do nothing)') + + +def homing(h): + manual_joint_mode(h) + h.nml_unhome_all() + for j in range(JOINTS): + h.expect_pin('joint.%d.is-homed is false after unhoming' % j, 'joint.%d.is-homed' % j, False) + + h.pulse('joint.1.home') + h.expect('joint.1.home homes joint 1', lambda: h.stat.homed[1]) + h.expect_pin('joint.1.is-homed sets', 'joint.1.is-homed', True) + h.pulse('joint.1.unhome') + h.expect('joint.1.unhome unhomes joint 1', lambda: not h.stat.homed[1]) + h.expect_pin('joint.1.is-homed clears', 'joint.1.is-homed', False) + + h.pulse('joint.2.select') + h.expect_pin('joint.selected.is-homed is false for unhomed joint 2', + 'joint.selected.is-homed', False) + h.pulse('joint.selected.home') + h.expect('joint.selected.home homes the selected joint (2)', lambda: h.stat.homed[2]) + h.expect_pin('joint.selected.is-homed follows joint 2', 'joint.selected.is-homed', True) + h.pulse('joint.selected.unhome') + h.expect('joint.selected.unhome unhomes the selected joint (2)', lambda: not h.stat.homed[2]) + h.expect_pin('joint.selected.is-homed clears', 'joint.selected.is-homed', False) + + h.pulse('home-all') + h.expect('home-all homes every joint', lambda: all(h.stat.homed[:JOINTS]), timeout=20) + for j in range(JOINTS): + h.expect_pin('joint.%d.is-homed is true after home-all' % j, 'joint.%d.is-homed' % j, True) + h.expect_pin('joint.selected.is-homed is true after home-all', 'joint.selected.is-homed', True) + # task puts an identity-kins machine into teleop once everything is homed + h.expect_pin('mode.is-teleop reports the switch to teleop after homing', 'mode.is-teleop', True) + + # homing is refused while in ESTOP + h.nml_unhome_all() + h.machine_estop() + h.pulse('joint.0.home') + h.expect_steady('joint.0.home in ESTOP does not home', lambda: not h.stat.homed[0]) + h.pulse('home-all') + h.expect_steady('home-all in ESTOP does not home', lambda: not any(h.stat.homed[:JOINTS])) + + +def hard_limits_and_fault(h): + manual_joint_mode(h, homed=True) + h.set('joint.jog-speed', 60) + h.set('joint.0.increment', 0.1) + for kind, motion_pin, key in (('min', 'neg-lim-sw-in', 'min_hard_limit'), + ('max', 'pos-lim-sw-in', 'max_hard_limit')): + manual_joint_mode(h) + h.pulse('joint.0.select') + pin = 'joint.0.on-hard-%s-limit' % kind + sel = 'joint.selected.on-hard-%s-limit' % kind + h.expect_pin('%s is false with the switch open' % pin, pin, False) + hal.set_p('joint.0.' + motion_pin, '1') + h.expect('task sees joint 0 on its hard %s limit' % kind, + lambda k=key: h.stat.joint[0][k]) + h.expect_pin('%s sets' % pin, pin, True) + h.expect_pin('%s follows selected joint 0' % sel, sel, True) + for other in (1, 2): + h.expect_pin('joint.%d.on-hard-%s-limit stays false' % (other, kind), + 'joint.%d.on-hard-%s-limit' % (other, kind), False) + h.pulse('joint.1.select') + h.expect_pin('%s is false while joint 1 is selected' % sel, sel, False) + h.expect_pin('%s is still set for joint 0' % pin, pin, True) + h.pulse('joint.0.select') + h.expect_pin('%s follows joint 0 again once it is reselected' % sel, sel, True) + + # override-limits is a status pin in halui; the override comes over + # NML. task reports one flag for all joints (taskintf.cc: + # overrideLimits = !!overrideLimitMask), so every joint shows it. + h.cmd.override_limits() + h.cmd.wait_complete() + h.expect('task reports the limits overridden', lambda: h.stat.joint[0]['override_limits']) + for j in range(JOINTS): + h.expect_pin('joint.%d.override-limits is set (one flag for all joints)' % j, + 'joint.%d.override-limits' % j, True) + h.expect_pin('joint.selected.override-limits is set', 'joint.selected.override-limits', True) + + hal.set_p('joint.0.' + motion_pin, '0') + h.expect('the hard %s limit clears in task' % kind, lambda k=key: not h.stat.joint[0][k]) + h.expect_pin('%s clears' % pin, pin, False) + h.expect_pin('%s clears' % sel, sel, False) + + # motion drops the override once a jog made while overridden finishes + manual_joint_mode(h) + h.expect_pin('override-limits is still set before any jog', 'joint.0.override-limits', True) + h.pulse('joint.0.increment-plus' if kind == 'min' else 'joint.0.increment-minus') + h.expect('the jog off the switch completes', lambda: h.stat.inpos and close(jv(h, 0), 0.0, 1e-9)) + for j in range(JOINTS): + h.expect_pin('joint.%d.override-limits clears after that jog' % j, + 'joint.%d.override-limits' % j, False) + + manual_joint_mode(h) + h.pulse('joint.2.select') + h.expect_pin('joint.2.has-fault is false', 'joint.2.has-fault', False) + hal.set_p('joint.2.amp-fault-in', '1') + h.expect('task sees the joint 2 amp fault', lambda: h.stat.joint[2]['fault']) + h.expect_pin('joint.2.has-fault sets', 'joint.2.has-fault', True) + h.expect_pin('joint.selected.has-fault follows joint 2', 'joint.selected.has-fault', True) + h.expect_pin('joint.0.has-fault stays false', 'joint.0.has-fault', False) + hal.set_p('joint.2.amp-fault-in', '0') + manual_joint_mode(h) + h.expect('the fault clears in task', lambda: not h.stat.joint[2]['fault']) + h.expect_pin('joint.2.has-fault clears', 'joint.2.has-fault', False) + h.expect_pin('joint.selected.has-fault clears', 'joint.selected.has-fault', False) + + +def soft_limit_pins_never_set(h): + # task never reports per-joint soft limits: taskintf.cc hard-codes + # minSoftLimit/maxSoftLimit to 0 ("soft limits are now applied to the + # command, and should never happen"). motion does still detect a joint + # beyond its soft limit and says so on motion.on-soft-limit. + # + # [JOINT_2] limits are -4 .. 4 and the joint sits at 0. Move the limit + # past the joint through task's ini.N.* pins -- the case motion's own + # comment names as the way this happens. motion then wants the joint + # unhomed before it will move again, so this runs last. + to_zero(h) + manual_joint_mode(h, homed=True) + h.pulse('joint.2.select') + for kind, ini_pin, value in (('min', 'ini.2.min_limit', 1.0), + ('max', 'ini.2.max_limit', -1.0)): + pin = 'joint.2.on-soft-%s-limit' % kind + sel = 'joint.selected.on-soft-%s-limit' % kind + h.expect_pin('%s is false inside the limits' % pin, pin, False) + old = hal.get_value(ini_pin) + hal.set_p(ini_pin, str(value)) + h.expect('motion reports joint 2 beyond its soft %s limit' % kind, + lambda: hal.get_value('motion.on-soft-limit')) + h.known_bug('%s stays false while joint 2 is past that limit' % pin, + h.stays(lambda p=pin, s=sel: not h.get(p) and not h.get(s), 0.5), + 'task hard-codes minSoftLimit/maxSoftLimit to 0 (taskintf.cc), so ' + 'halui.joint.N.on-soft-*-limit and the selected mirrors can never be set') + hal.set_p(ini_pin, str(old)) + h.expect('motion clears on-soft-limit once the limit is restored', + lambda: not hal.get_value('motion.on-soft-limit')) + h.check('the ini limit is back to %g' % old, close(hal.get_value(ini_pin), old)) + h.nml_unhome_all() + + +def continuous_jog(h): + to_zero(h) + h.set('joint.jog-speed', 60) + for j in range(JOINTS): + h.set('joint.%d.plus' % j, 1) + expect_velocity(h, j, 1.0, 'while joint.%d.plus is held at jog-speed 60' % j) + h.set('joint.%d.plus' % j, 0) + expect_stopped(h, j, 'when joint.%d.plus is released' % j) + h.set('joint.%d.minus' % j, 1) + expect_velocity(h, j, -1.0, 'while joint.%d.minus is held' % j) + h.set('joint.%d.minus' % j, 0) + expect_stopped(h, j, 'when joint.%d.minus is released' % j) + + to_zero(h) + h.set('joint.0.plus', 1) + expect_velocity(h, 0, 1.0, 'at jog-speed 60') + h.set('joint.jog-speed', 120) + expect_velocity(h, 0, 2.0, 'after jog-speed changes to 120 mid-jog') + h.set('joint.jog-speed', 30) + expect_velocity(h, 0, 0.5, 'after jog-speed changes to 30 mid-jog') + h.set('joint.0.plus', 0) + expect_stopped(h, 0, 'on release') + + h.set('joint.jog-speed', 60) + h.set('joint.1.plus', 1) + h.set('joint.2.minus', 1) + expect_velocity(h, 1, 1.0, 'together with joint 2') + expect_velocity(h, 2, -1.0, 'together with joint 1') + h.set('joint.1.plus', 0) + expect_stopped(h, 1, 'on release while joint 2 keeps going') + expect_velocity(h, 2, -1.0, 'after joint 1 is released') + h.set('joint.2.minus', 0) + expect_stopped(h, 2, 'on release') + + h.set('joint.jog-speed', 0) + h.set('joint.0.plus', 1) + expect_not_moving(h, 0, 'at jog-speed 0') + h.set('joint.0.plus', 0) + h.set('joint.jog-speed', 60) + + +def jog_is_gated(h): + to_zero(h) + h.set('joint.jog-speed', 60) + + h.nml_state(L.STATE_OFF) + h.set('joint.0.plus', 1) + expect_not_moving(h, 0, 'when the machine is off') + h.set('joint.0.plus', 0) + + manual_joint_mode(h, homed=True) + h.nml_teleop(1) + h.set('joint.0.plus', 1) + expect_not_moving(h, 0, 'in teleop mode') + h.set('joint.0.plus', 0) + h.nml_teleop(0) + + # abort stops a jog; the held input does not restart it + h.set('joint.0.plus', 1) + expect_velocity(h, 0, 1.0, 'before abort') + h.pulse('abort') + expect_stopped(h, 0, 'after abort') + expect_not_moving(h, 0, 'while joint.0.plus is still held after abort') + h.set('joint.0.plus', 0) + + +def analog_jog(h): + to_zero(h) + h.set('joint.jog-speed', 60) + h.set('joint.0.analog', 0.5) + expect_velocity(h, 0, 0.5, 'at analog 0.5') + h.set('joint.0.analog', -0.8) + expect_velocity(h, 0, -0.8, 'at analog -0.8') + h.set('joint.0.analog', 0.1) + expect_stopped(h, 0, 'at analog 0.1, inside the 0.2 deadband') + h.set('joint.0.analog', 0.3) + expect_velocity(h, 0, 0.3, 'at analog 0.3') + h.set('joint.jog-speed', 120) + expect_velocity(h, 0, 0.6, 'at analog 0.3 after jog-speed changes to 120') + h.set('joint.jog-speed', 60) + h.set('joint.0.analog', 0.0) + expect_stopped(h, 0, 'at analog 0') + + h.set('joint.jog-deadband', 0.6) + h.set('joint.0.analog', 0.5) + expect_not_moving(h, 0, 'at analog 0.5 with a 0.6 deadband') + h.set('joint.0.analog', 0.7) + expect_velocity(h, 0, 0.7, 'at analog 0.7 with a 0.6 deadband') + h.set('joint.0.analog', -0.65) + expect_velocity(h, 0, -0.65, 'at analog -0.65 with a 0.6 deadband') + h.set('joint.0.analog', 0.0) + expect_stopped(h, 0, 'at analog 0') + h.set('joint.jog-deadband', 0.2) + + for j in (1, 2): + h.set('joint.%d.analog' % j, -0.4) + expect_velocity(h, j, -0.4, 'at analog -0.4') + h.set('joint.%d.analog' % j, 0.0) + expect_stopped(h, j, 'at analog 0') + + +def expect_at(h, j, pos, why): + return h.expect('joint %d ends at %+.3f %s' % (j, pos, why), + lambda: close(h.joint_pos(j), pos, 1e-4) and h.stat.inpos, + timeout=10, detail=lambda: 'position %+.4f' % h.joint_pos(j)) + + +def incremental_jog(h): + to_zero(h) + h.set('joint.jog-speed', 60) + for j in range(JOINTS): + h.set('joint.%d.increment' % j, 0.25) + h.pulse('joint.%d.increment-plus' % j) + expect_at(h, j, 0.25, 'after increment-plus') + h.pulse('joint.%d.increment-minus' % j) + expect_at(h, j, 0.0, 'after increment-minus') + + h.set('joint.0.increment-plus', 1) + expect_at(h, 0, 0.25, 'while increment-plus is held') + h.expect_steady('a held increment-plus moves only once', + lambda: close(h.joint_pos(0), 0.25, 1e-4), duration=0.6) + h.set('joint.0.increment-plus', 0) + h.settle() + h.expect_steady('releasing increment-plus moves nothing', + lambda: close(h.joint_pos(0), 0.25, 1e-4)) + + h.pulse('joint.1.select') + h.set('joint.selected.increment', 0.5) + h.pulse('joint.selected.increment-plus') + expect_at(h, 1, 0.5, 'after joint.selected.increment-plus with joint 1 selected') + h.pulse('joint.selected.increment-minus') + expect_at(h, 1, 0.0, 'after joint.selected.increment-minus') + h.check('the selected increment did not move joint 0', + close(h.joint_pos(0), 0.25, 1e-4), 'joint 0 at %+.4f' % h.joint_pos(0)) + + h.nml_state(L.STATE_OFF) + h.pulse('joint.2.increment-plus') + h.expect_steady('increment-plus does nothing when the machine is off', + lambda: close(h.joint_pos(2), 0.0, 1e-4)) + + +def selected_jog(h): + to_zero(h) + h.set('joint.jog-speed', 60) + h.pulse('joint.0.select') + + h.set('joint.selected.plus', 1) + expect_velocity(h, 0, 1.0, 'while joint.selected.plus is held') + h.pulse('joint.1.select') + expect_stopped(h, 0, 'when the selection moves to joint 1 mid-jog') + expect_velocity(h, 1, 1.0, 'after being selected mid-jog') + h.set('joint.selected.plus', 0) + expect_stopped(h, 1, 'when joint.selected.plus is released') + + h.set('joint.selected.minus', 1) + expect_velocity(h, 1, -1.0, 'while joint.selected.minus is held') + h.pulse('joint.2.select') + expect_stopped(h, 1, 'when the selection moves to joint 2') + expect_velocity(h, 2, -1.0, 'after being selected during a minus jog') + h.set('joint.selected.minus', 0) + expect_stopped(h, 2, 'on release') + + # a joint jogged on its own pin keeps going when the selection changes + to_zero(h) + h.pulse('joint.0.select') + h.set('joint.2.plus', 1) + h.set('joint.selected.plus', 1) + expect_velocity(h, 0, 1.0, 'as the selected joint') + expect_velocity(h, 2, 1.0, 'on its own pin') + h.pulse('joint.1.select') + expect_stopped(h, 0, 'after the selection moves to joint 1') + expect_velocity(h, 1, 1.0, 'as the newly selected joint') + expect_velocity(h, 2, 1.0, 'still, because its own pin is held') + h.set('joint.selected.plus', 0) + h.set('joint.2.plus', 0) + expect_stopped(h, 1, 'on release') + expect_stopped(h, 2, 'on release') + + # changing the selection when nothing is jogging moves nothing + h.pulse('joint.0.select') + for j in range(JOINTS): + expect_not_moving(h, j, 'after a selection change with no jog active') + + +run(pins_and_defaults, + select, + homing, + hard_limits_and_fault, + continuous_jog, + jog_is_gated, + analog_jog, + incremental_jog, + selected_jog, + soft_limit_pins_never_set) diff --git a/tests/halui/joints/test.sh b/tests/halui/joints/test.sh new file mode 100755 index 00000000000..fd122f82169 --- /dev/null +++ b/tests/halui/joints/test.sh @@ -0,0 +1,2 @@ +#!/bin/bash +exec ../_lib/launch.sh diff --git a/tests/halui/machine-state/checkresult b/tests/halui/machine-state/checkresult new file mode 100755 index 00000000000..73e90a43dfc --- /dev/null +++ b/tests/halui/machine-state/checkresult @@ -0,0 +1,2 @@ +#!/bin/sh +exit 0 # test failure is indicated by test.sh exit value diff --git a/tests/halui/machine-state/halui.ini b/tests/halui/machine-state/halui.ini new file mode 100644 index 00000000000..4d21b0429ec --- /dev/null +++ b/tests/halui/machine-state/halui.ini @@ -0,0 +1,100 @@ +# Test machine shared by the halui pin tests: XYZ trivkins, one spindle, +# a tool table, a home sequence (so halui.home-all exists) and two MDI +# commands (so halui.halui-mdi-is-running and halui.mdi-command-NN exist). + +[EMC] +VERSION = 1.1 +DEBUG = 0 + +[DISPLAY] +DISPLAY = ./test-ui.py +MAX_FEED_OVERRIDE = 1.5 +MIN_SPINDLE_OVERRIDE = 0.5 +MAX_SPINDLE_OVERRIDE = 1.2 + +[TASK] +TASK = milltask +CYCLE_TIME = 0.001 + +[RS274NGC] +PARAMETER_FILE = sim.var + +[EMCMOT] +EMCMOT = motmod +COMM_TIMEOUT = 4.0 +BASE_PERIOD = 0 +SERVO_PERIOD = 1000000 + +[EMCIO] +TOOL_TABLE = tool.tbl + +[HAL] +HALFILE = LIB:core_sim.hal + +[HALUI] +MDI_COMMAND = G0 X1 Y0 Z0 +MDI_COMMAND = G0 X0 Y0 Z0 + +[TRAJ] +COORDINATES = X Y Z +LINEAR_UNITS = inch +ANGULAR_UNITS = degree +DEFAULT_LINEAR_VELOCITY = 1.2 +MAX_LINEAR_VELOCITY = 4 +SPINDLES = 1 +NO_FORCE_HOMING = 1 + +[KINS] +KINEMATICS = trivkins +JOINTS = 3 + +[AXIS_X] +MIN_LIMIT = -40.0 +MAX_LIMIT = 40.0 +MAX_VELOCITY = 4 +MAX_ACCELERATION = 1000.0 + +[AXIS_Y] +MIN_LIMIT = -40.0 +MAX_LIMIT = 40.0 +MAX_VELOCITY = 4 +MAX_ACCELERATION = 1000.0 + +[AXIS_Z] +MIN_LIMIT = -4.0 +MAX_LIMIT = 4.0 +MAX_VELOCITY = 4 +MAX_ACCELERATION = 1000.0 + +[JOINT_0] +TYPE = LINEAR +HOME = 0.0 +MAX_VELOCITY = 4 +MAX_ACCELERATION = 1000.0 +MIN_LIMIT = -40.0 +MAX_LIMIT = 40.0 +FERROR = 0.050 +MIN_FERROR = 0.010 +HOME_SEQUENCE = 0 + +[JOINT_1] +TYPE = LINEAR +HOME = 0.0 +MAX_VELOCITY = 4 +MAX_ACCELERATION = 1000.0 +MIN_LIMIT = -40.0 +MAX_LIMIT = 40.0 +FERROR = 0.050 +MIN_FERROR = 0.010 +HOME_SEQUENCE = 0 + +[JOINT_2] +TYPE = LINEAR +HOME = 0.0 +MAX_VELOCITY = 4 +MAX_ACCELERATION = 1000.0 +MIN_LIMIT = -4.0 +MAX_LIMIT = 4.0 +FERROR = 0.050 +MIN_FERROR = 0.010 +HOME_SEQUENCE = 0 diff --git a/tests/halui/machine-state/test-ui.py b/tests/halui/machine-state/test-ui.py new file mode 100755 index 00000000000..e2d00e1300f --- /dev/null +++ b/tests/halui/machine-state/test-ui.py @@ -0,0 +1,188 @@ +#!/usr/bin/env python3 +"""halui: estop, machine power, task mode and motion mode. + +Pins: estop.activate, estop.reset, estop.is-activated, + machine.on, machine.off, machine.is-on, machine.units-per-mm, + mode.manual, mode.auto, mode.mdi, mode.teleop, mode.joint, + mode.is-manual, mode.is-auto, mode.is-mdi, mode.is-teleop, mode.is-joint +""" + +import os +import sys + +sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', '_lib')) +from halui_test import run, INCH_PER_MM # noqa: E402 + +import linuxcnc as L # noqa: E402 + +# task has no distinct OFF state: it reports ESTOP_RESET when the machine is +# neither estopped nor enabled (emctask.cc, emcTaskSetState) +POWERED_OFF = L.STATE_ESTOP_RESET + +MODE_PINS = {L.MODE_MANUAL: 'mode.is-manual', + L.MODE_AUTO: 'mode.is-auto', + L.MODE_MDI: 'mode.is-mdi'} + + +def startup_status(h): + h.expect('task starts in ESTOP', lambda: h.stat.task_state == L.STATE_ESTOP) + h.expect_pin('estop.is-activated reflects startup ESTOP', 'estop.is-activated', True) + h.expect_pin('machine.is-on is false at startup', 'machine.is-on', False) + # linear units are units per mm; this is an inch machine + h.expect_pin('machine.units-per-mm is published once task is up', + 'machine.units-per-mm', INCH_PER_MM, tol=1e-9) + + +def estop_and_power(h): + h.pulse('estop.reset') + h.expect('estop.reset -> task ESTOP_RESET', + lambda: h.stat.task_state == L.STATE_ESTOP_RESET) + h.expect_pin('estop.is-activated clears on reset', 'estop.is-activated', False) + h.expect_pin('machine.is-on stays false after reset', 'machine.is-on', False) + + h.pulse('machine.on') + h.expect('machine.on -> task ON', lambda: h.stat.task_state == L.STATE_ON) + h.expect_pin('machine.is-on sets', 'machine.is-on', True) + + h.pulse('machine.off') + h.expect('machine.off powers down (task reads back ESTOP_RESET)', + lambda: h.stat.task_state == POWERED_OFF) + h.expect_pin('machine.is-on clears on OFF', 'machine.is-on', False) + h.expect_pin('estop.is-activated stays clear on OFF', 'estop.is-activated', False) + + h.pulse('machine.on') + h.expect('machine.on from OFF -> task ON', lambda: h.stat.task_state == L.STATE_ON) + + h.pulse('estop.activate') + h.expect('estop.activate from ON -> task ESTOP', lambda: h.stat.task_state == L.STATE_ESTOP) + h.expect_pin('estop.is-activated sets', 'estop.is-activated', True) + h.expect_pin('machine.is-on clears on ESTOP', 'machine.is-on', False) + + +def power_on_refused_in_estop(h): + # task refuses ON straight from ESTOP; halui passes the request on and + # does not try to work around it + h.machine_estop() + h.pulse('machine.on') + h.expect_steady('machine.on while in ESTOP is refused by task', + lambda: h.stat.task_state == L.STATE_ESTOP) + h.expect_pin('machine.is-on stays false', 'machine.is-on', False) + + +def inputs_are_edge_triggered(h): + h.machine_estop() + h.nml_state(L.STATE_ESTOP_RESET) + h.set('machine.on', 1) + h.expect('rising edge on machine.on powers on', lambda: h.stat.task_state == L.STATE_ON) + h.nml_state(L.STATE_OFF) + h.expect_steady('a held machine.on does not power on again', + lambda: h.stat.task_state == POWERED_OFF, duration=0.6) + h.set('machine.on', 0) + h.expect_steady('the falling edge of machine.on does nothing', + lambda: h.stat.task_state == POWERED_OFF, duration=0.4) + + h.nml_state(L.STATE_ON) + h.set('estop.activate', 1) + h.expect('rising edge on estop.activate estops', lambda: h.stat.task_state == L.STATE_ESTOP) + h.nml_state(L.STATE_ESTOP_RESET) + h.expect_steady('a held estop.activate does not estop again', + lambda: h.stat.task_state == L.STATE_ESTOP_RESET, duration=0.6) + h.set('estop.activate', 0) + + +def status_follows_other_clients(h): + # output pins mirror task state no matter who changed it + h.machine_estop() + h.expect_pin('estop.is-activated follows an NML estop', 'estop.is-activated', True) + h.machine_on() + h.expect_pin('machine.is-on follows an NML power-on', 'machine.is-on', True) + h.expect_pin('estop.is-activated follows an NML reset', 'estop.is-activated', False) + + +def expect_task_mode_pins(h, want, why): + for mode, pin in MODE_PINS.items(): + h.expect_pin('%s is %s %s' % (pin, mode == want, why), pin, mode == want) + + +def task_modes(h): + h.machine_on() + h.nml_mode(L.MODE_MANUAL) + for request, mode, label in (('mode.mdi', L.MODE_MDI, 'MDI'), + ('mode.auto', L.MODE_AUTO, 'AUTO'), + ('mode.manual', L.MODE_MANUAL, 'MANUAL')): + h.pulse(request) + h.expect('%s -> task %s' % (request, label), lambda m=mode: h.stat.task_mode == m) + expect_task_mode_pins(h, mode, 'after ' + request) + + # asking for the mode task is already in sends nothing at all + for request, mode in (('mode.manual', L.MODE_MANUAL), + ('mode.auto', L.MODE_AUTO), + ('mode.mdi', L.MODE_MDI)): + h.nml_mode(mode) + h.settle(0.1) + serial = h.poll().echo_serial_number + h.pulse(request) + h.settle(0.3) + h.check('%s while already in that mode sends no command' % request, + h.poll().echo_serial_number == serial, + 'echo_serial_number %d -> %d' % (serial, h.stat.echo_serial_number)) + + # status pins follow a mode change made by another client + h.nml_mode(L.MODE_AUTO) + expect_task_mode_pins(h, L.MODE_AUTO, 'after an NML mode change') + h.nml_mode(L.MODE_MANUAL) + + +def task_mode_while_not_on(h): + for state, label in ((L.STATE_ESTOP, 'ESTOP'), (L.STATE_OFF, 'OFF')): + if state == L.STATE_ESTOP: + h.machine_estop() + else: + h.machine_on() + h.nml_state(L.STATE_OFF) + h.nml_mode(L.MODE_MANUAL) + h.pulse('mode.mdi') + h.expect('mode.mdi is accepted while in %s' % label, + lambda: h.stat.task_mode == L.MODE_MDI) + h.pulse('mode.manual') + h.expect('mode.manual is accepted while in %s' % label, + lambda: h.stat.task_mode == L.MODE_MANUAL) + + +def motion_modes(h): + h.machine_on() + h.nml_mode(L.MODE_MANUAL) + h.nml_home_all() + + h.pulse('mode.teleop') + h.expect('mode.teleop -> motion TELEOP', lambda: h.stat.motion_mode == L.TRAJ_MODE_TELEOP) + h.expect_pin('mode.is-teleop sets', 'mode.is-teleop', True) + h.expect_pin('mode.is-joint clears in teleop', 'mode.is-joint', False) + + h.pulse('mode.joint') + h.expect('mode.joint -> motion FREE', lambda: h.stat.motion_mode == L.TRAJ_MODE_FREE) + h.expect_pin('mode.is-joint sets', 'mode.is-joint', True) + h.expect_pin('mode.is-teleop clears in joint mode', 'mode.is-teleop', False) + + # in MDI, motion is in coordinated mode: neither teleop nor joint + h.nml_mode(L.MODE_MDI) + h.expect('MDI puts motion in COORD', lambda: h.stat.motion_mode == L.TRAJ_MODE_COORD) + h.expect_pin('mode.is-joint is false in COORD', 'mode.is-joint', False) + h.expect_pin('mode.is-teleop is false in COORD', 'mode.is-teleop', False) + + # status follows another client switching to teleop + h.nml_mode(L.MODE_MANUAL) + h.nml_teleop(1) + h.expect_pin('mode.is-teleop follows an NML teleop enable', 'mode.is-teleop', True) + h.nml_teleop(0) + h.expect_pin('mode.is-joint follows an NML teleop disable', 'mode.is-joint', True) + + +run(startup_status, + estop_and_power, + power_on_refused_in_estop, + inputs_are_edge_triggered, + status_follows_other_clients, + task_modes, + task_mode_while_not_on, + motion_modes) diff --git a/tests/halui/machine-state/test.sh b/tests/halui/machine-state/test.sh new file mode 100755 index 00000000000..fd122f82169 --- /dev/null +++ b/tests/halui/machine-state/test.sh @@ -0,0 +1,2 @@ +#!/bin/bash +exec ../_lib/launch.sh diff --git a/tests/halui/mdi-commands/checkresult b/tests/halui/mdi-commands/checkresult new file mode 100755 index 00000000000..73e90a43dfc --- /dev/null +++ b/tests/halui/mdi-commands/checkresult @@ -0,0 +1,2 @@ +#!/bin/sh +exit 0 # test failure is indicated by test.sh exit value diff --git a/tests/halui/mdi-commands/halui.ini b/tests/halui/mdi-commands/halui.ini new file mode 100644 index 00000000000..b7ddfc5ab00 --- /dev/null +++ b/tests/halui/mdi-commands/halui.ini @@ -0,0 +1,102 @@ +# Test machine shared by the halui pin tests: XYZ trivkins, one spindle, +# a tool table, a home sequence (so halui.home-all exists) and two MDI +# commands (so halui.halui-mdi-is-running and halui.mdi-command-NN exist). + +[EMC] +VERSION = 1.1 +DEBUG = 0 + +[DISPLAY] +DISPLAY = ./test-ui.py +MAX_FEED_OVERRIDE = 1.5 +MIN_SPINDLE_OVERRIDE = 0.5 +MAX_SPINDLE_OVERRIDE = 1.2 + +[TASK] +TASK = milltask +CYCLE_TIME = 0.001 + +[RS274NGC] +PARAMETER_FILE = sim.var + +[EMCMOT] +EMCMOT = motmod +COMM_TIMEOUT = 4.0 +BASE_PERIOD = 0 +SERVO_PERIOD = 1000000 + +[EMCIO] +TOOL_TABLE = tool.tbl + +[HAL] +HALFILE = LIB:core_sim.hal + +[HALUI] +MDI_COMMAND = G20 G90 G0 X1 +MDI_COMMAND = G20 G90 G0 X0 +MDI_COMMAND = G20 G90 G1 X2 F60 +MDI_COMMAND = G20 G90 G1 X0 F60 + +[TRAJ] +COORDINATES = X Y Z +LINEAR_UNITS = inch +ANGULAR_UNITS = degree +DEFAULT_LINEAR_VELOCITY = 1.2 +MAX_LINEAR_VELOCITY = 4 +SPINDLES = 1 +NO_FORCE_HOMING = 1 + +[KINS] +KINEMATICS = trivkins +JOINTS = 3 + +[AXIS_X] +MIN_LIMIT = -40.0 +MAX_LIMIT = 40.0 +MAX_VELOCITY = 4 +MAX_ACCELERATION = 1000.0 + +[AXIS_Y] +MIN_LIMIT = -40.0 +MAX_LIMIT = 40.0 +MAX_VELOCITY = 4 +MAX_ACCELERATION = 1000.0 + +[AXIS_Z] +MIN_LIMIT = -4.0 +MAX_LIMIT = 4.0 +MAX_VELOCITY = 4 +MAX_ACCELERATION = 1000.0 + +[JOINT_0] +TYPE = LINEAR +HOME = 0.0 +MAX_VELOCITY = 4 +MAX_ACCELERATION = 1000.0 +MIN_LIMIT = -40.0 +MAX_LIMIT = 40.0 +FERROR = 0.050 +MIN_FERROR = 0.010 +HOME_SEQUENCE = 0 + +[JOINT_1] +TYPE = LINEAR +HOME = 0.0 +MAX_VELOCITY = 4 +MAX_ACCELERATION = 1000.0 +MIN_LIMIT = -40.0 +MAX_LIMIT = 40.0 +FERROR = 0.050 +MIN_FERROR = 0.010 +HOME_SEQUENCE = 0 + +[JOINT_2] +TYPE = LINEAR +HOME = 0.0 +MAX_VELOCITY = 4 +MAX_ACCELERATION = 1000.0 +MIN_LIMIT = -4.0 +MAX_LIMIT = 4.0 +FERROR = 0.050 +MIN_FERROR = 0.010 +HOME_SEQUENCE = 0 diff --git a/tests/halui/mdi-commands/long.ngc b/tests/halui/mdi-commands/long.ngc new file mode 100644 index 00000000000..cac45d6b3e7 --- /dev/null +++ b/tests/halui/mdi-commands/long.ngc @@ -0,0 +1,5 @@ +(six seconds out along X, six back: long enough to pause, resume and stop) +G20 G90 G17 +G1 X3 F30 +G1 X0 F30 +M2 diff --git a/tests/halui/mdi-commands/test-ui.py b/tests/halui/mdi-commands/test-ui.py new file mode 100755 index 00000000000..89516f9c54b --- /dev/null +++ b/tests/halui/mdi-commands/test-ui.py @@ -0,0 +1,182 @@ +#!/usr/bin/env python3 +"""halui: [HALUI]MDI_COMMAND buttons. + +Pins: mdi-command-NN, halui-mdi-is-running + +halui switches task to MDI, runs the command, and switches back to the mode +it found once task reports DONE. tests/halui/mdi covers the basic round trip; +this covers the running flag, queueing, and the paths where task refuses. + +MDI_COMMAND 00: G0 X1 01: G0 X0 + 02: G1 X2 F60 03: G1 X0 F60 (two seconds each) +""" + +import os +import sys +import time + +sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', '_lib')) +from halui_test import run, close # noqa: E402 + +import linuxcnc as L # noqa: E402 + +MODES = {L.MODE_MANUAL: 'MANUAL', L.MODE_AUTO: 'AUTO', L.MODE_MDI: 'MDI'} + + +def x(h): + return h.stat.actual_position[0] + + +def expect_x(h, want, why, timeout=10): + return h.expect('X reaches %g %s' % (want, why), + lambda: close(x(h), want, 1e-4) and h.stat.inpos, timeout, + detail=lambda: 'X=%.4f' % x(h)) + + +def expect_mode(h, mode, why, timeout=5): + return h.expect('task is back in %s %s' % (MODES[mode], why), + lambda: h.stat.task_mode == mode, timeout, + detail=lambda: 'mode=%s' % MODES.get(h.stat.task_mode, h.stat.task_mode)) + + +def at_x0(h, mode): + h.machine_on() + h.nml_mdi('G20 G90 G0 X0 Y0 Z0') + h.nml_mode(mode) + + +def pins(h): + for n in range(4): + h.check('mdi-command-%02d exists' % n, h.has('mdi-command-%02d' % n)) + h.check('there is no pin beyond the configured commands', not h.has('mdi-command-04')) + h.check('halui-mdi-is-running exists because MDI commands are configured', + h.has('halui-mdi-is-running')) + h.expect_pin('halui-mdi-is-running is false at startup', 'halui-mdi-is-running', False) + + +def round_trip_from_each_mode(h): + for mode in (L.MODE_MANUAL, L.MODE_AUTO, L.MODE_MDI): + at_x0(h, mode) + h.pulse('mdi-command-00') + expect_x(h, 1, 'after mdi-command-00 from %s' % MODES[mode]) + expect_mode(h, mode, 'after the command') + h.expect_pin('halui-mdi-is-running clears after the command from %s' % MODES[mode], + 'halui-mdi-is-running', False) + + +def running_flag(h): + at_x0(h, L.MODE_MANUAL) + h.pulse('mdi-command-02') + h.expect('task switches to MDI for the command', lambda: h.stat.task_mode == L.MODE_MDI) + h.expect_pin('halui-mdi-is-running sets while the command runs', 'halui-mdi-is-running', True) + h.expect('the command is moving X', lambda: 0.2 < x(h) < 1.8) + h.check('task is still in MDI mid-command', h.stat.task_mode == L.MODE_MDI) + expect_x(h, 2, 'at the end of mdi-command-02') + expect_mode(h, L.MODE_MANUAL, 'once the command is done') + h.expect_pin('halui-mdi-is-running clears when it is done', 'halui-mdi-is-running', False) + + +def queued_commands(h): + at_x0(h, L.MODE_MANUAL) + h.pulse('mdi-command-02') + h.expect('first command under way', lambda: x(h) > 0.2) + h.pulse('mdi-command-03') + furthest = 0.0 + end = time.time() + 10 + while time.time() < end: + h.poll() + furthest = max(furthest, x(h)) + if h.stat.task_mode != L.MODE_MDI: + break + time.sleep(0.01) + h.check('both queued commands ran in order (X went to 2 and back to 0)', + furthest > 1.99 and close(x(h), 0, 1e-4), + 'furthest X=%.4f, final X=%.4f' % (furthest, x(h))) + h.check('the mode is restored only after the whole queue is done', + close(x(h), 0, 1e-4), 'mode left MDI at X=%.4f' % x(h)) + expect_mode(h, L.MODE_MANUAL, 'after the queue') + h.expect_pin('halui-mdi-is-running clears after the queue', 'halui-mdi-is-running', False) + + +def edge_only(h): + at_x0(h, L.MODE_MANUAL) + h.set('mdi-command-00', 1) + expect_x(h, 1, 'while mdi-command-00 is held') + expect_mode(h, L.MODE_MANUAL, 'while it is still held') + h.nml_mdi('G0 X0') + h.nml_mode(L.MODE_MANUAL) + h.expect_steady('a held mdi-command-00 does not run again', + lambda: close(x(h), 0, 1e-4) and h.stat.task_mode == L.MODE_MANUAL, + duration=0.8) + h.set('mdi-command-00', 0) + + +def refused_by_task(h): + # In ESTOP task accepts the switch to MDI but refuses the command itself. + at_x0(h, L.MODE_MANUAL) + h.machine_estop() + h.nml_mode(L.MODE_MANUAL) + h.drain_errors() + h.pulse('mdi-command-00') + h.settle(1.0) + s = h.poll() + h.log('mdi-command-00 in ESTOP: mode=%s status=%d X=%.4f is-running=%s errors=%r' + % (MODES.get(s.task_mode), s.state, x(h), h.get('halui-mdi-is-running'), + h.drain_errors())) + h.check('the command does not move anything in ESTOP', close(x(h), 0, 1e-4)) + h.check('task reports the refused command as an error', s.state == L.RCS_ERROR, + 'status=%d' % s.state) + # halui restores the old mode only on RCS DONE (modify_hal_pins). The + # refused command leaves task in ERROR, so nothing is restored and the + # running flag never drops. + h.known_bug('task is left in MDI after an MDI button is refused', + h.stays(lambda: h.stat.task_mode == L.MODE_MDI, 1.0), + 'halui only restores the previous mode when task status is DONE; ' + 'on ERROR it waits forever. Should be back in MANUAL') + h.known_bug('halui-mdi-is-running stays true after the refused command', + h.stays(lambda: h.get('halui-mdi-is-running'), 1.0), + 'halui_sent_mdi is cleared only on DONE; should be false') + + # The stale state resolves on the next command that finishes with DONE, + # whatever it is. Here that is powering the machine on, which therefore + # also switches task out of MDI -- long after the button press. + h.machine_on() + h.known_bug('turning the machine on later switches task back to MANUAL', + h.wait_for(lambda: h.stat.task_mode == L.MODE_MANUAL), + 'the delayed restore from the refused MDI button fires on the next DONE, ' + 'from an unrelated command') + h.expect_pin('halui-mdi-is-running clears after that', 'halui-mdi-is-running', False) + + +def while_program_runs(h): + # task refuses the switch to MDI while a program runs + at_x0(h, L.MODE_AUTO) + here = os.path.dirname(os.path.abspath(__file__)) + h.cmd.program_open(os.path.join(here, 'long.ngc')) + h.cmd.wait_complete() + h.cmd.auto(L.AUTO_RUN, 0) + h.expect('the program is running', lambda: x(h) > 0.2) + h.pulse('mdi-command-00') + h.settle(0.5) + running_flag = h.get('halui-mdi-is-running') + h.log('mdi-command-00 while a program runs: mode=%s is-running=%s' + % (MODES.get(h.poll().task_mode), running_flag)) + h.check('task stays in AUTO', h.stat.task_mode == L.MODE_AUTO) + h.known_bug('halui-mdi-is-running is true although no MDI command was sent', + running_flag, + 'sendMdiCommand() sets halui_sent_mdi before task has refused the ' + 'switch to MDI; should stay false') + h.check('the program keeps running', h.stat.interp_state != L.INTERP_IDLE) + h.nml_abort() + h.expect_pin('halui-mdi-is-running is clear once the program is gone', + 'halui-mdi-is-running', False) + h.check('task is still in AUTO afterwards', h.poll().task_mode == L.MODE_AUTO) + + +run(pins, + round_trip_from_each_mode, + running_flag, + queued_commands, + edge_only, + refused_by_task, + while_program_runs) diff --git a/tests/halui/mdi-commands/test.sh b/tests/halui/mdi-commands/test.sh new file mode 100755 index 00000000000..fd122f82169 --- /dev/null +++ b/tests/halui/mdi-commands/test.sh @@ -0,0 +1,2 @@ +#!/bin/bash +exec ../_lib/launch.sh diff --git a/tests/halui/overrides/checkresult b/tests/halui/overrides/checkresult new file mode 100755 index 00000000000..73e90a43dfc --- /dev/null +++ b/tests/halui/overrides/checkresult @@ -0,0 +1,2 @@ +#!/bin/sh +exit 0 # test failure is indicated by test.sh exit value diff --git a/tests/halui/overrides/halui.ini b/tests/halui/overrides/halui.ini new file mode 100644 index 00000000000..4d21b0429ec --- /dev/null +++ b/tests/halui/overrides/halui.ini @@ -0,0 +1,100 @@ +# Test machine shared by the halui pin tests: XYZ trivkins, one spindle, +# a tool table, a home sequence (so halui.home-all exists) and two MDI +# commands (so halui.halui-mdi-is-running and halui.mdi-command-NN exist). + +[EMC] +VERSION = 1.1 +DEBUG = 0 + +[DISPLAY] +DISPLAY = ./test-ui.py +MAX_FEED_OVERRIDE = 1.5 +MIN_SPINDLE_OVERRIDE = 0.5 +MAX_SPINDLE_OVERRIDE = 1.2 + +[TASK] +TASK = milltask +CYCLE_TIME = 0.001 + +[RS274NGC] +PARAMETER_FILE = sim.var + +[EMCMOT] +EMCMOT = motmod +COMM_TIMEOUT = 4.0 +BASE_PERIOD = 0 +SERVO_PERIOD = 1000000 + +[EMCIO] +TOOL_TABLE = tool.tbl + +[HAL] +HALFILE = LIB:core_sim.hal + +[HALUI] +MDI_COMMAND = G0 X1 Y0 Z0 +MDI_COMMAND = G0 X0 Y0 Z0 + +[TRAJ] +COORDINATES = X Y Z +LINEAR_UNITS = inch +ANGULAR_UNITS = degree +DEFAULT_LINEAR_VELOCITY = 1.2 +MAX_LINEAR_VELOCITY = 4 +SPINDLES = 1 +NO_FORCE_HOMING = 1 + +[KINS] +KINEMATICS = trivkins +JOINTS = 3 + +[AXIS_X] +MIN_LIMIT = -40.0 +MAX_LIMIT = 40.0 +MAX_VELOCITY = 4 +MAX_ACCELERATION = 1000.0 + +[AXIS_Y] +MIN_LIMIT = -40.0 +MAX_LIMIT = 40.0 +MAX_VELOCITY = 4 +MAX_ACCELERATION = 1000.0 + +[AXIS_Z] +MIN_LIMIT = -4.0 +MAX_LIMIT = 4.0 +MAX_VELOCITY = 4 +MAX_ACCELERATION = 1000.0 + +[JOINT_0] +TYPE = LINEAR +HOME = 0.0 +MAX_VELOCITY = 4 +MAX_ACCELERATION = 1000.0 +MIN_LIMIT = -40.0 +MAX_LIMIT = 40.0 +FERROR = 0.050 +MIN_FERROR = 0.010 +HOME_SEQUENCE = 0 + +[JOINT_1] +TYPE = LINEAR +HOME = 0.0 +MAX_VELOCITY = 4 +MAX_ACCELERATION = 1000.0 +MIN_LIMIT = -40.0 +MAX_LIMIT = 40.0 +FERROR = 0.050 +MIN_FERROR = 0.010 +HOME_SEQUENCE = 0 + +[JOINT_2] +TYPE = LINEAR +HOME = 0.0 +MAX_VELOCITY = 4 +MAX_ACCELERATION = 1000.0 +MIN_LIMIT = -4.0 +MAX_LIMIT = 4.0 +FERROR = 0.050 +MIN_FERROR = 0.010 +HOME_SEQUENCE = 0 diff --git a/tests/halui/overrides/test-ui.py b/tests/halui/overrides/test-ui.py new file mode 100755 index 00000000000..25840468ee0 --- /dev/null +++ b/tests/halui/overrides/test-ui.py @@ -0,0 +1,230 @@ +#!/usr/bin/env python3 +"""halui: feed, rapid, spindle and max-velocity overrides. + +For each override: counts (relative and direct-value), count-enable, scale, +increase, decrease, reset, value -- and the clamping halui applies. + +Limits in halui.ini: [DISPLAY]MAX_FEED_OVERRIDE = 1.5, +MIN_SPINDLE_OVERRIDE = 0.5, MAX_SPINDLE_OVERRIDE = 1.2, +[TRAJ]MAX_LINEAR_VELOCITY = 4. +""" + +import os +import sys + +sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', '_lib')) +from halui_test import run, close # noqa: E402 + +import linuxcnc as L # noqa: E402 + + +class Model: + """What halui should ask for: last value +/- steps, clamped.""" + + def __init__(self, value, lo, hi): + self.value, self.lo, self.hi, self.counts = value, lo, hi, 0 + + def clamp(self, v): + return max(self.lo, min(self.hi, v)) + + def relative(self, counts, scale): + self.value = self.clamp(self.value + (counts - self.counts) * scale) + self.counts = counts + + def direct(self, counts, scale): + self.value = self.clamp(counts * scale) + self.counts = counts + + def ignored(self, counts): + self.counts = counts + + def set(self, v): + self.value = self.clamp(v) + + +def exercise(h, label, pfx, read, lo, hi, has_reset=True): + def P(s): + return pfx + '.' + s + + m = Model(read(h.poll()), lo, hi) + + def expect(why): + # When a step leaves the value unchanged (already at a limit) the + # check below passes at once, so give halui time to sample the input + # before the next one arrives -- otherwise two steps look like one. + h.settle() + want = m.value + h.expect('%s is %.3f %s' % (label, want, why), + lambda: close(read(h.stat), want, 1e-6), + detail=lambda: 'task has %.4f' % read(h.stat)) + h.expect_pin('%s.value is %.3f %s' % (pfx, want, why), P('value'), want, tol=1e-6) + + h.check('%s.scale defaults to 0.1' % pfx, close(h.default(P('scale')), 0.1), + 'default %r' % h.default(P('scale'))) + h.check('%s.count-enable defaults to on' % pfx, h.default(P('count-enable')) is True, + 'default %r' % h.default(P('count-enable'))) + expect('at startup') + + scale = 0.1 + for c in (1, 4, 20, 19, -40, -38): + h.set(P('counts'), c) + m.relative(c, scale) + expect('after counts -> %d (relative)' % c) + + h.set(P('count-enable'), 0) + h.set(P('counts'), -30) + m.ignored(-30) + h.expect_steady('%s ignores counts while count-enable is off' % pfx, + lambda: close(read(h.stat), m.value, 1e-6)) + h.set(P('count-enable'), 1) + h.set(P('counts'), -29) + m.relative(-29, scale) + expect('after re-enabling: one count, no jump from the ignored ones') + + h.pulse(P('increase')) + m.set(m.value + scale) + expect('after increase') + h.pulse(P('decrease')) + m.set(m.value - scale) + expect('after decrease') + + h.set(P('increase'), 1) + h.settle(0.3) + m.set(m.value + scale) + expect('while increase is held (one step per edge)') + h.set(P('increase'), 0) + h.settle() + + scale = 0.25 + h.set(P('scale'), scale) + h.pulse(P('increase')) + m.set(m.value + scale) + expect('after increase with scale 0.25') + for _ in range(8): + h.pulse(P('increase')) + m.set(m.value + scale) + expect('after increasing past the upper limit') + for _ in range(12): + h.pulse(P('decrease')) + m.set(m.value - scale) + expect('after decreasing past the lower limit') + + if has_reset: + h.pulse(P('reset')) + m.set(1.0) + expect('after reset') + else: + h.check('%s has no reset pin' % pfx, not h.has(P('reset'))) + + scale = 0.1 + h.set(P('scale'), scale) + h.set(P('direct-value'), 1) + for c in (7, 30, -1, 9): + h.set(P('counts'), c) + m.direct(c, scale) + expect('after counts -> %d (direct-value)' % c) + h.set(P('direct-value'), 0) + h.set(P('counts'), 10) + m.relative(10, scale) + expect('after counts -> 10 (relative again)') + return m + + +def feed_override(h): + h.machine_on() + exercise(h, 'task feed override', 'feed-override', lambda s: s.feedrate, 0.0, 1.5) + h.cmd.feedrate(0.7) + h.expect_pin('feed-override.value follows an NML change', 'feed-override.value', 0.7) + + +def rapid_override(h): + h.machine_on() + # halui hard-codes the rapid override ceiling at 1.0 + exercise(h, 'task rapid override', 'rapid-override', lambda s: s.rapidrate, 0.0, 1.0) + h.cmd.rapidrate(0.3) + h.expect_pin('rapid-override.value follows an NML change', 'rapid-override.value', 0.3) + + +def spindle_override(h): + h.machine_on() + exercise(h, 'task spindle 0 override', 'spindle.0.override', + lambda s: s.spindle[0]['override'], 0.5, 1.2) + h.cmd.spindleoverride(0.8, 0) + h.expect_pin('spindle.0.override.value follows an NML change', + 'spindle.0.override.value', 0.8) + + +def max_velocity(h): + h.machine_on() + start = h.poll().max_velocity + h.check('task starts at [TRAJ]MAX_LINEAR_VELOCITY', close(start, 4.0), 'max_velocity=%.3f' % start) + h.expect_pin('max-velocity.value shows it', 'max-velocity.value', 4.0) + h.check('max-velocity.scale defaults to 0 (halui never initialises it)', + close(h.default('max-velocity.scale'), 0.0), 'default %r' % h.default('max-velocity.scale')) + h.check('max-velocity.count-enable defaults to on', h.default('max-velocity.count-enable') is True) + + h.set('max-velocity.scale', 0.5) + h.pulse('max-velocity.decrease') + h.known_bug('max-velocity.decrease from 4.0 lands on 1.0 instead of 3.5', + h.wait_for(lambda: close(h.stat.max_velocity, 1.0)), + 'every request is clamped to 1.0: iniLoad() no longer reads ' + '[TRAJ]MAX_LINEAR_VELOCITY into maxMaxVelocity since 2f57090adb ' + '(new ini parser); intended ceiling here is 4.0') + h.expect_pin('max-velocity.value follows the clamped value', 'max-velocity.value', 1.0) + + # inside [0, 1.0] the override behaves as intended + m = Model(1.0, 0.0, 1.0) + + def expect(why): + h.settle() + want = m.value + h.expect('task max velocity is %.3f %s' % (want, why), + lambda: close(h.stat.max_velocity, want, 1e-6), + detail=lambda: 'task has %.4f' % h.stat.max_velocity) + h.expect_pin('max-velocity.value is %.3f %s' % (want, why), 'max-velocity.value', want) + + h.pulse('max-velocity.decrease') + m.set(0.5) + expect('after decrease') + h.pulse('max-velocity.increase') + m.set(1.0) + expect('after increase') + h.pulse('max-velocity.increase') + expect('after increasing past the (buggy) 1.0 ceiling') + for c in (-1, -5, -3): + h.set('max-velocity.counts', c) + m.relative(c, 0.5) + expect('after counts -> %d (relative)' % c) + + h.set('max-velocity.count-enable', 0) + h.set('max-velocity.counts', 5) + m.ignored(5) + h.expect_steady('max-velocity ignores counts while count-enable is off', + lambda: close(h.stat.max_velocity, m.value, 1e-6)) + h.set('max-velocity.count-enable', 1) + + h.set('max-velocity.direct-value', 1) + h.set('max-velocity.counts', 1) + m.direct(1, 0.5) + expect('after counts -> 1 (direct-value)') + h.set('max-velocity.counts', 6) + h.known_bug('max-velocity direct-value 3.0 lands on 1.0', + h.wait_for(lambda: close(h.stat.max_velocity, 1.0)), + 'same maxMaxVelocity clamp; intended result is 3.0') + h.set('max-velocity.direct-value', 0) + h.check('max-velocity has no reset pin', not h.has('max-velocity.reset')) + + h.cmd.maxvel(2.5) + h.expect_pin('max-velocity.value follows an NML change', 'max-velocity.value', 2.5) + + +def not_on(h): + # overrides are immediate commands: task accepts them even when not ON + h.machine_estop() + h.cmd.feedrate(1.0) + h.cmd.wait_complete() + h.pulse('feed-override.decrease') + h.expect('feed override changes while in ESTOP', lambda: close(h.stat.feedrate, 0.9)) + + +run(feed_override, rapid_override, spindle_override, max_velocity, not_on) diff --git a/tests/halui/overrides/test.sh b/tests/halui/overrides/test.sh new file mode 100755 index 00000000000..fd122f82169 --- /dev/null +++ b/tests/halui/overrides/test.sh @@ -0,0 +1,2 @@ +#!/bin/bash +exec ../_lib/launch.sh diff --git a/tests/halui/program/block-delete.ngc b/tests/halui/program/block-delete.ngc new file mode 100644 index 00000000000..ccec84254ac --- /dev/null +++ b/tests/halui/program/block-delete.ngc @@ -0,0 +1,4 @@ +G20 G90 +G0 Z0 +/G0 Z-1 +M2 diff --git a/tests/halui/program/checkresult b/tests/halui/program/checkresult new file mode 100755 index 00000000000..73e90a43dfc --- /dev/null +++ b/tests/halui/program/checkresult @@ -0,0 +1,2 @@ +#!/bin/sh +exit 0 # test failure is indicated by test.sh exit value diff --git a/tests/halui/program/halui.ini b/tests/halui/program/halui.ini new file mode 100644 index 00000000000..4d21b0429ec --- /dev/null +++ b/tests/halui/program/halui.ini @@ -0,0 +1,100 @@ +# Test machine shared by the halui pin tests: XYZ trivkins, one spindle, +# a tool table, a home sequence (so halui.home-all exists) and two MDI +# commands (so halui.halui-mdi-is-running and halui.mdi-command-NN exist). + +[EMC] +VERSION = 1.1 +DEBUG = 0 + +[DISPLAY] +DISPLAY = ./test-ui.py +MAX_FEED_OVERRIDE = 1.5 +MIN_SPINDLE_OVERRIDE = 0.5 +MAX_SPINDLE_OVERRIDE = 1.2 + +[TASK] +TASK = milltask +CYCLE_TIME = 0.001 + +[RS274NGC] +PARAMETER_FILE = sim.var + +[EMCMOT] +EMCMOT = motmod +COMM_TIMEOUT = 4.0 +BASE_PERIOD = 0 +SERVO_PERIOD = 1000000 + +[EMCIO] +TOOL_TABLE = tool.tbl + +[HAL] +HALFILE = LIB:core_sim.hal + +[HALUI] +MDI_COMMAND = G0 X1 Y0 Z0 +MDI_COMMAND = G0 X0 Y0 Z0 + +[TRAJ] +COORDINATES = X Y Z +LINEAR_UNITS = inch +ANGULAR_UNITS = degree +DEFAULT_LINEAR_VELOCITY = 1.2 +MAX_LINEAR_VELOCITY = 4 +SPINDLES = 1 +NO_FORCE_HOMING = 1 + +[KINS] +KINEMATICS = trivkins +JOINTS = 3 + +[AXIS_X] +MIN_LIMIT = -40.0 +MAX_LIMIT = 40.0 +MAX_VELOCITY = 4 +MAX_ACCELERATION = 1000.0 + +[AXIS_Y] +MIN_LIMIT = -40.0 +MAX_LIMIT = 40.0 +MAX_VELOCITY = 4 +MAX_ACCELERATION = 1000.0 + +[AXIS_Z] +MIN_LIMIT = -4.0 +MAX_LIMIT = 4.0 +MAX_VELOCITY = 4 +MAX_ACCELERATION = 1000.0 + +[JOINT_0] +TYPE = LINEAR +HOME = 0.0 +MAX_VELOCITY = 4 +MAX_ACCELERATION = 1000.0 +MIN_LIMIT = -40.0 +MAX_LIMIT = 40.0 +FERROR = 0.050 +MIN_FERROR = 0.010 +HOME_SEQUENCE = 0 + +[JOINT_1] +TYPE = LINEAR +HOME = 0.0 +MAX_VELOCITY = 4 +MAX_ACCELERATION = 1000.0 +MIN_LIMIT = -40.0 +MAX_LIMIT = 40.0 +FERROR = 0.050 +MIN_FERROR = 0.010 +HOME_SEQUENCE = 0 + +[JOINT_2] +TYPE = LINEAR +HOME = 0.0 +MAX_VELOCITY = 4 +MAX_ACCELERATION = 1000.0 +MIN_LIMIT = -4.0 +MAX_LIMIT = 4.0 +FERROR = 0.050 +MIN_FERROR = 0.010 +HOME_SEQUENCE = 0 diff --git a/tests/halui/program/long.ngc b/tests/halui/program/long.ngc new file mode 100644 index 00000000000..cac45d6b3e7 --- /dev/null +++ b/tests/halui/program/long.ngc @@ -0,0 +1,5 @@ +(six seconds out along X, six back: long enough to pause, resume and stop) +G20 G90 G17 +G1 X3 F30 +G1 X0 F30 +M2 diff --git a/tests/halui/program/optional-stop.ngc b/tests/halui/program/optional-stop.ngc new file mode 100644 index 00000000000..563612d0428 --- /dev/null +++ b/tests/halui/program/optional-stop.ngc @@ -0,0 +1,5 @@ +G20 G90 +G0 X0 +M1 +G0 X0.5 +M2 diff --git a/tests/halui/program/step.ngc b/tests/halui/program/step.ngc new file mode 100644 index 00000000000..111479bd529 --- /dev/null +++ b/tests/halui/program/step.ngc @@ -0,0 +1,5 @@ +(every line moves, so each step is visible as a change in X) +G20 G90 G0 X0.1 +G0 X0.2 +G0 X0.3 +M2 diff --git a/tests/halui/program/test-ui.py b/tests/halui/program/test-ui.py new file mode 100755 index 00000000000..dc5fe39abb6 --- /dev/null +++ b/tests/halui/program/test-ui.py @@ -0,0 +1,295 @@ +#!/usr/bin/env python3 +"""halui: program control and program status. + +Pins: program.run, program.pause, program.resume, program.step, program.stop, + program.optional-stop.on, program.optional-stop.off, + program.optional-stop.is-on, + program.block-delete.on, program.block-delete.off, + program.block-delete.is-on, + program.is-idle, program.is-running, program.is-paused, abort + +halui cannot open a program, so opening one is done over NML as setup. +""" + +import os +import sys +import time + +HERE = os.path.dirname(os.path.abspath(__file__)) +sys.path.insert(0, os.path.join(HERE, '..', '_lib')) +from halui_test import run, close # noqa: E402 + +import linuxcnc as L # noqa: E402 + + +def running(h): + return h.stat.interp_state in (L.INTERP_READING, L.INTERP_WAITING) + + +def paused(h): + return h.stat.interp_state == L.INTERP_PAUSED + + +def idle(h): + return h.stat.interp_state == L.INTERP_IDLE + + +def x(h): + return h.poll().actual_position[0] + + +def expect_program_pins(h, is_idle, is_running, is_paused, why): + h.expect_pin('program.is-idle is %s %s' % (is_idle, why), 'program.is-idle', is_idle) + h.expect_pin('program.is-running is %s %s' % (is_running, why), 'program.is-running', is_running) + h.expect_pin('program.is-paused is %s %s' % (is_paused, why), 'program.is-paused', is_paused) + + +def to_origin(h): + h.machine_on() + h.nml_mdi('G20 G90 G0 X0 Y0 Z0') + + +def open_program(h, name): + h.nml_mode(L.MODE_AUTO) + h.cmd.program_open(os.path.join(HERE, name)) + h.cmd.wait_complete() + if not h.wait_for(lambda: h.stat.file.endswith(name)): + raise RuntimeError('setup: could not open ' + name) + + +def nml_run(h): + # wait_complete() on a run only returns once the program has finished, + # so for a short program just wait for task to take the command + h.cmd.auto(L.AUTO_RUN, 0) + if not h.wait_for(lambda: h.stat.echo_serial_number >= h.cmd.serial): + raise RuntimeError('setup: task did not take the run command') + + +def expect_still(h, name): + h.settle(0.3) + a = x(h) + h.settle(0.4) + b = x(h) + return h.check(name, close(a, b, 1e-6), 'X %.5f -> %.5f' % (a, b)) + + +def run_without_a_program(h): + h.machine_on() + h.nml_mode(L.MODE_MANUAL) + h.check('no program is open at startup', h.poll().file == '', 'file=%r' % h.stat.file) + expect_program_pins(h, True, False, False, 'at startup') + serial = h.poll().echo_serial_number + h.pulse('program.run') + h.settle(0.3) + h.check('program.run with no program open sends nothing', + h.poll().echo_serial_number == serial, + 'echo_serial_number %d -> %d' % (serial, h.stat.echo_serial_number)) + h.check('program.run with no program open leaves task in MANUAL', + h.stat.task_mode == L.MODE_MANUAL, 'mode=%d' % h.stat.task_mode) + + +def run_pause_resume_stop(h): + to_origin(h) + open_program(h, 'long.ngc') + h.nml_mode(L.MODE_MANUAL) + + h.pulse('program.run') + h.expect('program.run switches task to AUTO by itself', + lambda: h.stat.task_mode == L.MODE_AUTO) + h.expect('program.run starts the program', lambda: running(h)) + h.expect('the program moves X', lambda: h.stat.actual_position[0] > 0.2) + expect_program_pins(h, False, True, False, 'while running') + + h.pulse('program.pause') + h.expect('program.pause pauses the program', lambda: paused(h)) + expect_program_pins(h, False, False, True, 'while paused') + expect_still(h, 'motion stops while paused') + + h.pulse('program.pause') + h.expect_steady('program.pause while paused keeps it paused', lambda: paused(h), duration=0.4) + + here = x(h) + h.pulse('program.resume') + h.expect('program.resume resumes the program', lambda: running(h)) + h.expect('motion continues after resume', lambda: h.stat.actual_position[0] > here + 0.05) + expect_program_pins(h, False, True, False, 'after resume') + + h.pulse('program.resume') + h.expect_steady('program.resume while running keeps it running', lambda: running(h), duration=0.4) + + h.pulse('program.stop') + h.expect('program.stop ends the program', lambda: idle(h)) + expect_program_pins(h, True, False, False, 'after program.stop') + expect_still(h, 'motion stops after program.stop') + + +def run_while_already_in_auto(h): + to_origin(h) + open_program(h, 'long.ngc') + h.pulse('program.run') + h.expect('program.run from AUTO starts the program', lambda: running(h)) + h.pulse('program.stop') + h.expect('program.stop ends it', lambda: idle(h)) + + +def pause_when_idle(h): + # task accepts a pause with a program open but not running, and reports + # the interpreter as PAUSED. That is task behaviour, not halui's; halui + # passes the request on and its status pins report what task says. + to_origin(h) + open_program(h, 'long.ngc') + h.pulse('program.pause') + h.expect('program.pause with nothing running puts task in PAUSED', lambda: paused(h)) + expect_program_pins(h, False, False, True, 'after a pause while idle') + h.pulse('program.stop') + h.expect('program.stop leaves that paused state', lambda: idle(h)) + expect_program_pins(h, True, False, False, 'after stopping it') + + +def abort_pin(h): + to_origin(h) + open_program(h, 'long.ngc') + nml_run(h) + h.expect('the program runs (started over NML)', lambda: h.stat.actual_position[0] > 0.2) + expect_program_pins(h, False, True, False, 'while a program started over NML runs') + h.pulse('abort') + h.expect('abort ends a running program', lambda: idle(h)) + expect_program_pins(h, True, False, False, 'after abort') + expect_still(h, 'motion stops after abort') + + # abort also stops a paused program + to_origin(h) + open_program(h, 'long.ngc') + nml_run(h) + h.cmd.auto(L.AUTO_PAUSE) + h.cmd.wait_complete() + h.wait_for(lambda: paused(h)) + h.pulse('abort') + h.expect('abort ends a paused program', lambda: idle(h)) + expect_program_pins(h, True, False, False, 'after aborting a paused program') + + # and an MDI move + to_origin(h) + h.nml_mode(L.MODE_MDI) + h.cmd.mdi('G1 X3 F30') + h.expect('an MDI move is under way', lambda: h.stat.actual_position[0] > 0.1) + h.pulse('abort') + h.expect('abort ends an MDI move', lambda: idle(h)) + expect_still(h, 'motion stops after aborting MDI') + + +def step_trace(h, do_step, steps=8): + """Step through step.ngc, recording (X, interpreter state) after each step.""" + to_origin(h) + open_program(h, 'step.ngc') + trace = [] + for _ in range(steps): + do_step() + h.settle(0.6) + s = h.poll() + trace.append((round(s.actual_position[0], 4), s.interp_state)) + return trace + + +def step(h): + # How far one step gets is task's business (it lags the presses while the + # program starts up). halui's job is to turn each rising edge into exactly + # one step, so compare it with stepping over NML. + def nml_step(): + h.cmd.auto(L.AUTO_STEP) + h.cmd.wait_complete() + + reference = step_trace(h, nml_step) + h.nml_abort() + via_pin = step_trace(h, lambda: h.pulse('program.step')) + h.check('program.step steps exactly like an NML step, press for press', + via_pin == reference, 'NML %s / pin %s' % (reference, via_pin)) + + xs = [x for x, _ in via_pin] + h.check('stepping walks through the whole program', 0.3 in xs, 'X after each step: %s' % xs) + h.check('no step moves more than one line', + all(b - a <= 0.1 + 1e-6 for a, b in zip([0.0] + xs, xs)), 'X after each step: %s' % xs) + + h.pulse('program.stop') + h.expect('program.stop ends a stepped program', lambda: idle(h)) + + +def optional_stop(h): + h.machine_on() + h.pulse('program.optional-stop.on') + h.expect('optional-stop.on turns optional stop on in task', lambda: h.stat.optional_stop) + h.expect_pin('optional-stop.is-on sets', 'program.optional-stop.is-on', True) + + to_origin(h) + h.nml_mdi('G0 X0') + open_program(h, 'optional-stop.ngc') + nml_run(h) + h.expect('with optional stop on, M1 pauses the program', lambda: paused(h)) + h.check('the move after M1 has not happened', close(x(h), 0.0, 1e-4), 'X=%.4f' % x(h)) + h.pulse('program.resume') + h.expect('program.resume continues past M1', + lambda: idle(h) and close(h.stat.actual_position[0], 0.5, 1e-4)) + + h.pulse('program.optional-stop.off') + h.expect('optional-stop.off turns optional stop off in task', lambda: not h.stat.optional_stop) + h.expect_pin('optional-stop.is-on clears', 'program.optional-stop.is-on', False) + + to_origin(h) + open_program(h, 'optional-stop.ngc') + saw_pause = False + nml_run(h) + end = time.time() + 10 + while time.time() < end: + h.poll() + saw_pause = saw_pause or paused(h) + if idle(h): + break + time.sleep(0.01) + h.check('with optional stop off, M1 is skipped', not saw_pause and idle(h) + and close(h.stat.actual_position[0], 0.5, 1e-4), + 'paused=%s X=%.4f' % (saw_pause, h.stat.actual_position[0])) + + h.cmd.set_optional_stop(1) + h.expect_pin('optional-stop.is-on follows an NML change', 'program.optional-stop.is-on', True) + h.cmd.set_optional_stop(0) + h.expect_pin('optional-stop.is-on follows it back', 'program.optional-stop.is-on', False) + + +def block_delete(h): + h.machine_on() + h.pulse('program.block-delete.on') + h.expect('block-delete.on turns block delete on in task', lambda: h.stat.block_delete) + h.expect_pin('block-delete.is-on sets', 'program.block-delete.is-on', True) + + to_origin(h) + open_program(h, 'block-delete.ngc') + nml_run(h) + h.wait_idle() + h.check('with block delete on, the "/" line is skipped', + close(h.poll().actual_position[2], 0.0, 1e-4), 'Z=%.4f' % h.stat.actual_position[2]) + + h.pulse('program.block-delete.off') + h.expect('block-delete.off turns block delete off in task', lambda: not h.stat.block_delete) + h.expect_pin('block-delete.is-on clears', 'program.block-delete.is-on', False) + + to_origin(h) + open_program(h, 'block-delete.ngc') + nml_run(h) + h.wait_idle() + h.check('with block delete off, the "/" line runs', + close(h.poll().actual_position[2], -1.0, 1e-4), 'Z=%.4f' % h.stat.actual_position[2]) + + h.cmd.set_block_delete(1) + h.expect_pin('block-delete.is-on follows an NML change', 'program.block-delete.is-on', True) + h.cmd.set_block_delete(0) + h.expect_pin('block-delete.is-on follows it back', 'program.block-delete.is-on', False) + + +run(run_without_a_program, + run_pause_resume_stop, + run_while_already_in_auto, + pause_when_idle, + abort_pin, + step, + optional_stop, + block_delete) diff --git a/tests/halui/program/test.sh b/tests/halui/program/test.sh new file mode 100755 index 00000000000..fd122f82169 --- /dev/null +++ b/tests/halui/program/test.sh @@ -0,0 +1,2 @@ +#!/bin/bash +exec ../_lib/launch.sh diff --git a/tests/halui/spindle-coolant/checkresult b/tests/halui/spindle-coolant/checkresult new file mode 100755 index 00000000000..73e90a43dfc --- /dev/null +++ b/tests/halui/spindle-coolant/checkresult @@ -0,0 +1,2 @@ +#!/bin/sh +exit 0 # test failure is indicated by test.sh exit value diff --git a/tests/halui/spindle-coolant/halui.ini b/tests/halui/spindle-coolant/halui.ini new file mode 100644 index 00000000000..4d21b0429ec --- /dev/null +++ b/tests/halui/spindle-coolant/halui.ini @@ -0,0 +1,100 @@ +# Test machine shared by the halui pin tests: XYZ trivkins, one spindle, +# a tool table, a home sequence (so halui.home-all exists) and two MDI +# commands (so halui.halui-mdi-is-running and halui.mdi-command-NN exist). + +[EMC] +VERSION = 1.1 +DEBUG = 0 + +[DISPLAY] +DISPLAY = ./test-ui.py +MAX_FEED_OVERRIDE = 1.5 +MIN_SPINDLE_OVERRIDE = 0.5 +MAX_SPINDLE_OVERRIDE = 1.2 + +[TASK] +TASK = milltask +CYCLE_TIME = 0.001 + +[RS274NGC] +PARAMETER_FILE = sim.var + +[EMCMOT] +EMCMOT = motmod +COMM_TIMEOUT = 4.0 +BASE_PERIOD = 0 +SERVO_PERIOD = 1000000 + +[EMCIO] +TOOL_TABLE = tool.tbl + +[HAL] +HALFILE = LIB:core_sim.hal + +[HALUI] +MDI_COMMAND = G0 X1 Y0 Z0 +MDI_COMMAND = G0 X0 Y0 Z0 + +[TRAJ] +COORDINATES = X Y Z +LINEAR_UNITS = inch +ANGULAR_UNITS = degree +DEFAULT_LINEAR_VELOCITY = 1.2 +MAX_LINEAR_VELOCITY = 4 +SPINDLES = 1 +NO_FORCE_HOMING = 1 + +[KINS] +KINEMATICS = trivkins +JOINTS = 3 + +[AXIS_X] +MIN_LIMIT = -40.0 +MAX_LIMIT = 40.0 +MAX_VELOCITY = 4 +MAX_ACCELERATION = 1000.0 + +[AXIS_Y] +MIN_LIMIT = -40.0 +MAX_LIMIT = 40.0 +MAX_VELOCITY = 4 +MAX_ACCELERATION = 1000.0 + +[AXIS_Z] +MIN_LIMIT = -4.0 +MAX_LIMIT = 4.0 +MAX_VELOCITY = 4 +MAX_ACCELERATION = 1000.0 + +[JOINT_0] +TYPE = LINEAR +HOME = 0.0 +MAX_VELOCITY = 4 +MAX_ACCELERATION = 1000.0 +MIN_LIMIT = -40.0 +MAX_LIMIT = 40.0 +FERROR = 0.050 +MIN_FERROR = 0.010 +HOME_SEQUENCE = 0 + +[JOINT_1] +TYPE = LINEAR +HOME = 0.0 +MAX_VELOCITY = 4 +MAX_ACCELERATION = 1000.0 +MIN_LIMIT = -40.0 +MAX_LIMIT = 40.0 +FERROR = 0.050 +MIN_FERROR = 0.010 +HOME_SEQUENCE = 0 + +[JOINT_2] +TYPE = LINEAR +HOME = 0.0 +MAX_VELOCITY = 4 +MAX_ACCELERATION = 1000.0 +MIN_LIMIT = -4.0 +MAX_LIMIT = 4.0 +FERROR = 0.050 +MIN_FERROR = 0.010 +HOME_SEQUENCE = 0 diff --git a/tests/halui/spindle-coolant/test-ui.py b/tests/halui/spindle-coolant/test-ui.py new file mode 100755 index 00000000000..f1daa19269b --- /dev/null +++ b/tests/halui/spindle-coolant/test-ui.py @@ -0,0 +1,171 @@ +#!/usr/bin/env python3 +"""halui: spindle control, spindle brake, mist and flood. + +Pins: spindle.0.start, stop, forward, reverse, increase, decrease, + brake-on, brake-off, is-on, runs-forward, runs-backward, brake-is-on, + mist.on, mist.off, mist.is-on, flood.on, flood.off, flood.is-on +""" + +import os +import sys + +sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', '_lib')) +from halui_test import run # noqa: E402 + +import linuxcnc as L # noqa: E402 + +SP = 'spindle.0.' + + +def sp(h): + return h.stat.spindle[0] + + +def expect_spindle(h, speed, why): + direction = (speed > 0) - (speed < 0) + h.expect('spindle 0 runs at %g %s' % (speed, why), + lambda: sp(h)['speed'] == speed and sp(h)['direction'] == direction + and bool(sp(h)['enabled']) == (speed != 0), + detail=lambda: 'speed=%g direction=%d enabled=%d' + % (sp(h)['speed'], sp(h)['direction'], sp(h)['enabled'])) + h.expect_pin(SP + 'is-on is %s %s' % (speed != 0, why), SP + 'is-on', speed != 0) + h.expect_pin(SP + 'runs-forward is %s %s' % (speed > 0, why), SP + 'runs-forward', speed > 0) + h.expect_pin(SP + 'runs-backward is %s %s' % (speed < 0, why), SP + 'runs-backward', speed < 0) + + +def expect_speed_steady(h, speed, why): + h.expect_steady('spindle 0 stays at %g %s' % (speed, why), + lambda: sp(h)['speed'] == speed, + detail=lambda: 'speed=%g' % sp(h)['speed']) + + +def without_s_word(h): + h.machine_on() + h.nml_mode(L.MODE_MANUAL) + expect_spindle(h, 0, 'at startup') + # with no S word active, halui asks for speed +/-1 + h.pulse(SP + 'start') + expect_spindle(h, 1, 'after start with no S word') + h.pulse(SP + 'stop') + expect_spindle(h, 0, 'after stop') + h.pulse(SP + 'reverse') + expect_spindle(h, -1, 'after reverse with no S word') + h.pulse(SP + 'forward') + expect_spindle(h, 1, 'after forward with no S word') + h.pulse(SP + 'stop') + expect_spindle(h, 0, 'after stop') + + +def with_s_word(h): + h.machine_on() + h.nml_mdi('S500') + h.nml_mode(L.MODE_MANUAL) + h.pulse(SP + 'forward') + expect_spindle(h, 500, 'after forward with S500') + h.pulse(SP + 'reverse') + expect_spindle(h, -500, 'after reverse with S500') + h.pulse(SP + 'start') + expect_spindle(h, 500, 'after start with S500 (start is forward)') + + # each rising edge steps by [SPINDLE_0]INCREMENT (default 100); + # the falling edge sends SPINDLE_CONSTANT, which keeps the speed + h.set(SP + 'increase', 1) + expect_spindle(h, 600, 'on the rising edge of increase') + expect_speed_steady(h, 600, 'while increase is held') + h.set(SP + 'increase', 0) + expect_speed_steady(h, 600, 'after increase is released') + + h.set(SP + 'decrease', 1) + expect_spindle(h, 500, 'on the rising edge of decrease') + h.set(SP + 'decrease', 0) + expect_speed_steady(h, 500, 'after decrease is released') + + h.pulse(SP + 'reverse') + expect_spindle(h, -500, 'after reverse') + h.pulse(SP + 'increase') + expect_spindle(h, -600, 'after increase while in reverse (magnitude grows)') + h.pulse(SP + 'decrease') + expect_spindle(h, -500, 'after decrease while in reverse') + + h.pulse(SP + 'stop') + expect_spindle(h, 0, 'after stop') + h.pulse(SP + 'increase') + expect_spindle(h, 0, 'after increase while stopped (does nothing)') + h.pulse(SP + 'decrease') + expect_spindle(h, 0, 'after decrease while stopped (does nothing)') + + +def brake(h): + h.machine_on() + h.nml_mode(L.MODE_MANUAL) + h.pulse(SP + 'brake-on') + h.expect('brake-on engages the brake', lambda: sp(h)['brake'] == 1) + h.expect_pin(SP + 'brake-is-on sets', SP + 'brake-is-on', True) + h.pulse(SP + 'brake-off') + h.expect('brake-off releases the brake', lambda: sp(h)['brake'] == 0) + h.expect_pin(SP + 'brake-is-on clears', SP + 'brake-is-on', False) + + h.cmd.brake(L.BRAKE_ENGAGE, 0) + h.expect_pin(SP + 'brake-is-on follows an NML brake engage', SP + 'brake-is-on', True) + h.cmd.brake(L.BRAKE_RELEASE, 0) + h.expect_pin(SP + 'brake-is-on follows an NML brake release', SP + 'brake-is-on', False) + + +def status_follows_other_clients(h): + h.machine_on() + h.nml_mode(L.MODE_MANUAL) + h.cmd.spindle(L.SPINDLE_FORWARD, 300, 0) + expect_spindle(h, 300, 'after an NML spindle forward') + h.cmd.spindle(L.SPINDLE_REVERSE, 300, 0) + expect_spindle(h, -300, 'after an NML spindle reverse') + h.cmd.spindle(L.SPINDLE_OFF, 0) + expect_spindle(h, 0, 'after an NML spindle off') + + +def spindle_when_not_on(h): + h.machine_estop() + h.pulse(SP + 'start') + expect_speed_steady(h, 0, 'when start is pressed in ESTOP') + h.expect_pin(SP + 'is-on stays false in ESTOP', SP + 'is-on', False) + + +def coolant(h): + h.machine_on() + h.nml_mode(L.MODE_MANUAL) + for kind in ('mist', 'flood'): + read = (lambda s: s.mist) if kind == 'mist' else (lambda s: s.flood) + h.pulse(kind + '.on') + h.expect('%s.on turns %s on' % (kind, kind), lambda r=read: r(h.stat)) + h.expect_pin('%s.is-on sets' % kind, kind + '.is-on', True) + h.pulse(kind + '.off') + h.expect('%s.off turns %s off' % (kind, kind), lambda r=read: not r(h.stat)) + h.expect_pin('%s.is-on clears' % kind, kind + '.is-on', False) + + h.cmd.mist(L.MIST_ON) + h.expect_pin('mist.is-on follows an NML mist on', 'mist.is-on', True) + h.cmd.flood(L.FLOOD_ON) + h.expect_pin('flood.is-on follows an NML flood on', 'flood.is-on', True) + h.cmd.mist(L.MIST_OFF) + h.cmd.flood(L.FLOOD_OFF) + h.expect_pin('mist.is-on follows an NML mist off', 'mist.is-on', False) + h.expect_pin('flood.is-on follows an NML flood off', 'flood.is-on', False) + + +def machine_off_stops_flood(h): + # task turns flood off whenever the machine is turned on or off + # (emcTaskSetState); flood.is-on has to follow that + h.machine_on() + h.pulse('flood.on') + h.expect_pin('flood is on', 'flood.is-on', True) + h.pulse('machine.off') + h.expect('machine.off turns flood off in task', lambda: not h.stat.flood) + h.expect_pin('flood.is-on follows task turning flood off', 'flood.is-on', False) + + +run(without_s_word, + with_s_word, + brake, + status_follows_other_clients, + spindle_when_not_on, + coolant, + machine_off_stops_flood) diff --git a/tests/halui/spindle-coolant/test.sh b/tests/halui/spindle-coolant/test.sh new file mode 100755 index 00000000000..fd122f82169 --- /dev/null +++ b/tests/halui/spindle-coolant/test.sh @@ -0,0 +1,2 @@ +#!/bin/bash +exec ../_lib/launch.sh diff --git a/tests/halui/startup-halfile/checkresult b/tests/halui/startup-halfile/checkresult new file mode 100755 index 00000000000..73e90a43dfc --- /dev/null +++ b/tests/halui/startup-halfile/checkresult @@ -0,0 +1,2 @@ +#!/bin/sh +exit 0 # test failure is indicated by test.sh exit value diff --git a/tests/halui/startup-halfile/halui-nets.hal b/tests/halui/startup-halfile/halui-nets.hal new file mode 100644 index 00000000000..bf0bcf2c075 --- /dev/null +++ b/tests/halui/startup-halfile/halui-nets.hal @@ -0,0 +1,7 @@ +# halui pins wired from a regular HALFILE. The startup script runs HAL files +# only after halui is ready, and configs rely on that: this must keep loading +# if halui ever moves into task. +net machine-is-on-led halui.machine.is-on +net remote-estop halui.estop.activate +net remote-estop-reset halui.estop.reset +net remote-mode-mdi halui.mode.mdi diff --git a/tests/halui/startup-halfile/halui.ini b/tests/halui/startup-halfile/halui.ini new file mode 100644 index 00000000000..901508b390c --- /dev/null +++ b/tests/halui/startup-halfile/halui.ini @@ -0,0 +1,102 @@ +# Test machine shared by the halui pin tests: XYZ trivkins, one spindle, +# a tool table, a home sequence (so halui.home-all exists) and two MDI +# commands (so halui.halui-mdi-is-running and halui.mdi-command-NN exist). + +[EMC] +VERSION = 1.1 +DEBUG = 0 + +[DISPLAY] +DISPLAY = ./test-ui.py +MAX_FEED_OVERRIDE = 1.5 +MIN_SPINDLE_OVERRIDE = 0.5 +MAX_SPINDLE_OVERRIDE = 1.2 + +[TASK] +TASK = milltask +CYCLE_TIME = 0.001 + +[RS274NGC] +PARAMETER_FILE = sim.var + +[EMCMOT] +EMCMOT = motmod +COMM_TIMEOUT = 4.0 +BASE_PERIOD = 0 +SERVO_PERIOD = 1000000 + +[EMCIO] +TOOL_TABLE = tool.tbl + +[HAL] +HALFILE = LIB:core_sim.hal +# halui pins wired in a regular HALFILE, not POSTGUI_HALFILE +HALFILE = halui-nets.hal + +[HALUI] +MDI_COMMAND = G0 X1 Y0 Z0 +MDI_COMMAND = G0 X0 Y0 Z0 + +[TRAJ] +COORDINATES = X Y Z +LINEAR_UNITS = inch +ANGULAR_UNITS = degree +DEFAULT_LINEAR_VELOCITY = 1.2 +MAX_LINEAR_VELOCITY = 4 +SPINDLES = 1 +NO_FORCE_HOMING = 1 + +[KINS] +KINEMATICS = trivkins +JOINTS = 3 + +[AXIS_X] +MIN_LIMIT = -40.0 +MAX_LIMIT = 40.0 +MAX_VELOCITY = 4 +MAX_ACCELERATION = 1000.0 + +[AXIS_Y] +MIN_LIMIT = -40.0 +MAX_LIMIT = 40.0 +MAX_VELOCITY = 4 +MAX_ACCELERATION = 1000.0 + +[AXIS_Z] +MIN_LIMIT = -4.0 +MAX_LIMIT = 4.0 +MAX_VELOCITY = 4 +MAX_ACCELERATION = 1000.0 + +[JOINT_0] +TYPE = LINEAR +HOME = 0.0 +MAX_VELOCITY = 4 +MAX_ACCELERATION = 1000.0 +MIN_LIMIT = -40.0 +MAX_LIMIT = 40.0 +FERROR = 0.050 +MIN_FERROR = 0.010 +HOME_SEQUENCE = 0 + +[JOINT_1] +TYPE = LINEAR +HOME = 0.0 +MAX_VELOCITY = 4 +MAX_ACCELERATION = 1000.0 +MIN_LIMIT = -40.0 +MAX_LIMIT = 40.0 +FERROR = 0.050 +MIN_FERROR = 0.010 +HOME_SEQUENCE = 0 + +[JOINT_2] +TYPE = LINEAR +HOME = 0.0 +MAX_VELOCITY = 4 +MAX_ACCELERATION = 1000.0 +MIN_LIMIT = -4.0 +MAX_LIMIT = 4.0 +FERROR = 0.050 +MIN_FERROR = 0.010 +HOME_SEQUENCE = 0 diff --git a/tests/halui/startup-halfile/test-ui.py b/tests/halui/startup-halfile/test-ui.py new file mode 100755 index 00000000000..c07b51daac6 --- /dev/null +++ b/tests/halui/startup-halfile/test-ui.py @@ -0,0 +1,67 @@ +#!/usr/bin/env python3 +"""halui pins wired from a regular HALFILE. + +The startup script runs HAL files only after halui is ready, and configs +rely on that ordering. This config nets halui pins in a HALFILE (see +halui-nets.hal); if halui's pins did not exist yet, linuxcnc would not get +as far as running this script. +""" + +import os +import sys +import time + +sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', '_lib')) +from halui_test import run, HOLD # noqa: E402 + +import hal # noqa: E402 +import linuxcnc as L # noqa: E402 + +NETTED = {'machine.is-on', 'estop.activate', 'estop.reset', 'mode.mdi'} + + +def pulse_signal(h, sig, pin): + h.touched.add(pin) + hal.set_s(sig, True) + time.sleep(HOLD) + hal.set_s(sig, False) + time.sleep(HOLD) + + +def wiring(h): + h.check('linuxcnc started with halui pins netted from a HALFILE', True) + h.check('exactly the netted pins are wired outside the harness', + h.external == NETTED, 'external: %s' % sorted(h.external)) + + +def netted_pins_work(h): + h.expect('the machine-is-on-led signal is false in ESTOP', + lambda: not hal.get_value('machine-is-on-led')) + + pulse_signal(h, 'remote-estop-reset', 'estop.reset') + h.expect('a pulse on the netted estop.reset resets estop', + lambda: h.stat.task_state == L.STATE_ESTOP_RESET) + + h.machine_on() + h.expect('the machine-is-on-led signal follows the machine turning on', + lambda: hal.get_value('machine-is-on-led')) + + h.nml_mode(L.MODE_MANUAL) + pulse_signal(h, 'remote-mode-mdi', 'mode.mdi') + h.expect('a pulse on the netted mode.mdi switches task to MDI', + lambda: h.stat.task_mode == L.MODE_MDI) + + pulse_signal(h, 'remote-estop', 'estop.activate') + h.expect('a pulse on the netted estop.activate estops the machine', + lambda: h.stat.task_state == L.STATE_ESTOP) + h.expect('the machine-is-on-led signal drops with it', + lambda: not hal.get_value('machine-is-on-led')) + + try: + h.set('estop.activate', 1) + h.check('the harness refuses to drive a pin the config wired', False) + except KeyError: + h.check('the harness refuses to drive a pin the config wired', True) + + +run(wiring, netted_pins_work) diff --git a/tests/halui/startup-halfile/test.sh b/tests/halui/startup-halfile/test.sh new file mode 100755 index 00000000000..fd122f82169 --- /dev/null +++ b/tests/halui/startup-halfile/test.sh @@ -0,0 +1,2 @@ +#!/bin/bash +exec ../_lib/launch.sh diff --git a/tests/halui/tool/checkresult b/tests/halui/tool/checkresult new file mode 100755 index 00000000000..73e90a43dfc --- /dev/null +++ b/tests/halui/tool/checkresult @@ -0,0 +1,2 @@ +#!/bin/sh +exit 0 # test failure is indicated by test.sh exit value diff --git a/tests/halui/tool/halui.ini b/tests/halui/tool/halui.ini new file mode 100644 index 00000000000..4d21b0429ec --- /dev/null +++ b/tests/halui/tool/halui.ini @@ -0,0 +1,100 @@ +# Test machine shared by the halui pin tests: XYZ trivkins, one spindle, +# a tool table, a home sequence (so halui.home-all exists) and two MDI +# commands (so halui.halui-mdi-is-running and halui.mdi-command-NN exist). + +[EMC] +VERSION = 1.1 +DEBUG = 0 + +[DISPLAY] +DISPLAY = ./test-ui.py +MAX_FEED_OVERRIDE = 1.5 +MIN_SPINDLE_OVERRIDE = 0.5 +MAX_SPINDLE_OVERRIDE = 1.2 + +[TASK] +TASK = milltask +CYCLE_TIME = 0.001 + +[RS274NGC] +PARAMETER_FILE = sim.var + +[EMCMOT] +EMCMOT = motmod +COMM_TIMEOUT = 4.0 +BASE_PERIOD = 0 +SERVO_PERIOD = 1000000 + +[EMCIO] +TOOL_TABLE = tool.tbl + +[HAL] +HALFILE = LIB:core_sim.hal + +[HALUI] +MDI_COMMAND = G0 X1 Y0 Z0 +MDI_COMMAND = G0 X0 Y0 Z0 + +[TRAJ] +COORDINATES = X Y Z +LINEAR_UNITS = inch +ANGULAR_UNITS = degree +DEFAULT_LINEAR_VELOCITY = 1.2 +MAX_LINEAR_VELOCITY = 4 +SPINDLES = 1 +NO_FORCE_HOMING = 1 + +[KINS] +KINEMATICS = trivkins +JOINTS = 3 + +[AXIS_X] +MIN_LIMIT = -40.0 +MAX_LIMIT = 40.0 +MAX_VELOCITY = 4 +MAX_ACCELERATION = 1000.0 + +[AXIS_Y] +MIN_LIMIT = -40.0 +MAX_LIMIT = 40.0 +MAX_VELOCITY = 4 +MAX_ACCELERATION = 1000.0 + +[AXIS_Z] +MIN_LIMIT = -4.0 +MAX_LIMIT = 4.0 +MAX_VELOCITY = 4 +MAX_ACCELERATION = 1000.0 + +[JOINT_0] +TYPE = LINEAR +HOME = 0.0 +MAX_VELOCITY = 4 +MAX_ACCELERATION = 1000.0 +MIN_LIMIT = -40.0 +MAX_LIMIT = 40.0 +FERROR = 0.050 +MIN_FERROR = 0.010 +HOME_SEQUENCE = 0 + +[JOINT_1] +TYPE = LINEAR +HOME = 0.0 +MAX_VELOCITY = 4 +MAX_ACCELERATION = 1000.0 +MIN_LIMIT = -40.0 +MAX_LIMIT = 40.0 +FERROR = 0.050 +MIN_FERROR = 0.010 +HOME_SEQUENCE = 0 + +[JOINT_2] +TYPE = LINEAR +HOME = 0.0 +MAX_VELOCITY = 4 +MAX_ACCELERATION = 1000.0 +MIN_LIMIT = -4.0 +MAX_LIMIT = 4.0 +FERROR = 0.050 +MIN_FERROR = 0.010 +HOME_SEQUENCE = 0 diff --git a/tests/halui/tool/test-ui.py b/tests/halui/tool/test-ui.py new file mode 100755 index 00000000000..5c0f4d9d6c0 --- /dev/null +++ b/tests/halui/tool/test-ui.py @@ -0,0 +1,112 @@ +#!/usr/bin/env python3 +"""halui: tool status. + +Pins: tool.number, tool.diameter, + tool.length_offset.x/y/z/a/b/c/u/v/w + +tool.tbl: T1 Z0.5 D0.25, T2 Z1.0 D0.5, T3 Z0 D0.125. test.sh copies it +fresh from ../_lib before every run, because G10 L1 rewrites it. +""" + +import os +import sys + +HERE = os.path.dirname(os.path.abspath(__file__)) +sys.path.insert(0, os.path.join(HERE, '..', '_lib')) +from halui_test import run # noqa: E402 + +import linuxcnc as L # noqa: E402 + +OFFSET_LETTERS = 'xyzabcuvw' + + +def mdi(h, *codes): + h.machine_on() + for c in codes: + h.nml_mdi(c) + + +def expect_tool(h, number, diameter, why): + h.expect('task has tool %d in the spindle %s' % (number, why), + lambda: h.stat.tool_in_spindle == number, + detail=lambda: 'tool_in_spindle=%d' % h.stat.tool_in_spindle) + h.expect_pin('tool.number is %d %s' % (number, why), 'tool.number', number) + h.expect_pin('tool.diameter is %g %s' % (diameter, why), 'tool.diameter', diameter, tol=1e-6) + + +def expect_offsets(h, offsets, why): + for i, a in enumerate(OFFSET_LETTERS): + want = offsets.get(a, 0.0) + h.expect('task tool offset %s is %g %s' % (a, want, why), + lambda i=i, w=want: abs(h.stat.tool_offset[i] - w) < 1e-6, + detail=lambda i=i: 'tool_offset[%d]=%g' % (i, h.stat.tool_offset[i])) + h.expect_pin('tool.length_offset.%s is %g %s' % (a, want, why), + 'tool.length_offset.' + a, want, tol=1e-6) + + +def startup(h): + expect_tool(h, 0, 0.0, 'at startup') + expect_offsets(h, {}, 'at startup') + + +def tool_changes(h): + mdi(h, 'G20 G90 G49', 'M61 Q2') + expect_tool(h, 2, 0.5, 'after M61 Q2') + expect_offsets(h, {}, 'before G43') + + mdi(h, 'G43') + expect_offsets(h, {'z': 1.0}, 'after G43 with tool 2') + + mdi(h, 'M61 Q1', 'G43') + expect_tool(h, 1, 0.25, 'after M61 Q1') + expect_offsets(h, {'z': 0.5}, 'after G43 with tool 1') + + mdi(h, 'T3 M6') + expect_tool(h, 3, 0.125, 'after T3 M6') + mdi(h, 'G43') + expect_offsets(h, {'z': 0.0}, 'after G43 with tool 3') + + mdi(h, 'G43.1 X0.1 Y0.2 Z0.3') + expect_offsets(h, {'x': 0.1, 'y': 0.2, 'z': 0.3}, 'after G43.1 X0.1 Y0.2 Z0.3') + + mdi(h, 'G49') + expect_offsets(h, {}, 'after G49') + + mdi(h, 'M61 Q0') + expect_tool(h, 0, 0.0, 'after M61 Q0 (empty spindle)') + + +def status_follows_table_edits(h): + mdi(h, 'G20 G90 M61 Q2') + expect_tool(h, 2, 0.5, 'before the table edit') + mdi(h, 'G10 L1 P2 R0.4') + expect_tool(h, 2, 0.8, 'after G10 L1 P2 R0.4 (radius 0.4)') + mdi(h, 'G10 L1 P2 Z1.25', 'G43') + expect_offsets(h, {'z': 1.25}, 'after G10 L1 P2 Z1.25 and G43') + mdi(h, 'G49', 'M61 Q0') + + +def unknown_tool(h): + # modify_hal_pins() has a latent bug: its "tool not found" test compares + # the loop index with CANON_POCKETS_MAX, but the loop stops after the last + # used index, so a tool missing from the table would leave the previous + # diameter on the pin. It cannot be reached this way: task refuses M61 for + # a tool that is not in the table, and on a non-random changer index 0 + # always mirrors the loaded tool. + mdi(h, 'G20 G90 M61 Q3') + expect_tool(h, 3, 0.125, 'before asking for an unknown tool') + h.drain_errors() + h.nml_mode(L.MODE_MDI) + h.cmd.mdi('M61 Q99') + h.cmd.wait_complete() + h.wait_idle() + h.settle(0.3) + errors = h.drain_errors() + h.check('task refuses M61 for a tool that is not in the table', + h.poll().tool_in_spindle == 3 and any('99' in e for e in errors), + 'tool_in_spindle=%d errors=%r' % (h.stat.tool_in_spindle, errors)) + expect_tool(h, 3, 0.125, 'after the refused M61 Q99') + mdi(h, 'M61 Q0') + + +run(startup, tool_changes, status_follows_table_edits, unknown_tool) diff --git a/tests/halui/tool/test.sh b/tests/halui/tool/test.sh new file mode 100755 index 00000000000..fd122f82169 --- /dev/null +++ b/tests/halui/tool/test.sh @@ -0,0 +1,2 @@ +#!/bin/bash +exec ../_lib/launch.sh From cb04d862f4b546fda2aa1c196354f12861245563 Mon Sep 17 00:00:00 2001 From: Rene Hopf Date: Sun, 20 Sep 2026 17:33:30 +0200 Subject: [PATCH 02/21] remove halui from example configs --- configs/attic/dallur-thc/dallur-advanced.ini | 3 --- configs/by_interface/mesa/plasma-5i20/plasma-5i20.ini | 1 - configs/by_interface/mesa/plasma-5i20/plasma-demo.ini | 1 - configs/by_interface/parport/gantry/gantry.ini | 1 - configs/by_interface/parport/gantry/gantry_joints.ini | 1 - configs/by_interface/parport/plasma-thc-sim/plasma_mm.ini | 3 --- configs/by_interface/parport/stepper-gantry/stepper_mm.ini | 3 --- configs/by_machine/scorbot-er-3/scorbot-er-3.ini | 2 -- configs/by_machine/smithy/1034gecko.ini | 1 - configs/by_machine/smithy/1240.ini | 1 - configs/by_machine/smithy/1240_4axis.ini | 1 - configs/by_machine/smithy/1240combined.ini | 1 - configs/by_machine/smithy/1240combined_4axis.ini | 1 - configs/by_machine/smithy/1240combined_mm.ini | 1 - configs/by_machine/smithy/1240gecko.ini | 1 - configs/by_machine/smithy/1240rutex.ini | 1 - configs/by_machine/smithy/1240rutex_4axis.ini | 1 - configs/by_machine/smithy/1315.ini | 1 - configs/by_machine/smithy/516gecko.ini | 1 - configs/by_machine/smithy/622.ini | 1 - configs/by_machine/smithy/622_4axis.ini | 1 - configs/by_machine/smithy/622gecko.ini | 1 - configs/by_machine/smithy/622keyence.ini | 1 - configs/by_machine/smithy/622leadshine.ini | 1 - configs/by_machine/smithy/622leadshine_4axis.ini | 1 - configs/by_machine/smithy/924.ini | 1 - configs/sim/axis/anglejog/anglejog.ini | 1 - configs/sim/axis/axis.ini | 2 -- configs/sim/axis/axis_9axis.ini | 1 - configs/sim/axis/axis_9axis_scurve.ini | 1 - configs/sim/axis/axis_mm.ini | 2 -- configs/sim/axis/axis_mm_scurve.ini | 1 - configs/sim/axis/canterp.ini | 1 - configs/sim/axis/external_offsets/dynamic_offsets.ini | 1 - configs/sim/axis/external_offsets/eoffsets.ini | 1 - configs/sim/axis/external_offsets/jwp_z.ini | 1 - configs/sim/axis/external_offsets/opa.ini | 1 - configs/sim/axis/extrajoints/12extrajoints.ini | 1 - configs/sim/axis/extrajoints/1extrajoint.ini | 1 - configs/sim/axis/extrajoints/2extrajoints.ini | 1 - configs/sim/axis/foam/axis_foam.ini | 1 - configs/sim/axis/gantry/gantry_mm.ini | 1 - configs/sim/axis/gladevcp/gladevcp_panel.ini | 1 - configs/sim/axis/gladevcp/gladevcp_panel_tester.ini | 1 - configs/sim/axis/gladevcp/gladevcp_tab.ini | 1 - configs/sim/axis/gladevcp/probe.ini | 1 - configs/sim/axis/gladevcp/set-param-from-ini.ini | 1 - configs/sim/axis/halui_pyvcp/halui.ini | 1 - configs/sim/axis/histogram_demo.ini | 1 - configs/sim/axis/home_is_shared/home_is_shared.ini | 1 - configs/sim/axis/ini_hal_demo.ini | 1 - configs/sim/axis/ja_tests/xyzb_locking_indexer/xyyzb.ini | 1 - configs/sim/axis/ja_tests/xyzb_locking_indexer/xyzb.ini | 1 - configs/sim/axis/ja_tests/xyzx_mpg/xyzx-xhc-hb04.ini | 1 - configs/sim/axis/ja_tests/xyzx_mpg/xyzx.ini | 1 - configs/sim/axis/laser/laser.ini | 1 - configs/sim/axis/lathe.ini | 1 - configs/sim/axis/moveoff/1_onpause_local.ini | 1 - configs/sim/axis/moveoff/2_onpause_external.ini | 1 - configs/sim/axis/moveoff/3_always_local.ini | 1 - configs/sim/axis/moveoff/4_always_external.ini | 1 - configs/sim/axis/moveoff/5_no_gui.ini | 1 - configs/sim/axis/moveoff/6_zretract.ini | 1 - configs/sim/axis/moveoff/7_pyvcp.ini | 1 - configs/sim/axis/moveoff/8_gladevcp.ini | 1 - configs/sim/axis/mtconnect/example.ini | 1 - configs/sim/axis/ngcgui/ngcgui.ini | 1 - configs/sim/axis/ngcgui/ngcgui_gcmc.ini | 1 - configs/sim/axis/ngcgui/ngcgui_lathe.ini | 1 - configs/sim/axis/ngcgui/ngcgui_simple.ini | 1 - configs/sim/axis/ngcgui/pyngcgui_axis.ini | 1 - configs/sim/axis/pentapod/pentapod.ini | 1 - configs/sim/axis/plasma/imperial.ini | 1 - configs/sim/axis/plasma/metric.ini | 1 - configs/sim/axis/profile_axis.ini | 1 - configs/sim/axis/qtvcp/qtvcp_tab.ini | 1 - configs/sim/axis/qtvcp/qtvismach_tab.ini | 1 - configs/sim/axis/random_tc.ini | 1 - configs/sim/axis/remap/cycle/cycle.ini | 1 - configs/sim/axis/remap/extend-builtins/extend-builtins.ini | 1 - configs/sim/axis/remap/getting-started/demo.ini | 1 - .../manualtoolchange.ini | 1 - configs/sim/axis/remap/rack-toolchange/racktoolchange.ini | 1 - configs/sim/axis/remap/stop-lookahead/demo.ini | 1 - configs/sim/axis/rose_engine/rose_engine.ini | 1 - configs/sim/axis/spindle_orient/orient.ini | 1 - configs/sim/axis/twopass/twopass.ini | 1 - configs/sim/axis/vismach/3axis-tutorial/3axis-tutorial.ini | 2 -- configs/sim/axis/vismach/5axis/bridgemill/5axis.ini | 1 - configs/sim/axis/vismach/5axis/max5/max5kins.ini | 1 - configs/sim/axis/vismach/5axis/max5/max5triv.ini | 1 - configs/sim/axis/vismach/5axis/table-dual-rotary/xyzab-tdr.ini | 1 - .../sim/axis/vismach/5axis/table-rotary-tilting/xyzac-trt.ini | 1 - .../sim/axis/vismach/5axis/table-rotary-tilting/xyzbc-trt.ini | 1 - .../xyzacb-trsrn_twp/xyzacb-trsrn.ini | 1 - .../xyzbca-trsrn_twp/xyzbca-trsrn.ini | 1 - configs/sim/axis/vismach/VMC_toolchange/vmc_graycode.ini | 1 - configs/sim/axis/vismach/VMC_toolchange/vmc_index.ini | 1 - configs/sim/axis/vismach/delta/ldelta.ini | 1 - configs/sim/axis/vismach/delta/ldelta_demo.ini | 1 - configs/sim/axis/vismach/delta/rdelta.ini | 1 - configs/sim/axis/vismach/hbm/hbm.ini | 1 - configs/sim/axis/vismach/hexapod-sim/hexapod.ini | 1 - .../vismach/melfa-sim/melfa-sim-genser/melfa-sim-genser.ini | 1 - .../sim/axis/vismach/melfa-sim/melfa-sim-three21/melfa_321.ini | 1 - configs/sim/axis/vismach/millturn/millturn.ini | 1 - configs/sim/axis/vismach/puma/puma.ini | 1 - configs/sim/axis/vismach/puma/puma560.ini | 1 - configs/sim/axis/vismach/puma/puma560_uvw.ini | 1 - configs/sim/axis/vismach/puma/puma_cube.ini | 1 - configs/sim/axis/vismach/scara/scara.ini | 1 - configs/sim/axis/wrapped_rotary/wrapped_rotary.ini | 1 - configs/sim/axis/xhc-hb04/xhc-hb04-layout1.ini | 1 - configs/sim/axis/xhc-hb04/xhc-hb04-layout2.ini | 1 - configs/sim/axis/xhc-hb04/xhc-hb04-layout2_mm.ini | 1 - configs/sim/gmoccapy/6_axis.ini | 1 - configs/sim/gmoccapy/7_axis.ini | 1 - configs/sim/gmoccapy/7_axis_tool.ini | 1 - configs/sim/gmoccapy/8_axis.ini | 1 - configs/sim/gmoccapy/9_axis.ini | 1 - configs/sim/gmoccapy/gmoccapy.ini | 2 -- configs/sim/gmoccapy/gmoccapy_4_axis.ini | 2 -- configs/sim/gmoccapy/gmoccapy_800x600.ini | 2 -- configs/sim/gmoccapy/gmoccapy_XYZAB.ini | 2 -- configs/sim/gmoccapy/gmoccapy_XYZAC.ini | 2 -- configs/sim/gmoccapy/gmoccapy_XYZCW.ini | 2 -- configs/sim/gmoccapy/gmoccapy_blockdelete.ini | 2 -- configs/sim/gmoccapy/gmoccapy_left_panel.ini | 2 -- configs/sim/gmoccapy/gmoccapy_messages.ini | 2 -- configs/sim/gmoccapy/gmoccapy_pedant.ini | 2 -- configs/sim/gmoccapy/gmoccapy_pyngcgui.ini | 2 -- configs/sim/gmoccapy/gmoccapy_pyngcgui_gcmc.ini | 2 -- configs/sim/gmoccapy/gmoccapy_qt_messages.ini | 2 -- configs/sim/gmoccapy/gmoccapy_right_panel.ini | 2 -- configs/sim/gmoccapy/gmoccapy_sim_hardware_button.ini | 2 -- configs/sim/gmoccapy/gmoccapy_tool_sensor.ini | 2 -- configs/sim/gmoccapy/gmoccapy_with_user_tabs.ini | 2 -- configs/sim/gmoccapy/lathe_configs/lathe.ini | 2 -- configs/sim/gmoccapy/lathe_configs/lathe_C.ini | 2 -- configs/sim/gmoccapy/lathe_configs/lathe_CW.ini | 2 -- configs/sim/gmoccapy/lathe_configs/lathe_backtool.ini | 2 -- configs/sim/gmoccapy/lathe_configs/lathe_imperial.ini | 2 -- configs/sim/gmoccapy/lathe_configs/lathe_macros.ini | 2 -- .../sim/gmoccapy/non_trivial_kinematics/Gantry/gantry_mm.ini | 1 - configs/sim/gmoccapy/non_trivial_kinematics/scara/scara.ini | 1 - .../non_trivial_kinematics/table-rotary-tilting/xyzac-trt.ini | 1 - configs/sim/gmoccapy/plasma_config/gmoccapy_plasma.ini | 2 -- configs/sim/gscreen/gscreen.ini | 2 -- configs/sim/gscreen/gscreen_custom/9axis.ini | 2 -- configs/sim/gscreen/gscreen_custom/gaxis_no_plot.ini | 2 -- configs/sim/gscreen/gscreen_custom/gscreen_gaxis.ini | 2 -- configs/sim/gscreen/gscreen_custom/industrial.ini | 2 -- configs/sim/gscreen/gscreen_custom/tester.ini | 2 -- configs/sim/gscreen/gscreen_custom/tester_metric.ini | 2 -- configs/sim/gscreen/gscreen_lathe.ini | 1 - configs/sim/gscreen/gscreen_mm.ini | 2 -- .../gscreen/industrial_lathe_wear/industrial_lathe_wear.ini | 1 - configs/sim/gscreen/ngcgui/pyngcgui_gscreen.ini | 1 - configs/sim/gscreen/ngcgui/pyngcgui_gscreen_popupkeyboard.ini | 1 - configs/sim/gscreen/silverdragon/silverdragon.ini | 1 - configs/sim/gscreen/spartan/spartan.ini | 1 - configs/sim/pyvcp_demo/pyvcp_bottom_panel.ini | 2 -- configs/sim/pyvcp_demo/pyvcp_demo1.ini | 2 -- configs/sim/pyvcp_demo/pyvcp_embed_tab.ini | 2 -- configs/sim/qtaxis/non-trivial/scara/scara.ini | 1 - configs/sim/qtaxis/xyz/qtaxis.ini | 2 -- configs/sim/qtdragon/qtdragon_multi_joint/qtdragon_xyyz.ini | 1 - configs/sim/qtdragon/qtdragon_multi_joint/qtdragon_xyyzw.ini | 1 - configs/sim/qtdragon/qtdragon_multi_joint/qtdragon_xyzy.ini | 1 - configs/sim/qtdragon/qtdragon_multi_joint/qtdragon_xyzya.ini | 1 - configs/sim/qtdragon/qtdragon_multi_joint/qtdragon_yyxz.ini | 1 - .../qtdragon/qtdragon_tool_probe/qtdragon_auto_tool_probe.ini | 1 - configs/sim/qtdragon/qtdragon_xyz/qtdragon_inch.ini | 1 - configs/sim/qtdragon/qtdragon_xyz/qtdragon_metric.ini | 1 - configs/sim/qtdragon/qtdragon_xyz/qtdragon_metric_debug.ini | 1 - configs/sim/qtdragon/qtdragon_xyz/qtdragon_xyza.ini | 1 - configs/sim/qtdragon/qtdragon_xyz45/qtdragon_xyza.ini | 1 - configs/sim/qtdragon/qtdragon_xyz45/qtdragon_xyzab.ini | 1 - configs/sim/qtdragon/qtdragon_xyz45/qtdragon_xyzac.ini | 1 - .../sim/qtdragon_hd/qtdragon_hd_xyz/qtdragon_hd_vertical.ini | 1 - .../qtdragon_hd/qtdragon_hd_xyz/qtdragon_hd_vertical_xyza.ini | 1 - configs/sim/qtdragon_hd/qtdragon_hd_xyz/qtdragon_hd_xyz.ini | 1 - configs/sim/qtdragon_hd/qtdragon_hd_xyz/qtdragon_hd_xyza.ini | 1 - configs/sim/qtdragon_hd/qtdragon_hd_xyz/qtdragon_hd_xyzab.ini | 1 - configs/sim/qtdragon_hd/qtdragon_hd_xyz/qtdragon_hd_xyzac.ini | 1 - configs/sim/qtdragon_hd/qtdragon_hd_xyz/qtdragon_next_xyz.ini | 1 - .../qtdragon_hd_z_compensation/qtdragon_hd_z_compensation.ini | 1 - configs/sim/qtdragon_lathe/basic_xz_lathe/lathe.ini | 1 - configs/sim/qttouchy/qttouchy.ini | 2 -- configs/sim/qtvcp_screens/blender.ini | 2 -- .../industrial_lathe_wear/industrial_lathe_wear.ini | 1 - configs/sim/qtvcp_screens/non-trivial/scara/scara.ini | 1 - configs/sim/qtvcp_screens/qt_800x600.ini | 2 -- configs/sim/qtvcp_screens/qtaxis.ini | 2 -- configs/sim/qtvcp_screens/qtaxis_lathe/qtaxis_lathe.ini | 2 -- configs/sim/qtvcp_screens/qtaxis_mpg.ini | 2 -- configs/sim/qtvcp_screens/qtdefault.ini | 2 -- configs/sim/qtvcp_screens/qtdefault_9axis.ini | 1 - configs/sim/qtvcp_screens/qtdefault_mm.ini | 2 -- configs/sim/qtvcp_screens/qtdragon/qtdragon_mpg.ini | 1 - configs/sim/qtvcp_screens/qtvcp_custom/qtdefault_ngc.ini | 2 -- configs/sim/qtvcp_screens/qtvcp_experimental/gremlin.ini | 2 -- .../qtvcp_screens/qtvcp_experimental/qtdefault_gladevcp.ini | 2 -- configs/sim/qtvcp_screens/qtvcp_experimental/qtdefault_ngc.ini | 2 -- configs/sim/qtvcp_screens/qtx1mill.ini | 2 -- configs/sim/qtvcp_screens/tester.ini | 2 -- configs/sim/tklinuxcnc/ldelta.ini | 1 - configs/sim/touchy/ngcgui/pyngcgui_touchy.ini | 1 - configs/sim/touchy/ngcgui/pyngcgui_touchy_lathe.ini | 1 - configs/sim/touchy/ngcgui/pyngcgui_touchy_moveoff.ini | 1 - configs/sim/woodpecker/woodpecker.ini | 1 - configs/sim/woodpecker/woodpecker_auto_tool_probe.ini | 1 - configs/sim/woodpecker/woodpecker_xyz.ini | 1 - configs/sim/woodpecker/woodpecker_xyza.ini | 1 - configs/sim/woodpecker/woodpecker_xyzab.ini | 1 - configs/sim/woodpecker/woodpecker_xyzy.ini | 1 - configs/sim/woodpecker/woodpecker_xyzya.ini | 1 - 217 files changed, 277 deletions(-) diff --git a/configs/attic/dallur-thc/dallur-advanced.ini b/configs/attic/dallur-thc/dallur-advanced.ini index 29c669589d4..17391f89e8a 100644 --- a/configs/attic/dallur-thc/dallur-advanced.ini +++ b/configs/attic/dallur-thc/dallur-advanced.ini @@ -79,9 +79,6 @@ CYCLE_TIME = 0.010 # The run script first uses halcmd to execute any HALFILE # files, and then to execute any individual HALCMD commands. # -# HALUI to interact with NML -# Run before any other HALFILE -HALUI=halui # list of hal config files to run through halcmd # files are executed in the order in which they appear HALFILE = dallur-core_stepper.hal diff --git a/configs/by_interface/mesa/plasma-5i20/plasma-5i20.ini b/configs/by_interface/mesa/plasma-5i20/plasma-5i20.ini index 665749f493d..05893701472 100644 --- a/configs/by_interface/mesa/plasma-5i20/plasma-5i20.ini +++ b/configs/by_interface/mesa/plasma-5i20/plasma-5i20.ini @@ -52,7 +52,6 @@ CYCLE_TIME = 0.010 # files are executed in the order in which they appear HALFILE = plasma-5i20.hal POSTGUI_HALFILE = postgui.hal -HALUI = halui # list of halcmd commands to execute # commands are executed in the order in which they appear #HALCMD = save neta diff --git a/configs/by_interface/mesa/plasma-5i20/plasma-demo.ini b/configs/by_interface/mesa/plasma-5i20/plasma-demo.ini index 227b53a8c42..50ce08897fc 100644 --- a/configs/by_interface/mesa/plasma-5i20/plasma-demo.ini +++ b/configs/by_interface/mesa/plasma-5i20/plasma-demo.ini @@ -43,7 +43,6 @@ TASK = milltask CYCLE_TIME = 0.010 [HAL] -HALUI = halui HALFILE = plasma-demo.hal POSTGUI_HALFILE = postgui.hal diff --git a/configs/by_interface/parport/gantry/gantry.ini b/configs/by_interface/parport/gantry/gantry.ini index efef5faf1f6..9940e23fc40 100644 --- a/configs/by_interface/parport/gantry/gantry.ini +++ b/configs/by_interface/parport/gantry/gantry.ini @@ -51,7 +51,6 @@ BASE_PERIOD = 30000 SERVO_PERIOD = 1000000 [HAL] -HALUI = halui HALFILE = gantry.hal #HALFILE = custom.hal #POSTGUI_HALFILE = postgui_call_list.hal diff --git a/configs/by_interface/parport/gantry/gantry_joints.ini b/configs/by_interface/parport/gantry/gantry_joints.ini index 6e8d83daa12..f249d65e20b 100644 --- a/configs/by_interface/parport/gantry/gantry_joints.ini +++ b/configs/by_interface/parport/gantry/gantry_joints.ini @@ -51,7 +51,6 @@ BASE_PERIOD = 30000 SERVO_PERIOD = 1000000 [HAL] -HALUI = halui HALFILE = gantry.hal [HALUI] diff --git a/configs/by_interface/parport/plasma-thc-sim/plasma_mm.ini b/configs/by_interface/parport/plasma-thc-sim/plasma_mm.ini index db1c400a957..56884b5fc77 100644 --- a/configs/by_interface/parport/plasma-thc-sim/plasma_mm.ini +++ b/configs/by_interface/parport/plasma-thc-sim/plasma_mm.ini @@ -104,9 +104,6 @@ CYCLE_TIME = 0.100 # The run script first uses halcmd to execute any HALFILE # files, and then to execute any individual HALCMD commands. # -# HALUI to interact with NML -# Run before any other HALFILE -HALUI = halui # list of hal config files to run through halcmd #+ files are executed in the order in which they appear HALFILE = kinematics.hal diff --git a/configs/by_interface/parport/stepper-gantry/stepper_mm.ini b/configs/by_interface/parport/stepper-gantry/stepper_mm.ini index d8fc9c20233..801ef71b72b 100644 --- a/configs/by_interface/parport/stepper-gantry/stepper_mm.ini +++ b/configs/by_interface/parport/stepper-gantry/stepper_mm.ini @@ -96,9 +96,6 @@ CYCLE_TIME = 0.100 # The run script first uses halcmd to execute any HALFILE # files, and then to execute any individual HALCMD commands. # -# HALUI to interact with NML -# Run before any other HALFILE -HALUI = halui # list of hal config files to run through halcmd #+ files are executed in the order in which they appear HALFILE = kinematics.hal diff --git a/configs/by_machine/scorbot-er-3/scorbot-er-3.ini b/configs/by_machine/scorbot-er-3/scorbot-er-3.ini index 3ba8fea37ae..71911f9215a 100644 --- a/configs/by_machine/scorbot-er-3/scorbot-er-3.ini +++ b/configs/by_machine/scorbot-er-3/scorbot-er-3.ini @@ -73,8 +73,6 @@ HALFILE = scorbot-er-3.hal #HALFILE = shuttlexpress-customization.hal POSTGUI_HALFILE = pyvcp.hal -HALUI = halui - [HALUI] #No Content diff --git a/configs/by_machine/smithy/1034gecko.ini b/configs/by_machine/smithy/1034gecko.ini index 71ac255c449..56468417b47 100644 --- a/configs/by_machine/smithy/1034gecko.ini +++ b/configs/by_machine/smithy/1034gecko.ini @@ -87,7 +87,6 @@ TASK = milltask CYCLE_TIME = 0.010 [HAL] -HALUI = halui HALFILE = 1240gecko.hal EZTROL_HALFILE = eztrol.hal HALFILE = axis_manualtoolchange.hal diff --git a/configs/by_machine/smithy/1240.ini b/configs/by_machine/smithy/1240.ini index a5301550bd5..3763cc7282a 100644 --- a/configs/by_machine/smithy/1240.ini +++ b/configs/by_machine/smithy/1240.ini @@ -88,7 +88,6 @@ TASK = milltask CYCLE_TIME = 0.001 [HAL] -HALUI = halui HALFILE = 1240.hal #HALFILE = naiky.hal EZTROL_HALFILE = 5i20eztrol.hal diff --git a/configs/by_machine/smithy/1240_4axis.ini b/configs/by_machine/smithy/1240_4axis.ini index 07f326a7977..a9a53f169f5 100644 --- a/configs/by_machine/smithy/1240_4axis.ini +++ b/configs/by_machine/smithy/1240_4axis.ini @@ -88,7 +88,6 @@ TASK = milltask CYCLE_TIME = 0.001 [HAL] -HALUI = halui HALFILE = 1240_4axis.hal #HALFILE = naiky.hal EZTROL_HALFILE = 5i20eztrol.hal diff --git a/configs/by_machine/smithy/1240combined.ini b/configs/by_machine/smithy/1240combined.ini index fe808dd5564..10241ccea9b 100644 --- a/configs/by_machine/smithy/1240combined.ini +++ b/configs/by_machine/smithy/1240combined.ini @@ -91,7 +91,6 @@ TASK = milltask CYCLE_TIME = 0.001 [HAL] -HALUI = halui HALFILE = 1240combined.hal #HALFILE = naiky.hal EZTROL_HALFILE = 5i20eztrol.hal diff --git a/configs/by_machine/smithy/1240combined_4axis.ini b/configs/by_machine/smithy/1240combined_4axis.ini index a9600f508ab..b26588e6ed2 100644 --- a/configs/by_machine/smithy/1240combined_4axis.ini +++ b/configs/by_machine/smithy/1240combined_4axis.ini @@ -91,7 +91,6 @@ TASK = milltask CYCLE_TIME = 0.001 [HAL] -HALUI = halui HALFILE = 1240combined_4axis.hal #HALFILE = naiky_4axis.hal EZTROL_HALFILE = 5i20eztrol.hal diff --git a/configs/by_machine/smithy/1240combined_mm.ini b/configs/by_machine/smithy/1240combined_mm.ini index e04e4edfee5..a497764d694 100644 --- a/configs/by_machine/smithy/1240combined_mm.ini +++ b/configs/by_machine/smithy/1240combined_mm.ini @@ -89,7 +89,6 @@ TASK = milltask CYCLE_TIME = 0.001 [HAL] -HALUI = halui HALFILE = 1240combined.hal #HALFILE = naiky.hal EZTROL_HALFILE = 5i20eztrol.hal diff --git a/configs/by_machine/smithy/1240gecko.ini b/configs/by_machine/smithy/1240gecko.ini index 05d87c39a63..34cca4694b6 100644 --- a/configs/by_machine/smithy/1240gecko.ini +++ b/configs/by_machine/smithy/1240gecko.ini @@ -88,7 +88,6 @@ TASK = milltask CYCLE_TIME = 0.010 [HAL] -HALUI = halui HALFILE = 1240gecko.hal EZTROL_HALFILE = eztrol.hal POSTGUI_HALFILE = gecko_postgui.hal diff --git a/configs/by_machine/smithy/1240rutex.ini b/configs/by_machine/smithy/1240rutex.ini index ab8906feb24..c5af47baf79 100644 --- a/configs/by_machine/smithy/1240rutex.ini +++ b/configs/by_machine/smithy/1240rutex.ini @@ -87,7 +87,6 @@ TASK = milltask CYCLE_TIME = 0.010 [HAL] -HALUI = halui HALFILE = 1240rutex.hal EZTROL_HALFILE = eztrol.hal HALFILE = axis_manualtoolchange.hal diff --git a/configs/by_machine/smithy/1240rutex_4axis.ini b/configs/by_machine/smithy/1240rutex_4axis.ini index a92967300e0..e4c04bc0001 100644 --- a/configs/by_machine/smithy/1240rutex_4axis.ini +++ b/configs/by_machine/smithy/1240rutex_4axis.ini @@ -87,7 +87,6 @@ TASK = milltask CYCLE_TIME = 0.010 [HAL] -HALUI = halui HALFILE = 1240rutex_4axis.hal EZTROL_HALFILE = eztrol.hal HALFILE = axis_manualtoolchange.hal diff --git a/configs/by_machine/smithy/1315.ini b/configs/by_machine/smithy/1315.ini index 695a2a71d84..992758019ad 100644 --- a/configs/by_machine/smithy/1315.ini +++ b/configs/by_machine/smithy/1315.ini @@ -67,7 +67,6 @@ TASK = milltask CYCLE_TIME = 0.010 [HAL] -HALUI = halui HALFILE = 1315.hal #HALFILE = naiky.hal POSTGUI_HALFILE = 1315postgui.hal diff --git a/configs/by_machine/smithy/516gecko.ini b/configs/by_machine/smithy/516gecko.ini index 09e46aef400..f3c8d942464 100644 --- a/configs/by_machine/smithy/516gecko.ini +++ b/configs/by_machine/smithy/516gecko.ini @@ -87,7 +87,6 @@ TASK = milltask CYCLE_TIME = 0.010 [HAL] -HALUI = halui HALFILE = 622gecko.hal EZTROL_HALFILE = eztrol.hal HALFILE = axis_manualtoolchange.hal diff --git a/configs/by_machine/smithy/622.ini b/configs/by_machine/smithy/622.ini index eea966b8284..b390d6b0f5d 100644 --- a/configs/by_machine/smithy/622.ini +++ b/configs/by_machine/smithy/622.ini @@ -87,7 +87,6 @@ TASK = milltask CYCLE_TIME = 0.001 [HAL] -HALUI = halui HALFILE = 622.hal #HALFILE = naiky.hal EZTROL_HALFILE = 5i20eztrol.hal diff --git a/configs/by_machine/smithy/622_4axis.ini b/configs/by_machine/smithy/622_4axis.ini index 88b085909d8..2bb26ee3bc6 100644 --- a/configs/by_machine/smithy/622_4axis.ini +++ b/configs/by_machine/smithy/622_4axis.ini @@ -87,7 +87,6 @@ TASK = milltask CYCLE_TIME = 0.001 [HAL] -HALUI = halui HALFILE = 622_4axis.hal #HALFILE = naiky.hal EZTROL_HALFILE = 5i20eztrol.hal diff --git a/configs/by_machine/smithy/622gecko.ini b/configs/by_machine/smithy/622gecko.ini index edd1a34409a..fdc8a35727e 100644 --- a/configs/by_machine/smithy/622gecko.ini +++ b/configs/by_machine/smithy/622gecko.ini @@ -87,7 +87,6 @@ TASK = milltask CYCLE_TIME = 0.010 [HAL] -HALUI = halui HALFILE = 622gecko.hal EZTROL_HALFILE = eztrol.hal HALFILE = axis_manualtoolchange.hal diff --git a/configs/by_machine/smithy/622keyence.ini b/configs/by_machine/smithy/622keyence.ini index b3a955910bf..7c16c57da94 100644 --- a/configs/by_machine/smithy/622keyence.ini +++ b/configs/by_machine/smithy/622keyence.ini @@ -88,7 +88,6 @@ TASK = milltask CYCLE_TIME = 0.001 [HAL] -HALUI = halui HALFILE = 622keyence.hal #HALFILE = naiky.hal EZTROL_HALFILE = 622eztrol-leadshine.hal diff --git a/configs/by_machine/smithy/622leadshine.ini b/configs/by_machine/smithy/622leadshine.ini index a23e2a29735..e5b0449c486 100644 --- a/configs/by_machine/smithy/622leadshine.ini +++ b/configs/by_machine/smithy/622leadshine.ini @@ -87,7 +87,6 @@ TASK = milltask CYCLE_TIME = 0.001 [HAL] -HALUI = halui HALFILE = 622leadshine.hal #HALFILE = naiky.hal EZTROL_HALFILE = 5i20eztrol.hal diff --git a/configs/by_machine/smithy/622leadshine_4axis.ini b/configs/by_machine/smithy/622leadshine_4axis.ini index 21c1c44340b..7b56be52200 100644 --- a/configs/by_machine/smithy/622leadshine_4axis.ini +++ b/configs/by_machine/smithy/622leadshine_4axis.ini @@ -87,7 +87,6 @@ TASK = milltask CYCLE_TIME = 0.001 [HAL] -HALUI = halui HALFILE = 622leadshine_4axis.hal #HALFILE = naiky.hal EZTROL_HALFILE = 5i20eztrol.hal diff --git a/configs/by_machine/smithy/924.ini b/configs/by_machine/smithy/924.ini index c4092c0a83e..684ddc663db 100644 --- a/configs/by_machine/smithy/924.ini +++ b/configs/by_machine/smithy/924.ini @@ -72,7 +72,6 @@ TASK = milltask CYCLE_TIME = 0.001 [HAL] -HALUI = halui HALFILE = 924.hal #HALFILE = naiky.hal diff --git a/configs/sim/axis/anglejog/anglejog.ini b/configs/sim/axis/anglejog/anglejog.ini index 696f6188bb2..17196bfe235 100644 --- a/configs/sim/axis/anglejog/anglejog.ini +++ b/configs/sim/axis/anglejog/anglejog.ini @@ -30,7 +30,6 @@ SERVO_PERIOD = 1000000 CYCLE_TIME = 0.001 [HAL] - HALUI = halui HALFILE = LIB:basic_sim.tcl -no_sim_spindle -no_use_hal_manualtoolchange # all provisions for anglejog: POSTGUI_HALFILE = anglejog_postgui.hal diff --git a/configs/sim/axis/axis.ini b/configs/sim/axis/axis.ini index 534604ef150..4945eafc986 100644 --- a/configs/sim/axis/axis.ini +++ b/configs/sim/axis/axis.ini @@ -124,8 +124,6 @@ HALFILE = cooling.hal # AXIS at this time (only AXIS creates a HAL component of its own) #POSTGUI_HALFILE = test_postgui.hal -HALUI = halui - # Trajectory planner section -------------------------------------------------- [TRAJ] COORDINATES = X Y Z diff --git a/configs/sim/axis/axis_9axis.ini b/configs/sim/axis/axis_9axis.ini index ff220c27567..103baf9c510 100644 --- a/configs/sim/axis/axis_9axis.ini +++ b/configs/sim/axis/axis_9axis.ini @@ -45,7 +45,6 @@ SERVO_PERIOD = 1000000 TOOL_CHANGE_POSITION = 0 0 2 [HAL] - HALUI = halui HALFILE = LIB:basic_sim.tcl HALFILE = locking_indexer.hal diff --git a/configs/sim/axis/axis_9axis_scurve.ini b/configs/sim/axis/axis_9axis_scurve.ini index 39c082a442b..24bc30f8012 100644 --- a/configs/sim/axis/axis_9axis_scurve.ini +++ b/configs/sim/axis/axis_9axis_scurve.ini @@ -47,7 +47,6 @@ TASK = milltask CYCLE_TIME = 0.010 [HAL] -HALUI = halui HALFILE = axis_9axis_scurve.hal [TRAJ] diff --git a/configs/sim/axis/axis_mm.ini b/configs/sim/axis/axis_mm.ini index df209baf313..1efb1d7dee4 100644 --- a/configs/sim/axis/axis_mm.ini +++ b/configs/sim/axis/axis_mm.ini @@ -115,8 +115,6 @@ HALFILE = cooling.hal # AXIS at this time (only AXIS creates a HAL component of its own) #POSTGUI_HALFILE = test_postgui.hal -HALUI = halui - # Trajectory planner section -------------------------------------------------- [TRAJ] COORDINATES = X Y Z diff --git a/configs/sim/axis/axis_mm_scurve.ini b/configs/sim/axis/axis_mm_scurve.ini index 13a3e803bbd..0f69e88d20c 100644 --- a/configs/sim/axis/axis_mm_scurve.ini +++ b/configs/sim/axis/axis_mm_scurve.ini @@ -47,7 +47,6 @@ TASK = milltask CYCLE_TIME = 0.010 [HAL] -HALUI = halui HALFILE = axis_mm_scurve.hal [TRAJ] diff --git a/configs/sim/axis/canterp.ini b/configs/sim/axis/canterp.ini index 1fc4c1ab779..c34f3c67fa1 100644 --- a/configs/sim/axis/canterp.ini +++ b/configs/sim/axis/canterp.ini @@ -32,7 +32,6 @@ BASE_PERIOD = 0 SERVO_PERIOD = 1000000 [HAL] - HALUI = halui HALFILE = LIB:basic_sim.tcl [TRAJ] diff --git a/configs/sim/axis/external_offsets/dynamic_offsets.ini b/configs/sim/axis/external_offsets/dynamic_offsets.ini index b07b103c737..6b0fd9969fd 100644 --- a/configs/sim/axis/external_offsets/dynamic_offsets.ini +++ b/configs/sim/axis/external_offsets/dynamic_offsets.ini @@ -4,7 +4,6 @@ DELAY = 5 APP = halscope -i dynamic_offsets.halscope [HAL] -HALUI = halui HALFILE = LIB:basic_sim.tcl -no_sim_spindle POSTGUI_HALFILE = dynamic_offsets_panel.hal diff --git a/configs/sim/axis/external_offsets/eoffsets.ini b/configs/sim/axis/external_offsets/eoffsets.ini index 0542f67c902..6559b3364f8 100644 --- a/configs/sim/axis/external_offsets/eoffsets.ini +++ b/configs/sim/axis/external_offsets/eoffsets.ini @@ -18,7 +18,6 @@ APP = sim_pin --title "MPG Simulator" \ APP = eoffsets_monitor.tcl [HAL] -HALUI = halui HALFILE = LIB:basic_sim.tcl -no_use_hal_manualtoolchange HALFILE = eoffsets.hal POSTGUI_HALFILE = eoffsets_panel.hal diff --git a/configs/sim/axis/external_offsets/jwp_z.ini b/configs/sim/axis/external_offsets/jwp_z.ini index d99db80c758..0c6853d4965 100644 --- a/configs/sim/axis/external_offsets/jwp_z.ini +++ b/configs/sim/axis/external_offsets/jwp_z.ini @@ -10,7 +10,6 @@ [HAL] -HALUI = halui HALFILE = LIB:basic_sim.tcl POSTGUI_HALFILE = jwp_z_panel.hal diff --git a/configs/sim/axis/external_offsets/opa.ini b/configs/sim/axis/external_offsets/opa.ini index 2301b15c977..87b68605f48 100644 --- a/configs/sim/axis/external_offsets/opa.ini +++ b/configs/sim/axis/external_offsets/opa.ini @@ -5,7 +5,6 @@ DELAY = 3 APP = sim_pin ini.x.max_acceleration ini.x.max_velocity [HAL] -HALUI = halui HALFILE = LIB:basic_sim.tcl HALFILE = opa.hal POSTGUI_HALFILE = opa_panel.hal diff --git a/configs/sim/axis/extrajoints/12extrajoints.ini b/configs/sim/axis/extrajoints/12extrajoints.ini index ff8f8f02c39..96ec281db6f 100644 --- a/configs/sim/axis/extrajoints/12extrajoints.ini +++ b/configs/sim/axis/extrajoints/12extrajoints.ini @@ -26,7 +26,6 @@ SERVO_PERIOD = 1000000 TWOPASS = on HALFILE = LIB:basic_sim.tcl HALFILE = ./extrajoints.tcl -HALUI = halui [DISPLAY] DISPLAY = axis diff --git a/configs/sim/axis/extrajoints/1extrajoint.ini b/configs/sim/axis/extrajoints/1extrajoint.ini index 38c17ad9da2..bdbb4358c2d 100644 --- a/configs/sim/axis/extrajoints/1extrajoint.ini +++ b/configs/sim/axis/extrajoints/1extrajoint.ini @@ -27,7 +27,6 @@ SERVO_PERIOD = 1000000 [HAL] HALFILE = 1extrajoint.hal -HALUI = halui [DISPLAY] diff --git a/configs/sim/axis/extrajoints/2extrajoints.ini b/configs/sim/axis/extrajoints/2extrajoints.ini index fee8ff15c41..21a7b8b7f10 100644 --- a/configs/sim/axis/extrajoints/2extrajoints.ini +++ b/configs/sim/axis/extrajoints/2extrajoints.ini @@ -31,7 +31,6 @@ SERVO_PERIOD = 1000000 [HAL] HALFILE = LIB:basic_sim.tcl HALFILE = ./2extrajoints.hal -HALUI = halui [DISPLAY] DISPLAY = axis diff --git a/configs/sim/axis/foam/axis_foam.ini b/configs/sim/axis/foam/axis_foam.ini index db93a5f2849..96961c0b731 100644 --- a/configs/sim/axis/foam/axis_foam.ini +++ b/configs/sim/axis/foam/axis_foam.ini @@ -41,7 +41,6 @@ TASK = milltask CYCLE_TIME = 0.001 [HAL] -HALUI = halui HALFILE = LIB:basic_sim.tcl [TRAJ] diff --git a/configs/sim/axis/gantry/gantry_mm.ini b/configs/sim/axis/gantry/gantry_mm.ini index 52e01d21bfb..51b029ffb28 100644 --- a/configs/sim/axis/gantry/gantry_mm.ini +++ b/configs/sim/axis/gantry/gantry_mm.ini @@ -39,7 +39,6 @@ SERVO_PERIOD = 1000000 [HAL] HALFILE = gantry_mm.hal -HALUI = halui [KINS] KINEMATICS = trivkins coordinates=xyyz kinstype=BOTH diff --git a/configs/sim/axis/gladevcp/gladevcp_panel.ini b/configs/sim/axis/gladevcp/gladevcp_panel.ini index a8f477b8ade..64b95bad2e4 100644 --- a/configs/sim/axis/gladevcp/gladevcp_panel.ini +++ b/configs/sim/axis/gladevcp/gladevcp_panel.ini @@ -44,7 +44,6 @@ TASK = milltask CYCLE_TIME = 0.001 [HAL] -HALUI = halui HALFILE = LIB:basic_sim.tcl POSTGUI_HALFILE= manual-example.hal diff --git a/configs/sim/axis/gladevcp/gladevcp_panel_tester.ini b/configs/sim/axis/gladevcp/gladevcp_panel_tester.ini index 26b292677c7..caedbd799c8 100644 --- a/configs/sim/axis/gladevcp/gladevcp_panel_tester.ini +++ b/configs/sim/axis/gladevcp/gladevcp_panel_tester.ini @@ -44,7 +44,6 @@ TASK = milltask CYCLE_TIME = 0.001 [HAL] -HALUI = halui HALFILE = LIB:basic_sim.tcl #POSTGUI_HALFILE= manual-example.hal diff --git a/configs/sim/axis/gladevcp/gladevcp_tab.ini b/configs/sim/axis/gladevcp/gladevcp_tab.ini index 4395c542d52..4b16152efd2 100644 --- a/configs/sim/axis/gladevcp/gladevcp_tab.ini +++ b/configs/sim/axis/gladevcp/gladevcp_tab.ini @@ -48,7 +48,6 @@ TASK = milltask CYCLE_TIME = 0.001 [HAL] -HALUI = halui HALFILE = LIB:basic_sim.tcl POSTGUI_HALFILE = manual-example.hal diff --git a/configs/sim/axis/gladevcp/probe.ini b/configs/sim/axis/gladevcp/probe.ini index 635f6424b62..e0d878d0e66 100644 --- a/configs/sim/axis/gladevcp/probe.ini +++ b/configs/sim/axis/gladevcp/probe.ini @@ -46,7 +46,6 @@ TASK = milltask CYCLE_TIME = 0.001 [HAL] -HALUI = halui HALFILE = LIB:basic_sim.tcl [TRAJ] diff --git a/configs/sim/axis/gladevcp/set-param-from-ini.ini b/configs/sim/axis/gladevcp/set-param-from-ini.ini index 43da20df92f..998a660657e 100644 --- a/configs/sim/axis/gladevcp/set-param-from-ini.ini +++ b/configs/sim/axis/gladevcp/set-param-from-ini.ini @@ -44,7 +44,6 @@ TASK = milltask CYCLE_TIME = 0.001 [HAL] -HALUI = halui HALFILE = LIB:basic_sim.tcl [TRAJ] diff --git a/configs/sim/axis/halui_pyvcp/halui.ini b/configs/sim/axis/halui_pyvcp/halui.ini index 4eaef32e8da..7e62a514a6a 100644 --- a/configs/sim/axis/halui_pyvcp/halui.ini +++ b/configs/sim/axis/halui_pyvcp/halui.ini @@ -33,7 +33,6 @@ CYCLE_TIME = 0.010 HALFILE = core_sim.hal HALFILE = pyvcp.hal HALFILE = simulated_home.hal -HALUI = halui [HALUI] MDI_COMMAND = G0 G53 Z0 diff --git a/configs/sim/axis/histogram_demo.ini b/configs/sim/axis/histogram_demo.ini index 615f01859fe..c6221ef9b75 100644 --- a/configs/sim/axis/histogram_demo.ini +++ b/configs/sim/axis/histogram_demo.ini @@ -45,7 +45,6 @@ TASK = milltask CYCLE_TIME = 0.001 [HAL] - HALUI = halui HALFILE = LIB:basic_sim.tcl [TRAJ] diff --git a/configs/sim/axis/home_is_shared/home_is_shared.ini b/configs/sim/axis/home_is_shared/home_is_shared.ini index e80bf812c76..5503aa51163 100644 --- a/configs/sim/axis/home_is_shared/home_is_shared.ini +++ b/configs/sim/axis/home_is_shared/home_is_shared.ini @@ -99,7 +99,6 @@ TOOL_CHANGE_QUILL_UP = 1 [HAL] HALFILE = core_sim.hal HALFILE = simulated_home_is_shared.hal -HALUI = halui # Trajectory planner section -------------------------------------------------- [TRAJ] diff --git a/configs/sim/axis/ini_hal_demo.ini b/configs/sim/axis/ini_hal_demo.ini index 75c5992b7f9..486d3f939d5 100644 --- a/configs/sim/axis/ini_hal_demo.ini +++ b/configs/sim/axis/ini_hal_demo.ini @@ -47,7 +47,6 @@ TASK = milltask CYCLE_TIME = 0.001 [HAL] - HALUI = halui HALFILE = LIB:basic_sim.tcl POSTGUI_HALFILE = postgui_calib_helper.hal diff --git a/configs/sim/axis/ja_tests/xyzb_locking_indexer/xyyzb.ini b/configs/sim/axis/ja_tests/xyzb_locking_indexer/xyyzb.ini index bce8ab912bc..c3ef01710a6 100644 --- a/configs/sim/axis/ja_tests/xyzb_locking_indexer/xyyzb.ini +++ b/configs/sim/axis/ja_tests/xyzb_locking_indexer/xyyzb.ini @@ -20,7 +20,6 @@ JOINTS = 5 KINEMATICS = trivkins coordinates=xyyzb kinstype=both [HAL] - HALUI = halui HALFILE = LIB:basic_sim.tcl HALFILE = LIB:wheeljogpins.tcl 0.1 diff --git a/configs/sim/axis/ja_tests/xyzb_locking_indexer/xyzb.ini b/configs/sim/axis/ja_tests/xyzb_locking_indexer/xyzb.ini index 8cc06b086f2..6e9838b1985 100644 --- a/configs/sim/axis/ja_tests/xyzb_locking_indexer/xyzb.ini +++ b/configs/sim/axis/ja_tests/xyzb_locking_indexer/xyzb.ini @@ -13,7 +13,6 @@ JOINTS = 4 KINEMATICS = trivkins coordinates=xyzb [HAL] - HALUI = halui HALFILE = LIB:basic_sim.tcl HALFILE = LIB:wheeljogpins.tcl 0.1 diff --git a/configs/sim/axis/ja_tests/xyzx_mpg/xyzx-xhc-hb04.ini b/configs/sim/axis/ja_tests/xyzx_mpg/xyzx-xhc-hb04.ini index 8918f2f36ae..548ba7b8b15 100644 --- a/configs/sim/axis/ja_tests/xyzx_mpg/xyzx-xhc-hb04.ini +++ b/configs/sim/axis/ja_tests/xyzx_mpg/xyzx-xhc-hb04.ini @@ -5,7 +5,6 @@ APP = halshow xyzx.halshow [HAL] - HALUI = halui HALFILE = LIB:basic_sim.tcl HALFILE = LIB:xhc-hb04.tcl diff --git a/configs/sim/axis/ja_tests/xyzx_mpg/xyzx.ini b/configs/sim/axis/ja_tests/xyzx_mpg/xyzx.ini index 997ab73cc95..ec873a69d30 100644 --- a/configs/sim/axis/ja_tests/xyzx_mpg/xyzx.ini +++ b/configs/sim/axis/ja_tests/xyzx_mpg/xyzx.ini @@ -11,7 +11,6 @@ APP = sim_pin \ APP = halshow xyzx.halshow [HAL] - HALUI = halui HALFILE = LIB:basic_sim.tcl HALFILE = ./xyzx_jog.hal diff --git a/configs/sim/axis/laser/laser.ini b/configs/sim/axis/laser/laser.ini index 9ca8259791b..cb43697088a 100644 --- a/configs/sim/axis/laser/laser.ini +++ b/configs/sim/axis/laser/laser.ini @@ -13,7 +13,6 @@ LINEAR_UNITS = mm ANGULAR_UNITS = degree [HAL] -HALUI = halui HALFILE = LIB:basic_sim.tcl HALFILE = laser.hal POSTGUI_HALFILE = postgui.hal diff --git a/configs/sim/axis/lathe.ini b/configs/sim/axis/lathe.ini index dcbfba03341..47cb37b0514 100644 --- a/configs/sim/axis/lathe.ini +++ b/configs/sim/axis/lathe.ini @@ -40,7 +40,6 @@ SERVO_PERIOD = 1000000 CYCLE_TIME = 0.001 [HAL] - HALUI = halui HALFILE = LIB:basic_sim.tcl POSTGUI_HALFILE = lathe_postgui.hal diff --git a/configs/sim/axis/moveoff/1_onpause_local.ini b/configs/sim/axis/moveoff/1_onpause_local.ini index b6cf30a605a..4892c9bdeba 100644 --- a/configs/sim/axis/moveoff/1_onpause_local.ini +++ b/configs/sim/axis/moveoff/1_onpause_local.ini @@ -7,7 +7,6 @@ VERSION = 1.1 MACHINE = moveoff,onpause,local [HAL] - HALUI = halui HALFILE = LIB:basic_sim.tcl # hookup a moveoff component: diff --git a/configs/sim/axis/moveoff/2_onpause_external.ini b/configs/sim/axis/moveoff/2_onpause_external.ini index 46c594a7d8d..6bf8dfe081c 100644 --- a/configs/sim/axis/moveoff/2_onpause_external.ini +++ b/configs/sim/axis/moveoff/2_onpause_external.ini @@ -7,7 +7,6 @@ VERSION = 1.1 MACHINE = moveoff,onpause,external [HAL] - HALUI = halui HALFILE = LIB:basic_sim.tcl # hookup a moveoff component: diff --git a/configs/sim/axis/moveoff/3_always_local.ini b/configs/sim/axis/moveoff/3_always_local.ini index eedd656d649..bf8b53e8698 100644 --- a/configs/sim/axis/moveoff/3_always_local.ini +++ b/configs/sim/axis/moveoff/3_always_local.ini @@ -7,7 +7,6 @@ VERSION = 1.1 MACHINE = moveoff,always,local [HAL] - HALUI = halui HALFILE = LIB:basic_sim.tcl # hookup a moveoff component: diff --git a/configs/sim/axis/moveoff/4_always_external.ini b/configs/sim/axis/moveoff/4_always_external.ini index 635bc49ce4f..2cf8283178e 100644 --- a/configs/sim/axis/moveoff/4_always_external.ini +++ b/configs/sim/axis/moveoff/4_always_external.ini @@ -7,7 +7,6 @@ VERSION = 1.1 MACHINE = moveoff,always,external [HAL] - HALUI = halui HALFILE = LIB:basic_sim.tcl # hookup a moveoff component: diff --git a/configs/sim/axis/moveoff/5_no_gui.ini b/configs/sim/axis/moveoff/5_no_gui.ini index 45c1ba29823..1d6aa1f06e1 100644 --- a/configs/sim/axis/moveoff/5_no_gui.ini +++ b/configs/sim/axis/moveoff/5_no_gui.ini @@ -7,7 +7,6 @@ VERSION = 1.1 MACHINE = moveoff,no_gui [HAL] - HALUI = halui HALFILE = LIB:basic_sim.tcl HALFILE = LIB:hookup_moveoff.tcl diff --git a/configs/sim/axis/moveoff/6_zretract.ini b/configs/sim/axis/moveoff/6_zretract.ini index a26f98bb48b..dd8996cb2b0 100644 --- a/configs/sim/axis/moveoff/6_zretract.ini +++ b/configs/sim/axis/moveoff/6_zretract.ini @@ -7,7 +7,6 @@ VERSION = 1.1 MACHINE = moveoff zretract demo [HAL] - HALUI = halui HALFILE = LIB:basic_sim.tcl # hookup a moveoff component: diff --git a/configs/sim/axis/moveoff/7_pyvcp.ini b/configs/sim/axis/moveoff/7_pyvcp.ini index 191a2b7fe17..852895b3621 100644 --- a/configs/sim/axis/moveoff/7_pyvcp.ini +++ b/configs/sim/axis/moveoff/7_pyvcp.ini @@ -7,7 +7,6 @@ VERSION = 1.1 MACHINE = moveoff,onpause,external [HAL] - HALUI = halui HALFILE = LIB:basic_sim.tcl # hookup a moveoff component: diff --git a/configs/sim/axis/moveoff/8_gladevcp.ini b/configs/sim/axis/moveoff/8_gladevcp.ini index 1c61c46b552..787c807baf4 100644 --- a/configs/sim/axis/moveoff/8_gladevcp.ini +++ b/configs/sim/axis/moveoff/8_gladevcp.ini @@ -7,7 +7,6 @@ VERSION = 1.1 MACHINE = moveoff,onpause,external [HAL] - HALUI = halui HALFILE = LIB:basic_sim.tcl # hookup a moveoff component: diff --git a/configs/sim/axis/mtconnect/example.ini b/configs/sim/axis/mtconnect/example.ini index 0ee7838cf6b..b39ad50015a 100644 --- a/configs/sim/axis/mtconnect/example.ini +++ b/configs/sim/axis/mtconnect/example.ini @@ -97,7 +97,6 @@ HALFILE = check_xyz_constraints.hal HALFILE = ../cooling.hal # Load the MTConnect agent as a userspace HAL component (see mtconnect.hal). HALFILE = mtconnect.hal -HALUI = halui [TRAJ] COORDINATES = X Y Z diff --git a/configs/sim/axis/ngcgui/ngcgui.ini b/configs/sim/axis/ngcgui/ngcgui.ini index 538017966e6..ac3e15f5f43 100644 --- a/configs/sim/axis/ngcgui/ngcgui.ini +++ b/configs/sim/axis/ngcgui/ngcgui.ini @@ -81,7 +81,6 @@ TASK = milltask CYCLE_TIME = 0.001 [HAL] -HALUI = halui HALFILE = LIB:basic_sim.tcl [TRAJ] diff --git a/configs/sim/axis/ngcgui/ngcgui_gcmc.ini b/configs/sim/axis/ngcgui/ngcgui_gcmc.ini index 9139f793ee4..6625d08060e 100644 --- a/configs/sim/axis/ngcgui/ngcgui_gcmc.ini +++ b/configs/sim/axis/ngcgui/ngcgui_gcmc.ini @@ -85,7 +85,6 @@ TASK = milltask CYCLE_TIME = 0.001 [HAL] -HALUI = halui HALFILE = LIB:basic_sim.tcl [TRAJ] diff --git a/configs/sim/axis/ngcgui/ngcgui_lathe.ini b/configs/sim/axis/ngcgui/ngcgui_lathe.ini index dff7147df02..7655af01c3e 100644 --- a/configs/sim/axis/ngcgui/ngcgui_lathe.ini +++ b/configs/sim/axis/ngcgui/ngcgui_lathe.ini @@ -67,7 +67,6 @@ TASK = milltask CYCLE_TIME = 0.001 [HAL] -HALUI = halui HALFILE = LIB:basic_sim.tcl [TRAJ] diff --git a/configs/sim/axis/ngcgui/ngcgui_simple.ini b/configs/sim/axis/ngcgui/ngcgui_simple.ini index ccb896d7e1f..95a47a195f3 100644 --- a/configs/sim/axis/ngcgui/ngcgui_simple.ini +++ b/configs/sim/axis/ngcgui/ngcgui_simple.ini @@ -68,7 +68,6 @@ TASK = milltask CYCLE_TIME = 0.001 [HAL] -HALUI = halui HALFILE = LIB:basic_sim.tcl [TRAJ] diff --git a/configs/sim/axis/ngcgui/pyngcgui_axis.ini b/configs/sim/axis/ngcgui/pyngcgui_axis.ini index 8cab0e77f10..3388435615d 100644 --- a/configs/sim/axis/ngcgui/pyngcgui_axis.ini +++ b/configs/sim/axis/ngcgui/pyngcgui_axis.ini @@ -82,7 +82,6 @@ TASK = milltask CYCLE_TIME = 0.001 [HAL] -HALUI = halui HALFILE = LIB:basic_sim.tcl [TRAJ] diff --git a/configs/sim/axis/pentapod/pentapod.ini b/configs/sim/axis/pentapod/pentapod.ini index 943a62c0c2d..0f91e195476 100644 --- a/configs/sim/axis/pentapod/pentapod.ini +++ b/configs/sim/axis/pentapod/pentapod.ini @@ -42,7 +42,6 @@ TASK = milltask CYCLE_TIME = 0.010 [HAL] -HALUI = halui HALFILE = LIB:basic_sim.tcl HALFILE = kinematics.hal POSTGUI_HALFILE = pentapod_postgui.hal diff --git a/configs/sim/axis/plasma/imperial.ini b/configs/sim/axis/plasma/imperial.ini index a86417ab27d..3b2d1092fdb 100644 --- a/configs/sim/axis/plasma/imperial.ini +++ b/configs/sim/axis/plasma/imperial.ini @@ -20,7 +20,6 @@ TWOPASS = ON HALFILE = plasmac2/lib/sim/sim_stepgen.tcl HALFILE = qtplasmac_comp.hal HALFILE = custom.hal -HALUI = halui [DISPLAY] DISPLAY = axis diff --git a/configs/sim/axis/plasma/metric.ini b/configs/sim/axis/plasma/metric.ini index d9d7d8ad745..a3b1d0e91eb 100644 --- a/configs/sim/axis/plasma/metric.ini +++ b/configs/sim/axis/plasma/metric.ini @@ -20,7 +20,6 @@ TWOPASS = ON HALFILE = plasmac2/lib/sim/sim_stepgen.tcl HALFILE = qtplasmac_comp.hal HALFILE = custom.hal -HALUI = halui [DISPLAY] DISPLAY = axis diff --git a/configs/sim/axis/profile_axis.ini b/configs/sim/axis/profile_axis.ini index e43ef4f7946..03cea494693 100644 --- a/configs/sim/axis/profile_axis.ini +++ b/configs/sim/axis/profile_axis.ini @@ -42,7 +42,6 @@ TASK = milltask CYCLE_TIME = 0.001 [HAL] - HALUI = halui HALFILE = LIB:basic_sim.tcl [TRAJ] diff --git a/configs/sim/axis/qtvcp/qtvcp_tab.ini b/configs/sim/axis/qtvcp/qtvcp_tab.ini index 7822089cb27..edf508783a0 100644 --- a/configs/sim/axis/qtvcp/qtvcp_tab.ini +++ b/configs/sim/axis/qtvcp/qtvcp_tab.ini @@ -51,7 +51,6 @@ TASK = milltask CYCLE_TIME = 0.001 [HAL] -HALUI = halui HALFILE = LIB:basic_sim.tcl [TRAJ] diff --git a/configs/sim/axis/qtvcp/qtvismach_tab.ini b/configs/sim/axis/qtvcp/qtvismach_tab.ini index 561c9b4c2a2..f00dc83969f 100644 --- a/configs/sim/axis/qtvcp/qtvismach_tab.ini +++ b/configs/sim/axis/qtvcp/qtvismach_tab.ini @@ -45,7 +45,6 @@ TASK = milltask CYCLE_TIME = 0.001 [HAL] -HALUI = halui HALFILE = LIB:basic_sim.tcl [TRAJ] diff --git a/configs/sim/axis/random_tc.ini b/configs/sim/axis/random_tc.ini index 442449ee371..2c1bd8f1b55 100644 --- a/configs/sim/axis/random_tc.ini +++ b/configs/sim/axis/random_tc.ini @@ -42,7 +42,6 @@ TASK = milltask CYCLE_TIME = 0.001 [HAL] - HALUI = halui HALFILE = LIB:basic_sim.tcl [TRAJ] diff --git a/configs/sim/axis/remap/cycle/cycle.ini b/configs/sim/axis/remap/cycle/cycle.ini index 6f3ebe6e5de..dcfe73aba97 100644 --- a/configs/sim/axis/remap/cycle/cycle.ini +++ b/configs/sim/axis/remap/cycle/cycle.ini @@ -50,7 +50,6 @@ TASK = milltask CYCLE_TIME = 0.001 [HAL] - HALUI = halui HALFILE = LIB:basic_sim.tcl HALFILE = locking_indexer.hal diff --git a/configs/sim/axis/remap/extend-builtins/extend-builtins.ini b/configs/sim/axis/remap/extend-builtins/extend-builtins.ini index 67634a009a1..3e2ff851f2a 100644 --- a/configs/sim/axis/remap/extend-builtins/extend-builtins.ini +++ b/configs/sim/axis/remap/extend-builtins/extend-builtins.ini @@ -83,7 +83,6 @@ TASK = milltask CYCLE_TIME = 0.001 [HAL] -HALUI = halui HALFILE = LIB:basic_sim.tcl POSTGUI_HALFILE = gladevcp.hal diff --git a/configs/sim/axis/remap/getting-started/demo.ini b/configs/sim/axis/remap/getting-started/demo.ini index e2e7ac32dc0..baf1cf305e9 100644 --- a/configs/sim/axis/remap/getting-started/demo.ini +++ b/configs/sim/axis/remap/getting-started/demo.ini @@ -132,7 +132,6 @@ TASK = milltask CYCLE_TIME = 0.001 [HAL] -HALUI = halui HALFILE = LIB:basic_sim.tcl [TRAJ] diff --git a/configs/sim/axis/remap/manual-toolchange-with-tool-length-switch/manualtoolchange.ini b/configs/sim/axis/remap/manual-toolchange-with-tool-length-switch/manualtoolchange.ini index 20fc4388e68..483ac90d5e1 100644 --- a/configs/sim/axis/remap/manual-toolchange-with-tool-length-switch/manualtoolchange.ini +++ b/configs/sim/axis/remap/manual-toolchange-with-tool-length-switch/manualtoolchange.ini @@ -56,7 +56,6 @@ TASK = milltask CYCLE_TIME = 0.001 [HAL] -HALUI = halui HALFILE = LIB:basic_sim.tcl POSTGUI_HALFILE= gladevcp.hal diff --git a/configs/sim/axis/remap/rack-toolchange/racktoolchange.ini b/configs/sim/axis/remap/rack-toolchange/racktoolchange.ini index 659bda067c3..dd1b7c86721 100644 --- a/configs/sim/axis/remap/rack-toolchange/racktoolchange.ini +++ b/configs/sim/axis/remap/rack-toolchange/racktoolchange.ini @@ -54,7 +54,6 @@ TASK = milltask CYCLE_TIME = 0.001 [HAL] -HALUI = halui HALFILE = LIB:basic_sim.tcl HALFILE = racktoolchange.hal POSTGUI_HALFILE= gladevcp.hal diff --git a/configs/sim/axis/remap/stop-lookahead/demo.ini b/configs/sim/axis/remap/stop-lookahead/demo.ini index 43aade97169..91d1c790b46 100644 --- a/configs/sim/axis/remap/stop-lookahead/demo.ini +++ b/configs/sim/axis/remap/stop-lookahead/demo.ini @@ -50,7 +50,6 @@ TASK = milltask CYCLE_TIME = 0.001 [HAL] -HALUI = halui HALFILE = LIB:basic_sim.tcl [TRAJ] diff --git a/configs/sim/axis/rose_engine/rose_engine.ini b/configs/sim/axis/rose_engine/rose_engine.ini index 7ad0172a7bd..1fbddfe4df9 100644 --- a/configs/sim/axis/rose_engine/rose_engine.ini +++ b/configs/sim/axis/rose_engine/rose_engine.ini @@ -1,7 +1,6 @@ [APPLICATIONS] APP = halshow rose_engine.halshow [HAL] -HALUI = halui HALFILE = LIB:basic_sim.tcl [TRAJ] diff --git a/configs/sim/axis/spindle_orient/orient.ini b/configs/sim/axis/spindle_orient/orient.ini index 148bf9935e5..7c281375fbb 100644 --- a/configs/sim/axis/spindle_orient/orient.ini +++ b/configs/sim/axis/spindle_orient/orient.ini @@ -46,7 +46,6 @@ TASK = milltask CYCLE_TIME = 0.001 [HAL] -HALUI = halui HALFILE = core_sim.hal HALFILE = axis_manualtoolchange.hal HALFILE = simulated_home.hal diff --git a/configs/sim/axis/twopass/twopass.ini b/configs/sim/axis/twopass/twopass.ini index b944fe09c1e..fa136a0fa74 100644 --- a/configs/sim/axis/twopass/twopass.ini +++ b/configs/sim/axis/twopass/twopass.ini @@ -43,7 +43,6 @@ TASK = milltask CYCLE_TIME = 0.001 [HAL] -HALUI = halui # options available are: on,verbose,nodelete TWOPASS = on HALFILE = core_sim.hal diff --git a/configs/sim/axis/vismach/3axis-tutorial/3axis-tutorial.ini b/configs/sim/axis/vismach/3axis-tutorial/3axis-tutorial.ini index 7e2dfcc4d1f..ead951a340c 100644 --- a/configs/sim/axis/vismach/3axis-tutorial/3axis-tutorial.ini +++ b/configs/sim/axis/vismach/3axis-tutorial/3axis-tutorial.ini @@ -112,8 +112,6 @@ HALFILE = 3axis-tutorial.hal # AXIS at this time (only AXIS creates a HAL component of its own) #POSTGUI_HALFILE = test_postgui.hal -HALUI = halui - # Trajectory planner section -------------------------------------------------- [HALUI] diff --git a/configs/sim/axis/vismach/5axis/bridgemill/5axis.ini b/configs/sim/axis/vismach/5axis/bridgemill/5axis.ini index 38e706fac22..2707f631b70 100644 --- a/configs/sim/axis/vismach/5axis/bridgemill/5axis.ini +++ b/configs/sim/axis/vismach/5axis/bridgemill/5axis.ini @@ -38,7 +38,6 @@ SERVO_PERIOD = 1000000 CYCLE_TIME = 0.010 [HAL] - HALUI = halui HALFILE = LIB:basic_sim.tcl HALFILE = 5axisgui.hal POSTGUI_HALFILE = 5axis_postgui.hal diff --git a/configs/sim/axis/vismach/5axis/max5/max5kins.ini b/configs/sim/axis/vismach/5axis/max5/max5kins.ini index b2d77aaf046..957798018a6 100644 --- a/configs/sim/axis/vismach/5axis/max5/max5kins.ini +++ b/configs/sim/axis/vismach/5axis/max5/max5kins.ini @@ -6,7 +6,6 @@ JOINTS = 6 [HAL] HALFILE = max5kins.hal -HALUI = halui [EMC] VERSION = 1.1 diff --git a/configs/sim/axis/vismach/5axis/max5/max5triv.ini b/configs/sim/axis/vismach/5axis/max5/max5triv.ini index 005c3627ad2..9c466209942 100644 --- a/configs/sim/axis/vismach/5axis/max5/max5triv.ini +++ b/configs/sim/axis/vismach/5axis/max5/max5triv.ini @@ -6,7 +6,6 @@ JOINTS = 6 [HAL] HALFILE = max5triv.hal -HALUI = halui [EMC] VERSION = 1.1 diff --git a/configs/sim/axis/vismach/5axis/table-dual-rotary/xyzab-tdr.ini b/configs/sim/axis/vismach/5axis/table-dual-rotary/xyzab-tdr.ini index bd6dc79e82a..d526e341f63 100644 --- a/configs/sim/axis/vismach/5axis/table-dual-rotary/xyzab-tdr.ini +++ b/configs/sim/axis/vismach/5axis/table-dual-rotary/xyzab-tdr.ini @@ -32,7 +32,6 @@ KINEMATICS = xyzab_tdr_kins JOINTS = 5 [HAL] - HALUI = halui HALFILE = LIB:basic_sim.tcl POSTGUI_HALFILE = xyzab-tdr-postgui.hal diff --git a/configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzac-trt.ini b/configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzac-trt.ini index 9c2bc00e33e..1436f780f3f 100644 --- a/configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzac-trt.ini +++ b/configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzac-trt.ini @@ -44,7 +44,6 @@ KINEMATICS = xyzac-trt-kins sparm=identityfirst JOINTS = 5 [HAL] - HALUI = halui HALFILE = LIB:basic_sim.tcl POSTGUI_HALFILE = switchkins_postgui.hal diff --git a/configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzbc-trt.ini b/configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzbc-trt.ini index 45d780a251c..278b8aa1262 100644 --- a/configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzbc-trt.ini +++ b/configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzbc-trt.ini @@ -44,7 +44,6 @@ KINEMATICS = xyzbc-trt-kins sparm=identityfirst JOINTS = 5 [HAL] - HALUI = halui HALFILE = LIB:basic_sim.tcl POSTGUI_HALFILE = switchkins_postgui.hal diff --git a/configs/sim/axis/vismach/5axis/table-rotary_spindle-rotary-nutating/xyzacb-trsrn_twp/xyzacb-trsrn.ini b/configs/sim/axis/vismach/5axis/table-rotary_spindle-rotary-nutating/xyzacb-trsrn_twp/xyzacb-trsrn.ini index 2be585e6ef8..c9bcb54ce49 100644 --- a/configs/sim/axis/vismach/5axis/table-rotary_spindle-rotary-nutating/xyzacb-trsrn_twp/xyzacb-trsrn.ini +++ b/configs/sim/axis/vismach/5axis/table-rotary_spindle-rotary-nutating/xyzacb-trsrn_twp/xyzacb-trsrn.ini @@ -70,7 +70,6 @@ PRIMARY = C SECONDARY = B [HAL] - HALUI = halui HALFILE = LIB:basic_sim.tcl POSTGUI_HALFILE = xyzacb-trsrn_postgui.hal diff --git a/configs/sim/axis/vismach/5axis/table-rotary_spindle-rotary-nutating/xyzbca-trsrn_twp/xyzbca-trsrn.ini b/configs/sim/axis/vismach/5axis/table-rotary_spindle-rotary-nutating/xyzbca-trsrn_twp/xyzbca-trsrn.ini index d3032855aee..ef3e476225d 100644 --- a/configs/sim/axis/vismach/5axis/table-rotary_spindle-rotary-nutating/xyzbca-trsrn_twp/xyzbca-trsrn.ini +++ b/configs/sim/axis/vismach/5axis/table-rotary_spindle-rotary-nutating/xyzbca-trsrn_twp/xyzbca-trsrn.ini @@ -70,7 +70,6 @@ PRIMARY = C SECONDARY = A [HAL] - HALUI = halui HALFILE = LIB:basic_sim.tcl POSTGUI_HALFILE = xyzbca-trsrn_postgui.hal diff --git a/configs/sim/axis/vismach/VMC_toolchange/vmc_graycode.ini b/configs/sim/axis/vismach/VMC_toolchange/vmc_graycode.ini index 35ee95f4ab3..da6425d924c 100644 --- a/configs/sim/axis/vismach/VMC_toolchange/vmc_graycode.ini +++ b/configs/sim/axis/vismach/VMC_toolchange/vmc_graycode.ini @@ -30,7 +30,6 @@ TASK = milltask CYCLE_TIME = 0.010 [HAL] -HALUI = halui HALFILE = vmc.hal HALFILE = sim_vmc.hal HALFILE = spindle.hal diff --git a/configs/sim/axis/vismach/VMC_toolchange/vmc_index.ini b/configs/sim/axis/vismach/VMC_toolchange/vmc_index.ini index 323b7eab813..b4783e494e2 100644 --- a/configs/sim/axis/vismach/VMC_toolchange/vmc_index.ini +++ b/configs/sim/axis/vismach/VMC_toolchange/vmc_index.ini @@ -30,7 +30,6 @@ TASK = milltask CYCLE_TIME = 0.010 [HAL] -HALUI = halui HALFILE = vmc.hal HALFILE = sim_vmc.hal HALFILE = spindle.hal diff --git a/configs/sim/axis/vismach/delta/ldelta.ini b/configs/sim/axis/vismach/delta/ldelta.ini index a6c95c302fa..fb1393a589f 100644 --- a/configs/sim/axis/vismach/delta/ldelta.ini +++ b/configs/sim/axis/vismach/delta/ldelta.ini @@ -46,7 +46,6 @@ SERVO_PERIOD = 1000000 [HAL] HALFILE = sim_ldelta.hal HALFILE = axis_manualtoolchange.hal -HALUI = halui [TRAJ] COORDINATES = X Y Z A diff --git a/configs/sim/axis/vismach/delta/ldelta_demo.ini b/configs/sim/axis/vismach/delta/ldelta_demo.ini index 8c72659967b..e45ac7d05d6 100644 --- a/configs/sim/axis/vismach/delta/ldelta_demo.ini +++ b/configs/sim/axis/vismach/delta/ldelta_demo.ini @@ -46,7 +46,6 @@ SERVO_PERIOD = 1000000 [HAL] HALFILE = sim_ldelta.hal HALFILE = axis_manualtoolchange.hal -HALUI = halui HALCMD = setp joint.0.jog-enable 1 HALCMD = setp joint.1.jog-enable 1 diff --git a/configs/sim/axis/vismach/delta/rdelta.ini b/configs/sim/axis/vismach/delta/rdelta.ini index e40defb1c41..17d83eaafc1 100644 --- a/configs/sim/axis/vismach/delta/rdelta.ini +++ b/configs/sim/axis/vismach/delta/rdelta.ini @@ -46,7 +46,6 @@ SERVO_PERIOD = 1000000 [HAL] HALFILE = sim_rdelta.hal HALFILE = axis_manualtoolchange.hal -HALUI = halui [TRAJ] COORDINATES = X Y Z A B C U V W diff --git a/configs/sim/axis/vismach/hbm/hbm.ini b/configs/sim/axis/vismach/hbm/hbm.ini index 231778a5009..ae108d96559 100644 --- a/configs/sim/axis/vismach/hbm/hbm.ini +++ b/configs/sim/axis/vismach/hbm/hbm.ini @@ -28,7 +28,6 @@ TASK = milltask CYCLE_TIME = 0.010 [HAL] -HALUI = halui HALFILE = hbm.hal [TRAJ] diff --git a/configs/sim/axis/vismach/hexapod-sim/hexapod.ini b/configs/sim/axis/vismach/hexapod-sim/hexapod.ini index f42a14799a0..65543c7a8bd 100644 --- a/configs/sim/axis/vismach/hexapod-sim/hexapod.ini +++ b/configs/sim/axis/vismach/hexapod-sim/hexapod.ini @@ -36,7 +36,6 @@ TASK = milltask CYCLE_TIME = 0.010 [HAL] -HALUI = halui HALFILE = LIB:basic_sim.tcl HALFILE = kinematics.hal HALCMD = loadusr -W ./hexagui.py diff --git a/configs/sim/axis/vismach/melfa-sim/melfa-sim-genser/melfa-sim-genser.ini b/configs/sim/axis/vismach/melfa-sim/melfa-sim-genser/melfa-sim-genser.ini index cfea9e01701..59221f236fb 100644 --- a/configs/sim/axis/vismach/melfa-sim/melfa-sim-genser/melfa-sim-genser.ini +++ b/configs/sim/axis/vismach/melfa-sim/melfa-sim-genser/melfa-sim-genser.ini @@ -8,7 +8,6 @@ KINEMATICS= genserkins JOINTS= 6 [HAL] -HALUI = halui HALFILE = LIB:basic_sim.tcl HALFILE = melfa_mdh.hal HALCMD = loadusr -W ../melfagui.py diff --git a/configs/sim/axis/vismach/melfa-sim/melfa-sim-three21/melfa_321.ini b/configs/sim/axis/vismach/melfa-sim/melfa-sim-three21/melfa_321.ini index 5a8ba9d4787..495a214a855 100644 --- a/configs/sim/axis/vismach/melfa-sim/melfa-sim-three21/melfa_321.ini +++ b/configs/sim/axis/vismach/melfa-sim/melfa-sim-three21/melfa_321.ini @@ -8,7 +8,6 @@ KINEMATICS= three21kins JOINTS= 6 [HAL] -HALUI = halui HALFILE = LIB:basic_sim.tcl HALFILE = melfa_dh.hal HALCMD = loadusr -W ../melfagui.py diff --git a/configs/sim/axis/vismach/millturn/millturn.ini b/configs/sim/axis/vismach/millturn/millturn.ini index 575947d9dce..9d5ea62d3eb 100644 --- a/configs/sim/axis/vismach/millturn/millturn.ini +++ b/configs/sim/axis/vismach/millturn/millturn.ini @@ -11,7 +11,6 @@ KINEMATICS = millturn JOINTS= 4 [HAL] -HALUI = halui HALFILE = LIB:basic_sim.tcl HALFILE = millturn.hal POSTGUI_HALFILE = millturn-postgui.hal diff --git a/configs/sim/axis/vismach/puma/puma.ini b/configs/sim/axis/vismach/puma/puma.ini index 99c0fa33112..c9eee69634a 100644 --- a/configs/sim/axis/vismach/puma/puma.ini +++ b/configs/sim/axis/vismach/puma/puma.ini @@ -8,7 +8,6 @@ KINEMATICS = pumakins JOINTS = 6 [HAL] -HALUI = halui HALFILE = LIB:basic_sim.tcl HALFILE = puma_dh.hal HALCMD = loadusr -W ./pumagui.py diff --git a/configs/sim/axis/vismach/puma/puma560.ini b/configs/sim/axis/vismach/puma/puma560.ini index 046f5d118d5..31ca764725d 100644 --- a/configs/sim/axis/vismach/puma/puma560.ini +++ b/configs/sim/axis/vismach/puma/puma560.ini @@ -12,7 +12,6 @@ JOINTS= 6 KINEMATICS= genserkins [HAL] -HALUI = halui HALCMD = loadusr -W ./puma560gui.py HALFILE = LIB:basic_sim.tcl HALFILE = puma560_dh.hal diff --git a/configs/sim/axis/vismach/puma/puma560_uvw.ini b/configs/sim/axis/vismach/puma/puma560_uvw.ini index a6b9f8544e9..df96788061d 100644 --- a/configs/sim/axis/vismach/puma/puma560_uvw.ini +++ b/configs/sim/axis/vismach/puma/puma560_uvw.ini @@ -12,7 +12,6 @@ JOINTS= 9 KINEMATICS= genserkins [HAL] -HALUI = halui HALCMD = loadusr -W ./puma560gui.py HALFILE = LIB:basic_sim.tcl HALFILE = puma560_dh.hal diff --git a/configs/sim/axis/vismach/puma/puma_cube.ini b/configs/sim/axis/vismach/puma/puma_cube.ini index 8397ce3ea7a..d40a54428fc 100644 --- a/configs/sim/axis/vismach/puma/puma_cube.ini +++ b/configs/sim/axis/vismach/puma/puma_cube.ini @@ -99,7 +99,6 @@ TASK = milltask CYCLE_TIME = 0.010 [HAL] -HALUI = halui HALFILE = LIB:basic_sim.tcl HALFILE = puma_dh.hal HALCMD = loadusr -W ./pumagui.py diff --git a/configs/sim/axis/vismach/scara/scara.ini b/configs/sim/axis/vismach/scara/scara.ini index 23323fdc8bf..9daec89d7d5 100644 --- a/configs/sim/axis/vismach/scara/scara.ini +++ b/configs/sim/axis/vismach/scara/scara.ini @@ -55,7 +55,6 @@ JOINTS = 6 KINEMATICS = scarakins coordinates=xyzcab [HAL] -HALUI = halui HALFILE = LIB:basic_sim.tcl HALCMD = loadusr -W ./scaragui.py POSTGUI_HALFILE = scara_postgui.hal diff --git a/configs/sim/axis/wrapped_rotary/wrapped_rotary.ini b/configs/sim/axis/wrapped_rotary/wrapped_rotary.ini index 4d2bc2673ec..0c5d7c296c0 100644 --- a/configs/sim/axis/wrapped_rotary/wrapped_rotary.ini +++ b/configs/sim/axis/wrapped_rotary/wrapped_rotary.ini @@ -39,7 +39,6 @@ SERVO_PERIOD = 1000000 [HAL] HALFILE = wrapped_rotary.hal -HALUI = halui [KINS] KINEMATICS = trivkins coordinates=xyza kinstype=BOTH diff --git a/configs/sim/axis/xhc-hb04/xhc-hb04-layout1.ini b/configs/sim/axis/xhc-hb04/xhc-hb04-layout1.ini index f57619ca97a..65147e531cd 100644 --- a/configs/sim/axis/xhc-hb04/xhc-hb04-layout1.ini +++ b/configs/sim/axis/xhc-hb04/xhc-hb04-layout1.ini @@ -9,7 +9,6 @@ MACHINE = xhc-hb04 layout1 demo [HAL] HALFILE = LIB:basic_sim.tcl HALFILE = LIB:xhc-hb04.tcl -HALUI = halui [XHC_HB04_CONFIG] # specify layout = n for LIB:xhc-hb04-layout{n}.cfg files diff --git a/configs/sim/axis/xhc-hb04/xhc-hb04-layout2.ini b/configs/sim/axis/xhc-hb04/xhc-hb04-layout2.ini index eba145fc3fb..f64e9ce1441 100644 --- a/configs/sim/axis/xhc-hb04/xhc-hb04-layout2.ini +++ b/configs/sim/axis/xhc-hb04/xhc-hb04-layout2.ini @@ -9,7 +9,6 @@ MACHINE = xhc-hb04 layout2 demo [HAL] HALFILE = LIB:basic_sim.tcl HALFILE = LIB:xhc-hb04.tcl -HALUI = halui [XHC_HB04_CONFIG] # specify layout = n for LIB:xhc-hb04-layout{n}.cfg files diff --git a/configs/sim/axis/xhc-hb04/xhc-hb04-layout2_mm.ini b/configs/sim/axis/xhc-hb04/xhc-hb04-layout2_mm.ini index 820f965f002..3bf3077f039 100644 --- a/configs/sim/axis/xhc-hb04/xhc-hb04-layout2_mm.ini +++ b/configs/sim/axis/xhc-hb04/xhc-hb04-layout2_mm.ini @@ -7,7 +7,6 @@ VERSION = 1.1 MACHINE = xhc-hb04 layout2 mm demo [HAL] -HALUI = halui HALFILE = LIB:basic_sim.tcl HALFILE = LIB:xhc-hb04.tcl diff --git a/configs/sim/gmoccapy/6_axis.ini b/configs/sim/gmoccapy/6_axis.ini index 4a1a0179f8c..7431a17fc2e 100644 --- a/configs/sim/gmoccapy/6_axis.ini +++ b/configs/sim/gmoccapy/6_axis.ini @@ -59,7 +59,6 @@ TOOL_TABLE = tool.tbl TOOL_CHANGE_POSITION = 0 0 2 [HAL] -HALUI = halui HALFILE = core_sim_6.hal #HALFILE = simulated_home_9.hal diff --git a/configs/sim/gmoccapy/7_axis.ini b/configs/sim/gmoccapy/7_axis.ini index e5d25e7fddb..2f0186f8c1a 100644 --- a/configs/sim/gmoccapy/7_axis.ini +++ b/configs/sim/gmoccapy/7_axis.ini @@ -59,7 +59,6 @@ TOOL_TABLE = tool.tbl TOOL_CHANGE_POSITION = 0 0 2 [HAL] -HALUI = halui HALFILE = core_sim_7.hal #HALFILE = simulated_home_9.hal diff --git a/configs/sim/gmoccapy/7_axis_tool.ini b/configs/sim/gmoccapy/7_axis_tool.ini index 62c9b2578a3..71aa1abba3b 100644 --- a/configs/sim/gmoccapy/7_axis_tool.ini +++ b/configs/sim/gmoccapy/7_axis_tool.ini @@ -59,7 +59,6 @@ TOOL_TABLE = tool.tbl TOOL_CHANGE_POSITION = 0 0 2 [HAL] -HALUI = halui HALFILE = core_sim_7.hal #HALFILE = simulated_home_9.hal diff --git a/configs/sim/gmoccapy/8_axis.ini b/configs/sim/gmoccapy/8_axis.ini index bbfd5b65dde..19410a0c3b9 100644 --- a/configs/sim/gmoccapy/8_axis.ini +++ b/configs/sim/gmoccapy/8_axis.ini @@ -62,7 +62,6 @@ TOOL_TABLE = tool.tbl TOOL_CHANGE_POSITION = 0 0 2 [HAL] -HALUI = halui HALFILE = core_sim_8.hal # Single file that is executed after the GUI has started. diff --git a/configs/sim/gmoccapy/9_axis.ini b/configs/sim/gmoccapy/9_axis.ini index 33fac9bce8d..61791bbb4a1 100644 --- a/configs/sim/gmoccapy/9_axis.ini +++ b/configs/sim/gmoccapy/9_axis.ini @@ -59,7 +59,6 @@ TOOL_TABLE = tool.tbl TOOL_CHANGE_POSITION = 0 0 2 [HAL] -HALUI = halui HALFILE = core_sim_9.hal #HALFILE = simulated_home_9.hal diff --git a/configs/sim/gmoccapy/gmoccapy.ini b/configs/sim/gmoccapy/gmoccapy.ini index 217ae378d61..6b64f9bc4a4 100644 --- a/configs/sim/gmoccapy/gmoccapy.ini +++ b/configs/sim/gmoccapy/gmoccapy.ini @@ -96,8 +96,6 @@ HALFILE = simulated_home.hal # Single file that is executed after the GUI has started. POSTGUI_HALFILE = gmoccapy_postgui.hal -HALUI = halui - # Trajectory planner section -------------------------------------------------- [HALUI] #No Content diff --git a/configs/sim/gmoccapy/gmoccapy_4_axis.ini b/configs/sim/gmoccapy/gmoccapy_4_axis.ini index 34e0bd18085..0d34ad8171e 100644 --- a/configs/sim/gmoccapy/gmoccapy_4_axis.ini +++ b/configs/sim/gmoccapy/gmoccapy_4_axis.ini @@ -69,8 +69,6 @@ HALFILE = simulated_home.hal # Single file that is executed after the GUI has started. POSTGUI_HALFILE = gmoccapy_postgui.hal -HALUI = halui - # Trajectory planner section -------------------------------------------------- [HALUI] #No Content diff --git a/configs/sim/gmoccapy/gmoccapy_800x600.ini b/configs/sim/gmoccapy/gmoccapy_800x600.ini index 8c2f29bdca9..95be38c3068 100644 --- a/configs/sim/gmoccapy/gmoccapy_800x600.ini +++ b/configs/sim/gmoccapy/gmoccapy_800x600.ini @@ -87,8 +87,6 @@ HALFILE = simulated_home.hal # Single file that is executed after the GUI has started. POSTGUI_HALFILE = gmoccapy_postgui.hal -HALUI = halui - # Trajectory planner section -------------------------------------------------- [HALUI] #No Content diff --git a/configs/sim/gmoccapy/gmoccapy_XYZAB.ini b/configs/sim/gmoccapy/gmoccapy_XYZAB.ini index 75c0997fcd4..d69347ad008 100644 --- a/configs/sim/gmoccapy/gmoccapy_XYZAB.ini +++ b/configs/sim/gmoccapy/gmoccapy_XYZAB.ini @@ -99,8 +99,6 @@ HALFILE = simulated_home.hal # Single file that is executed after the GUI has started. POSTGUI_HALFILE = gmoccapy_postgui.hal -HALUI = halui - # Trajectory planner section -------------------------------------------------- [HALUI] #No Content diff --git a/configs/sim/gmoccapy/gmoccapy_XYZAC.ini b/configs/sim/gmoccapy/gmoccapy_XYZAC.ini index 1b9348e4742..c67346b2dc6 100644 --- a/configs/sim/gmoccapy/gmoccapy_XYZAC.ini +++ b/configs/sim/gmoccapy/gmoccapy_XYZAC.ini @@ -88,8 +88,6 @@ HALFILE = simulated_home.hal # Single file that is executed after the GUI has started. POSTGUI_HALFILE = gmoccapy_postgui.hal -HALUI = halui - # Trajectory planner section -------------------------------------------------- [HALUI] #No Content diff --git a/configs/sim/gmoccapy/gmoccapy_XYZCW.ini b/configs/sim/gmoccapy/gmoccapy_XYZCW.ini index 9fbb984d4f7..74c66acb95c 100644 --- a/configs/sim/gmoccapy/gmoccapy_XYZCW.ini +++ b/configs/sim/gmoccapy/gmoccapy_XYZCW.ini @@ -84,8 +84,6 @@ HALFILE = simulated_home.hal # Single file that is executed after the GUI has started. POSTGUI_HALFILE = gmoccapy_postgui.hal -HALUI = halui - # Trajectory planner section -------------------------------------------------- [HALUI] #No Content diff --git a/configs/sim/gmoccapy/gmoccapy_blockdelete.ini b/configs/sim/gmoccapy/gmoccapy_blockdelete.ini index 4043aa966d9..bfb3dbd7e86 100644 --- a/configs/sim/gmoccapy/gmoccapy_blockdelete.ini +++ b/configs/sim/gmoccapy/gmoccapy_blockdelete.ini @@ -85,8 +85,6 @@ HALFILE = simulated_home.hal # Single file that is executed after the GUI has started. POSTGUI_HALFILE = gmoccapy_postgui.hal -HALUI = halui - # Trajectory planner section -------------------------------------------------- [HALUI] #No Content diff --git a/configs/sim/gmoccapy/gmoccapy_left_panel.ini b/configs/sim/gmoccapy/gmoccapy_left_panel.ini index 52c9d8b3a30..47e096e3f5e 100644 --- a/configs/sim/gmoccapy/gmoccapy_left_panel.ini +++ b/configs/sim/gmoccapy/gmoccapy_left_panel.ini @@ -78,8 +78,6 @@ HALFILE = simulated_home.hal # Single file that is executed after the GUI has started. POSTGUI_HALFILE = gmoccapy_postgui.hal -HALUI = halui - # Trajectory planner section -------------------------------------------------- [HALUI] #No Content diff --git a/configs/sim/gmoccapy/gmoccapy_messages.ini b/configs/sim/gmoccapy/gmoccapy_messages.ini index 705f051028f..1cf69d4c015 100644 --- a/configs/sim/gmoccapy/gmoccapy_messages.ini +++ b/configs/sim/gmoccapy/gmoccapy_messages.ini @@ -111,8 +111,6 @@ HALFILE = simulated_home.hal # Single file that is executed after the GUI has started. POSTGUI_HALFILE = gmoccapy_postgui.hal -HALUI = halui - # Trajectory planner section -------------------------------------------------- [HALUI] #No Content diff --git a/configs/sim/gmoccapy/gmoccapy_pedant.ini b/configs/sim/gmoccapy/gmoccapy_pedant.ini index 8ca75a3fd8c..2f13186e4f1 100644 --- a/configs/sim/gmoccapy/gmoccapy_pedant.ini +++ b/configs/sim/gmoccapy/gmoccapy_pedant.ini @@ -79,8 +79,6 @@ HALFILE = simulated_home.hal # Single file that is executed after the GUI has started. POSTGUI_HALFILE = gmoccapy_postgui.hal -HALUI = halui - # Trajectory planner section -------------------------------------------------- [HALUI] #No Content diff --git a/configs/sim/gmoccapy/gmoccapy_pyngcgui.ini b/configs/sim/gmoccapy/gmoccapy_pyngcgui.ini index 6bfc5c446a9..dffaee23f46 100644 --- a/configs/sim/gmoccapy/gmoccapy_pyngcgui.ini +++ b/configs/sim/gmoccapy/gmoccapy_pyngcgui.ini @@ -114,8 +114,6 @@ HALFILE = simulated_home.hal # Single file that is executed after the GUI has started. POSTGUI_HALFILE = gmoccapy_postgui.hal -HALUI = halui - # Trajectory planner section -------------------------------------------------- [HALUI] #No Content diff --git a/configs/sim/gmoccapy/gmoccapy_pyngcgui_gcmc.ini b/configs/sim/gmoccapy/gmoccapy_pyngcgui_gcmc.ini index de4a5e50836..303fe9156ea 100644 --- a/configs/sim/gmoccapy/gmoccapy_pyngcgui_gcmc.ini +++ b/configs/sim/gmoccapy/gmoccapy_pyngcgui_gcmc.ini @@ -115,8 +115,6 @@ HALFILE = simulated_home.hal # Single file that is executed after the GUI has started. POSTGUI_HALFILE = gmoccapy_postgui.hal -HALUI = halui - # Trajectory planner section -------------------------------------------------- [HALUI] #No Content diff --git a/configs/sim/gmoccapy/gmoccapy_qt_messages.ini b/configs/sim/gmoccapy/gmoccapy_qt_messages.ini index d15480633da..e77de499b01 100644 --- a/configs/sim/gmoccapy/gmoccapy_qt_messages.ini +++ b/configs/sim/gmoccapy/gmoccapy_qt_messages.ini @@ -109,8 +109,6 @@ POSTGUI_HALFILE = gmoccapy_postgui.hal POSTGUI_HALCMD = loadusr -Wn ini_dialogs qtvcp --ini gmoccapy_qt_messages.ini -q ini_dialogs POSTGUI_HALCMD = setp ini_dialogs.VFD 1 -HALUI = halui - # Trajectory planner section -------------------------------------------------- [HALUI] #No Content diff --git a/configs/sim/gmoccapy/gmoccapy_right_panel.ini b/configs/sim/gmoccapy/gmoccapy_right_panel.ini index 62213d687d5..35130499f47 100644 --- a/configs/sim/gmoccapy/gmoccapy_right_panel.ini +++ b/configs/sim/gmoccapy/gmoccapy_right_panel.ini @@ -74,8 +74,6 @@ HALFILE = simulated_home.hal # Single file that is executed after the GUI has started. POSTGUI_HALFILE = gmoccapy_postgui.hal -HALUI = halui - # Trajectory planner section -------------------------------------------------- [HALUI] #No Content diff --git a/configs/sim/gmoccapy/gmoccapy_sim_hardware_button.ini b/configs/sim/gmoccapy/gmoccapy_sim_hardware_button.ini index 704e64d796d..6f5f225cd5b 100644 --- a/configs/sim/gmoccapy/gmoccapy_sim_hardware_button.ini +++ b/configs/sim/gmoccapy/gmoccapy_sim_hardware_button.ini @@ -82,8 +82,6 @@ HALFILE = simulated_home.hal # Single file that is executed after the GUI has started. POSTGUI_HALFILE = gmoccapy_postgui.hal -HALUI = halui - # Trajectory planner section -------------------------------------------------- [HALUI] #No Content diff --git a/configs/sim/gmoccapy/gmoccapy_tool_sensor.ini b/configs/sim/gmoccapy/gmoccapy_tool_sensor.ini index 37daf107549..6f607735a8d 100644 --- a/configs/sim/gmoccapy/gmoccapy_tool_sensor.ini +++ b/configs/sim/gmoccapy/gmoccapy_tool_sensor.ini @@ -104,8 +104,6 @@ HALFILE = simulated_home.hal # Single file that is executed after the GUI has started. POSTGUI_HALFILE = gmoccapy_postgui.hal -HALUI = halui - # Trajectory planner section -------------------------------------------------- [HALUI] #No Content diff --git a/configs/sim/gmoccapy/gmoccapy_with_user_tabs.ini b/configs/sim/gmoccapy/gmoccapy_with_user_tabs.ini index 9ac53efa54b..2a186a7145d 100644 --- a/configs/sim/gmoccapy/gmoccapy_with_user_tabs.ini +++ b/configs/sim/gmoccapy/gmoccapy_with_user_tabs.ini @@ -99,8 +99,6 @@ HALFILE = simulated_home.hal # Single file that is executed after the GUI has started. POSTGUI_HALFILE = gmoccapy_postgui.hal -HALUI = halui - # Trajectory planner section -------------------------------------------------- [HALUI] #No Content diff --git a/configs/sim/gmoccapy/lathe_configs/lathe.ini b/configs/sim/gmoccapy/lathe_configs/lathe.ini index 71da9ff283d..4df6ba4e8d6 100644 --- a/configs/sim/gmoccapy/lathe_configs/lathe.ini +++ b/configs/sim/gmoccapy/lathe_configs/lathe.ini @@ -76,8 +76,6 @@ HALFILE = simulated_home_lathe.hal # Single file that is executed after the GUI has started. POSTGUI_HALFILE = gmoccapy_postgui.hal -HALUI = halui - # Trajectory planner section -------------------------------------------------- [HALUI] #No Content diff --git a/configs/sim/gmoccapy/lathe_configs/lathe_C.ini b/configs/sim/gmoccapy/lathe_configs/lathe_C.ini index b47ec8d569d..96c75824987 100644 --- a/configs/sim/gmoccapy/lathe_configs/lathe_C.ini +++ b/configs/sim/gmoccapy/lathe_configs/lathe_C.ini @@ -77,8 +77,6 @@ HALFILE = simulated_home_lathe.hal # Single file that is executed after the GUI has started. POSTGUI_HALFILE = gmoccapy_postgui.hal -HALUI = halui - # Trajectory planner section -------------------------------------------------- [HALUI] #No Content diff --git a/configs/sim/gmoccapy/lathe_configs/lathe_CW.ini b/configs/sim/gmoccapy/lathe_configs/lathe_CW.ini index e5bd6640c33..05a775972f8 100644 --- a/configs/sim/gmoccapy/lathe_configs/lathe_CW.ini +++ b/configs/sim/gmoccapy/lathe_configs/lathe_CW.ini @@ -77,8 +77,6 @@ HALFILE = simulated_home_lathe.hal # Single file that is executed after the GUI has started. POSTGUI_HALFILE = gmoccapy_postgui.hal -HALUI = halui - # Trajectory planner section -------------------------------------------------- [HALUI] #No Content diff --git a/configs/sim/gmoccapy/lathe_configs/lathe_backtool.ini b/configs/sim/gmoccapy/lathe_configs/lathe_backtool.ini index b49ae755431..6859eb479e8 100644 --- a/configs/sim/gmoccapy/lathe_configs/lathe_backtool.ini +++ b/configs/sim/gmoccapy/lathe_configs/lathe_backtool.ini @@ -77,8 +77,6 @@ HALFILE = simulated_home_lathe.hal # Single file that is executed after the GUI has started. POSTGUI_HALFILE = gmoccapy_postgui.hal -HALUI = halui - # Trajectory planner section -------------------------------------------------- [HALUI] #No Content diff --git a/configs/sim/gmoccapy/lathe_configs/lathe_imperial.ini b/configs/sim/gmoccapy/lathe_configs/lathe_imperial.ini index e95ffdd29ac..1b600a31078 100644 --- a/configs/sim/gmoccapy/lathe_configs/lathe_imperial.ini +++ b/configs/sim/gmoccapy/lathe_configs/lathe_imperial.ini @@ -77,8 +77,6 @@ HALFILE = simulated_home_lathe.hal # Single file that is executed after the GUI has started. POSTGUI_HALFILE = gmoccapy_postgui.hal -HALUI = halui - # Trajectory planner section -------------------------------------------------- [HALUI] #No Content diff --git a/configs/sim/gmoccapy/lathe_configs/lathe_macros.ini b/configs/sim/gmoccapy/lathe_configs/lathe_macros.ini index c3a49f61433..198ccbb5995 100644 --- a/configs/sim/gmoccapy/lathe_configs/lathe_macros.ini +++ b/configs/sim/gmoccapy/lathe_configs/lathe_macros.ini @@ -82,8 +82,6 @@ HALFILE = simulated_home_lathe.hal # Single file that is executed after the GUI has started. POSTGUI_HALFILE = ./gmoccapy_postgui.hal -HALUI = halui - # Trajectory planner section -------------------------------------------------- [HALUI] #No Content diff --git a/configs/sim/gmoccapy/non_trivial_kinematics/Gantry/gantry_mm.ini b/configs/sim/gmoccapy/non_trivial_kinematics/Gantry/gantry_mm.ini index 979e8775798..f5a577d52e8 100644 --- a/configs/sim/gmoccapy/non_trivial_kinematics/Gantry/gantry_mm.ini +++ b/configs/sim/gmoccapy/non_trivial_kinematics/Gantry/gantry_mm.ini @@ -54,7 +54,6 @@ SERVO_PERIOD = 1000000 [HAL] HALFILE = gantry_mm.hal -HALUI = halui # Single file that is executed after the GUI has started. #POSTGUI_HALFILE = gmoccapy_postgui.hal diff --git a/configs/sim/gmoccapy/non_trivial_kinematics/scara/scara.ini b/configs/sim/gmoccapy/non_trivial_kinematics/scara/scara.ini index 37b2ad9a241..9120639155a 100644 --- a/configs/sim/gmoccapy/non_trivial_kinematics/scara/scara.ini +++ b/configs/sim/gmoccapy/non_trivial_kinematics/scara/scara.ini @@ -44,7 +44,6 @@ SERVO_PERIOD = 1000000 TRAJ_PERIOD = 10000000 [HAL] -HALUI = halui HALFILE = scara_sim_4.hal POSTGUI_HALFILE = postgui.hal diff --git a/configs/sim/gmoccapy/non_trivial_kinematics/table-rotary-tilting/xyzac-trt.ini b/configs/sim/gmoccapy/non_trivial_kinematics/table-rotary-tilting/xyzac-trt.ini index ad1ea4a3877..50f5888fc8a 100644 --- a/configs/sim/gmoccapy/non_trivial_kinematics/table-rotary-tilting/xyzac-trt.ini +++ b/configs/sim/gmoccapy/non_trivial_kinematics/table-rotary-tilting/xyzac-trt.ini @@ -31,7 +31,6 @@ TOPLEVEL = ../../python/toplevel.py LOG_LEVEL = 0 [HAL] -HALUI = halui HALFILE = LIB:basic_sim.tcl -no_use_hal_manualtoolchange # vismach xyzac-trt-gui items diff --git a/configs/sim/gmoccapy/plasma_config/gmoccapy_plasma.ini b/configs/sim/gmoccapy/plasma_config/gmoccapy_plasma.ini index 5e0dffb5895..6037033e80b 100644 --- a/configs/sim/gmoccapy/plasma_config/gmoccapy_plasma.ini +++ b/configs/sim/gmoccapy/plasma_config/gmoccapy_plasma.ini @@ -79,8 +79,6 @@ HALFILE = simulated_home.hal # Single file that is executed after the GUI has started. POSTGUI_HALFILE = gmoccapy_postgui.hal -HALUI = halui - # Trajectory planner section -------------------------------------------------- [HALUI] #No Content diff --git a/configs/sim/gscreen/gscreen.ini b/configs/sim/gscreen/gscreen.ini index 42b90a1c5f5..b1232f673dc 100644 --- a/configs/sim/gscreen/gscreen.ini +++ b/configs/sim/gscreen/gscreen.ini @@ -132,8 +132,6 @@ HALFILE = simulated_home.hal # AXIS at this time (only AXIS creates a HAL component of its own) # POSTGUI_HALFILE = test_postgui.hal -HALUI = halui - # Trajectory planner section -------------------------------------------------- [HALUI] #No Content diff --git a/configs/sim/gscreen/gscreen_custom/9axis.ini b/configs/sim/gscreen/gscreen_custom/9axis.ini index 89ff1072083..7f88fa8c9d3 100644 --- a/configs/sim/gscreen/gscreen_custom/9axis.ini +++ b/configs/sim/gscreen/gscreen_custom/9axis.ini @@ -102,8 +102,6 @@ HALFILE = locking_indexer.hal # Single file that is executed after the GUI has started. #POSTGUI_HALFILE = test_postgui.hal -HALUI = halui - # Trajectory planner section -------------------------------------------------- [HALUI] #No Content diff --git a/configs/sim/gscreen/gscreen_custom/gaxis_no_plot.ini b/configs/sim/gscreen/gscreen_custom/gaxis_no_plot.ini index e91dd76845b..b7f485284c9 100644 --- a/configs/sim/gscreen/gscreen_custom/gaxis_no_plot.ini +++ b/configs/sim/gscreen/gscreen_custom/gaxis_no_plot.ini @@ -99,8 +99,6 @@ HALFILE = simulated_home.hal # Single file that is executed after the GUI has started. POSTGUI_HALFILE = gaxis_postgui.hal -HALUI = halui - # Trajectory planner section -------------------------------------------------- [HALUI] #No Content diff --git a/configs/sim/gscreen/gscreen_custom/gscreen_gaxis.ini b/configs/sim/gscreen/gscreen_custom/gscreen_gaxis.ini index d27ba0bd229..c2abe2d8f28 100644 --- a/configs/sim/gscreen/gscreen_custom/gscreen_gaxis.ini +++ b/configs/sim/gscreen/gscreen_custom/gscreen_gaxis.ini @@ -99,8 +99,6 @@ HALFILE = simulated_home.hal # Single file that is executed after the GUI has started. POSTGUI_HALFILE = gaxis_postgui.hal -HALUI = halui - # Trajectory planner section -------------------------------------------------- [HALUI] #No Content diff --git a/configs/sim/gscreen/gscreen_custom/industrial.ini b/configs/sim/gscreen/gscreen_custom/industrial.ini index 0aa100bbfd8..ca2d99900a0 100644 --- a/configs/sim/gscreen/gscreen_custom/industrial.ini +++ b/configs/sim/gscreen/gscreen_custom/industrial.ini @@ -101,8 +101,6 @@ HALFILE = simulated_home.hal # Single file that is executed after the GUI has started. POSTGUI_HALFILE = industrial_postgui.hal -HALUI = halui - # Trajectory planner section -------------------------------------------------- [HALUI] #No Content diff --git a/configs/sim/gscreen/gscreen_custom/tester.ini b/configs/sim/gscreen/gscreen_custom/tester.ini index 3b6f6145815..6924beacf6e 100644 --- a/configs/sim/gscreen/gscreen_custom/tester.ini +++ b/configs/sim/gscreen/gscreen_custom/tester.ini @@ -90,8 +90,6 @@ HALFILE = simulated_home.hal # Single file that is executed after the GUI has started. POSTGUI_HALFILE = tester_postgui.hal -HALUI = halui - # Trajectory planner section -------------------------------------------------- [HALUI] #No Content diff --git a/configs/sim/gscreen/gscreen_custom/tester_metric.ini b/configs/sim/gscreen/gscreen_custom/tester_metric.ini index e9d51848396..f313e40a46e 100644 --- a/configs/sim/gscreen/gscreen_custom/tester_metric.ini +++ b/configs/sim/gscreen/gscreen_custom/tester_metric.ini @@ -102,8 +102,6 @@ HALFILE = simulated_home.hal # Single file that is executed after the GUI has started. POSTGUI_HALFILE = tester_postgui.hal -HALUI = halui - # Trajectory planner section -------------------------------------------------- [HALUI] #No Content diff --git a/configs/sim/gscreen/gscreen_lathe.ini b/configs/sim/gscreen/gscreen_lathe.ini index b219e1e5931..23b5e756339 100644 --- a/configs/sim/gscreen/gscreen_lathe.ini +++ b/configs/sim/gscreen/gscreen_lathe.ini @@ -42,7 +42,6 @@ SERVO_PERIOD = 1000000 CYCLE_TIME = 0.001 [HAL] - HALUI = halui HALFILE = LIB:basic_sim.tcl POSTGUI_HALFILE = lathe_postgui.hal diff --git a/configs/sim/gscreen/gscreen_mm.ini b/configs/sim/gscreen/gscreen_mm.ini index fb27c3da7c8..af7a205c95f 100644 --- a/configs/sim/gscreen/gscreen_mm.ini +++ b/configs/sim/gscreen/gscreen_mm.ini @@ -103,8 +103,6 @@ HALFILE = simulated_home.hal # AXIS at this time (only AXIS creates a HAL component of its own) #POSTGUI_HALFILE = test_postgui.hal -HALUI = halui - # Trajectory planner section -------------------------------------------------- [HALUI] #No Content diff --git a/configs/sim/gscreen/industrial_lathe_wear/industrial_lathe_wear.ini b/configs/sim/gscreen/industrial_lathe_wear/industrial_lathe_wear.ini index a18d281d567..9032cffcfe2 100644 --- a/configs/sim/gscreen/industrial_lathe_wear/industrial_lathe_wear.ini +++ b/configs/sim/gscreen/industrial_lathe_wear/industrial_lathe_wear.ini @@ -44,7 +44,6 @@ TASK = milltask CYCLE_TIME = 0.001 [HAL] -HALUI = halui HALFILE = LIB:basic_sim.tcl POSTGUI_HALFILE = lathe_postgui.hal diff --git a/configs/sim/gscreen/ngcgui/pyngcgui_gscreen.ini b/configs/sim/gscreen/ngcgui/pyngcgui_gscreen.ini index bbc2903e276..5ad0a976566 100644 --- a/configs/sim/gscreen/ngcgui/pyngcgui_gscreen.ini +++ b/configs/sim/gscreen/ngcgui/pyngcgui_gscreen.ini @@ -91,7 +91,6 @@ TASK = milltask CYCLE_TIME = 0.001 [HAL] -HALUI = halui HALFILE = LIB:basic_sim.tcl [TRAJ] diff --git a/configs/sim/gscreen/ngcgui/pyngcgui_gscreen_popupkeyboard.ini b/configs/sim/gscreen/ngcgui/pyngcgui_gscreen_popupkeyboard.ini index cba1b603180..d4c922f9b96 100644 --- a/configs/sim/gscreen/ngcgui/pyngcgui_gscreen_popupkeyboard.ini +++ b/configs/sim/gscreen/ngcgui/pyngcgui_gscreen_popupkeyboard.ini @@ -88,7 +88,6 @@ TASK = milltask CYCLE_TIME = 0.001 [HAL] -HALUI = halui HALFILE = LIB:basic_sim.tcl [TRAJ] diff --git a/configs/sim/gscreen/silverdragon/silverdragon.ini b/configs/sim/gscreen/silverdragon/silverdragon.ini index fe2e27123d9..c7932c2b49e 100644 --- a/configs/sim/gscreen/silverdragon/silverdragon.ini +++ b/configs/sim/gscreen/silverdragon/silverdragon.ini @@ -77,7 +77,6 @@ HALFILE = simulated_home.hal # Single file that is executed after the GUI has started. #POSTGUI_HALFILE = silverdragon_postgui.hal -HALUI = halui # Trajectory planner section -------------------------------------------------- [HALUI] diff --git a/configs/sim/gscreen/spartan/spartan.ini b/configs/sim/gscreen/spartan/spartan.ini index dbdc9baa8b8..1de14983b2e 100644 --- a/configs/sim/gscreen/spartan/spartan.ini +++ b/configs/sim/gscreen/spartan/spartan.ini @@ -43,7 +43,6 @@ TASK = milltask CYCLE_TIME = 0.010 [HAL] -HALUI = halui HALFILE = spartan.hal HALFILE = simulated_home.hal HALFILE = custom.hal diff --git a/configs/sim/pyvcp_demo/pyvcp_bottom_panel.ini b/configs/sim/pyvcp_demo/pyvcp_bottom_panel.ini index ea8520ed706..07d9fb0e31b 100644 --- a/configs/sim/pyvcp_demo/pyvcp_bottom_panel.ini +++ b/configs/sim/pyvcp_demo/pyvcp_bottom_panel.ini @@ -117,8 +117,6 @@ HALFILE = simulated_home.hal # AXIS at this time (only AXIS creates a HAL component of its own) POSTGUI_HALFILE = pyvcp_bottom_panel.hal -HALUI = halui - [HALUI] # add halui MDI commands here (max 64) diff --git a/configs/sim/pyvcp_demo/pyvcp_demo1.ini b/configs/sim/pyvcp_demo/pyvcp_demo1.ini index 57be35b0ef0..076710de532 100644 --- a/configs/sim/pyvcp_demo/pyvcp_demo1.ini +++ b/configs/sim/pyvcp_demo/pyvcp_demo1.ini @@ -114,8 +114,6 @@ HALFILE = simulated_home.hal # AXIS at this time (only AXIS creates a HAL component of its own) POSTGUI_HALFILE = custom.hal -HALUI = halui - [HALUI] # add halui MDI commands here (max 64) diff --git a/configs/sim/pyvcp_demo/pyvcp_embed_tab.ini b/configs/sim/pyvcp_demo/pyvcp_embed_tab.ini index 1895448e577..80574f49fd3 100644 --- a/configs/sim/pyvcp_demo/pyvcp_embed_tab.ini +++ b/configs/sim/pyvcp_demo/pyvcp_embed_tab.ini @@ -118,8 +118,6 @@ HALFILE = simulated_home.hal # AXIS at this time (only AXIS creates a HAL component of its own) POSTGUI_HALFILE = pyvcp_embed_tab.hal -HALUI = halui - [HALUI] # add halui MDI commands here (max 64) diff --git a/configs/sim/qtaxis/non-trivial/scara/scara.ini b/configs/sim/qtaxis/non-trivial/scara/scara.ini index 00ea3d2a1ca..041ae255c34 100644 --- a/configs/sim/qtaxis/non-trivial/scara/scara.ini +++ b/configs/sim/qtaxis/non-trivial/scara/scara.ini @@ -119,7 +119,6 @@ JOINTS = 6 KINEMATICS = scarakins coordinates=xyzcab [HAL] -HALUI = halui HALFILE = LIB:basic_sim.tcl [HALUI] diff --git a/configs/sim/qtaxis/xyz/qtaxis.ini b/configs/sim/qtaxis/xyz/qtaxis.ini index 12cf1911843..2f9dcb2afa7 100644 --- a/configs/sim/qtaxis/xyz/qtaxis.ini +++ b/configs/sim/qtaxis/xyz/qtaxis.ini @@ -177,8 +177,6 @@ HALFILE = check_constraints.hal # AXIS at this time (only AXIS creates a HAL component of its own) POSTGUI_HALFILE = qtvcp_postgui.hal -HALUI = halui - # Trajectory planner section -------------------------------------------------- [HALUI] diff --git a/configs/sim/qtdragon/qtdragon_multi_joint/qtdragon_xyyz.ini b/configs/sim/qtdragon/qtdragon_multi_joint/qtdragon_xyyz.ini index 8c16d5e1d20..d84babffac8 100644 --- a/configs/sim/qtdragon/qtdragon_multi_joint/qtdragon_xyyz.ini +++ b/configs/sim/qtdragon/qtdragon_multi_joint/qtdragon_xyyz.ini @@ -120,7 +120,6 @@ DEFAULT_LINEAR_VELOCITY = 50.00 SPINDLES = 1 [HAL] -HALUI = halui HALBRIDGE = hal_bridge # loads the HAL machine simulation diff --git a/configs/sim/qtdragon/qtdragon_multi_joint/qtdragon_xyyzw.ini b/configs/sim/qtdragon/qtdragon_multi_joint/qtdragon_xyyzw.ini index b3614ef512a..791aefecd93 100644 --- a/configs/sim/qtdragon/qtdragon_multi_joint/qtdragon_xyyzw.ini +++ b/configs/sim/qtdragon/qtdragon_multi_joint/qtdragon_xyyzw.ini @@ -122,7 +122,6 @@ DEFAULT_LINEAR_VELOCITY = 50.00 SPINDLES = 1 [HAL] -HALUI = halui HALBRIDGE = hal_bridge # loads the HAL machine simulation diff --git a/configs/sim/qtdragon/qtdragon_multi_joint/qtdragon_xyzy.ini b/configs/sim/qtdragon/qtdragon_multi_joint/qtdragon_xyzy.ini index 1430466c4dc..f76d1d3d9a4 100644 --- a/configs/sim/qtdragon/qtdragon_multi_joint/qtdragon_xyzy.ini +++ b/configs/sim/qtdragon/qtdragon_multi_joint/qtdragon_xyzy.ini @@ -120,7 +120,6 @@ DEFAULT_LINEAR_VELOCITY = 50.00 SPINDLES = 1 [HAL] -HALUI = halui HALBRIDGE = hal_bridge # loads the HAL machine simulation diff --git a/configs/sim/qtdragon/qtdragon_multi_joint/qtdragon_xyzya.ini b/configs/sim/qtdragon/qtdragon_multi_joint/qtdragon_xyzya.ini index e37a803deae..10bb8a88291 100644 --- a/configs/sim/qtdragon/qtdragon_multi_joint/qtdragon_xyzya.ini +++ b/configs/sim/qtdragon/qtdragon_multi_joint/qtdragon_xyzya.ini @@ -124,7 +124,6 @@ DEFAULT_LINEAR_VELOCITY = 50.00 SPINDLES = 1 [HAL] -HALUI = halui HALBRIDGE = hal_bridge # loads the HAL machine simulation diff --git a/configs/sim/qtdragon/qtdragon_multi_joint/qtdragon_yyxz.ini b/configs/sim/qtdragon/qtdragon_multi_joint/qtdragon_yyxz.ini index 54631bbbfd8..cc39f30a238 100644 --- a/configs/sim/qtdragon/qtdragon_multi_joint/qtdragon_yyxz.ini +++ b/configs/sim/qtdragon/qtdragon_multi_joint/qtdragon_yyxz.ini @@ -120,7 +120,6 @@ DEFAULT_LINEAR_VELOCITY = 50.00 SPINDLES = 1 [HAL] -HALUI = halui HALBRIDGE = hal_bridge # loads the HAL machine simulation diff --git a/configs/sim/qtdragon/qtdragon_tool_probe/qtdragon_auto_tool_probe.ini b/configs/sim/qtdragon/qtdragon_tool_probe/qtdragon_auto_tool_probe.ini index cd8c1cd4ae7..109740b4e3d 100644 --- a/configs/sim/qtdragon/qtdragon_tool_probe/qtdragon_auto_tool_probe.ini +++ b/configs/sim/qtdragon/qtdragon_tool_probe/qtdragon_auto_tool_probe.ini @@ -144,7 +144,6 @@ DEFAULT_LINEAR_VELOCITY = 50.00 SPINDLES = 1 [HAL] -HALUI = halui HALBRIDGE = hal_bridge HALFILE = core_sim.hal diff --git a/configs/sim/qtdragon/qtdragon_xyz/qtdragon_inch.ini b/configs/sim/qtdragon/qtdragon_xyz/qtdragon_inch.ini index 4be20c9b004..f4a3cf65d14 100644 --- a/configs/sim/qtdragon/qtdragon_xyz/qtdragon_inch.ini +++ b/configs/sim/qtdragon/qtdragon_xyz/qtdragon_inch.ini @@ -153,7 +153,6 @@ DEFAULT_LINEAR_VELOCITY = 50.00 SPINDLES = 1 [HAL] -HALUI = halui HALBRIDGE = hal_bridge # loads the HAL machine simulation diff --git a/configs/sim/qtdragon/qtdragon_xyz/qtdragon_metric.ini b/configs/sim/qtdragon/qtdragon_xyz/qtdragon_metric.ini index c246e1d6845..561179e06ac 100644 --- a/configs/sim/qtdragon/qtdragon_xyz/qtdragon_metric.ini +++ b/configs/sim/qtdragon/qtdragon_xyz/qtdragon_metric.ini @@ -150,7 +150,6 @@ DEFAULT_LINEAR_VELOCITY = 50.00 SPINDLES = 1 [HAL] -HALUI = halui HALBRIDGE = hal_bridge # loads the HAL machine simulation diff --git a/configs/sim/qtdragon/qtdragon_xyz/qtdragon_metric_debug.ini b/configs/sim/qtdragon/qtdragon_xyz/qtdragon_metric_debug.ini index b2bb0b8ddd2..347ebd1ff4d 100644 --- a/configs/sim/qtdragon/qtdragon_xyz/qtdragon_metric_debug.ini +++ b/configs/sim/qtdragon/qtdragon_xyz/qtdragon_metric_debug.ini @@ -158,7 +158,6 @@ DEFAULT_LINEAR_VELOCITY = 50.00 SPINDLES = 1 [HAL] -HALUI = halui HALBRIDGE = hal_bridge # loads the HAL machine simulation diff --git a/configs/sim/qtdragon/qtdragon_xyz/qtdragon_xyza.ini b/configs/sim/qtdragon/qtdragon_xyz/qtdragon_xyza.ini index 466f0e98085..8eabb84c516 100644 --- a/configs/sim/qtdragon/qtdragon_xyz/qtdragon_xyza.ini +++ b/configs/sim/qtdragon/qtdragon_xyz/qtdragon_xyza.ini @@ -129,7 +129,6 @@ DEFAULT_LINEAR_VELOCITY = 50.00 SPINDLES = 1 [HAL] -HALUI = halui # loads the HAL machine simulation HALFILE = gantrysim.hal HALFILE = simulated-gantry-home.hal diff --git a/configs/sim/qtdragon/qtdragon_xyz45/qtdragon_xyza.ini b/configs/sim/qtdragon/qtdragon_xyz45/qtdragon_xyza.ini index 59e43f1cb63..0477fec4d1c 100644 --- a/configs/sim/qtdragon/qtdragon_xyz45/qtdragon_xyza.ini +++ b/configs/sim/qtdragon/qtdragon_xyz45/qtdragon_xyza.ini @@ -125,7 +125,6 @@ DEFAULT_LINEAR_VELOCITY = 50.00 SPINDLES = 1 [HAL] -HALUI = halui HALBRIDGE = hal_bridge # loads the HAL machine simulation diff --git a/configs/sim/qtdragon/qtdragon_xyz45/qtdragon_xyzab.ini b/configs/sim/qtdragon/qtdragon_xyz45/qtdragon_xyzab.ini index 41dbf6364b5..59ac96fee1e 100644 --- a/configs/sim/qtdragon/qtdragon_xyz45/qtdragon_xyzab.ini +++ b/configs/sim/qtdragon/qtdragon_xyz45/qtdragon_xyzab.ini @@ -125,7 +125,6 @@ DEFAULT_LINEAR_VELOCITY = 50.00 SPINDLES = 1 [HAL] -HALUI = halui HALBRIDGE = hal_bridge # loads the HAL machine simulation diff --git a/configs/sim/qtdragon/qtdragon_xyz45/qtdragon_xyzac.ini b/configs/sim/qtdragon/qtdragon_xyz45/qtdragon_xyzac.ini index 01fc99beefe..70857afcdf4 100644 --- a/configs/sim/qtdragon/qtdragon_xyz45/qtdragon_xyzac.ini +++ b/configs/sim/qtdragon/qtdragon_xyz45/qtdragon_xyzac.ini @@ -125,7 +125,6 @@ DEFAULT_LINEAR_VELOCITY = 50.00 SPINDLES = 1 [HAL] -HALUI = halui HALBRIDGE = hal_bridge # loads the HAL machine simulation diff --git a/configs/sim/qtdragon_hd/qtdragon_hd_xyz/qtdragon_hd_vertical.ini b/configs/sim/qtdragon_hd/qtdragon_hd_xyz/qtdragon_hd_vertical.ini index 605f9700ce1..22d30d42e14 100644 --- a/configs/sim/qtdragon_hd/qtdragon_hd_xyz/qtdragon_hd_vertical.ini +++ b/configs/sim/qtdragon_hd/qtdragon_hd_xyz/qtdragon_hd_vertical.ini @@ -128,7 +128,6 @@ DEFAULT_LINEAR_VELOCITY = 50.00 SPINDLES = 1 [HAL] -HALUI = halui HALBRIDGE = hal_bridge HALFILE = core_sim.hal diff --git a/configs/sim/qtdragon_hd/qtdragon_hd_xyz/qtdragon_hd_vertical_xyza.ini b/configs/sim/qtdragon_hd/qtdragon_hd_xyz/qtdragon_hd_vertical_xyza.ini index d8e88f3b704..e412ddcec3b 100644 --- a/configs/sim/qtdragon_hd/qtdragon_hd_xyz/qtdragon_hd_vertical_xyza.ini +++ b/configs/sim/qtdragon_hd/qtdragon_hd_xyz/qtdragon_hd_vertical_xyza.ini @@ -131,7 +131,6 @@ DEFAULT_LINEAR_VELOCITY = 50.00 SPINDLES = 1 [HAL] -HALUI = halui HALBRIDGE = hal_bridge # loads the HAL machine simulation diff --git a/configs/sim/qtdragon_hd/qtdragon_hd_xyz/qtdragon_hd_xyz.ini b/configs/sim/qtdragon_hd/qtdragon_hd_xyz/qtdragon_hd_xyz.ini index 25283374243..c3d249406bd 100644 --- a/configs/sim/qtdragon_hd/qtdragon_hd_xyz/qtdragon_hd_xyz.ini +++ b/configs/sim/qtdragon_hd/qtdragon_hd_xyz/qtdragon_hd_xyz.ini @@ -126,7 +126,6 @@ DEFAULT_LINEAR_VELOCITY = 50.00 SPINDLES = 1 [HAL] -HALUI = halui HALBRIDGE = hal_bridge HALFILE = core_sim.hal diff --git a/configs/sim/qtdragon_hd/qtdragon_hd_xyz/qtdragon_hd_xyza.ini b/configs/sim/qtdragon_hd/qtdragon_hd_xyz/qtdragon_hd_xyza.ini index b206ed1a7db..20e593a5275 100644 --- a/configs/sim/qtdragon_hd/qtdragon_hd_xyz/qtdragon_hd_xyza.ini +++ b/configs/sim/qtdragon_hd/qtdragon_hd_xyz/qtdragon_hd_xyza.ini @@ -128,7 +128,6 @@ DEFAULT_LINEAR_VELOCITY = 50.00 SPINDLES = 1 [HAL] -HALUI = halui HALBRIDGE = hal_bridge # loads the HAL machine simulation diff --git a/configs/sim/qtdragon_hd/qtdragon_hd_xyz/qtdragon_hd_xyzab.ini b/configs/sim/qtdragon_hd/qtdragon_hd_xyz/qtdragon_hd_xyzab.ini index a489db176c6..660227adaa2 100644 --- a/configs/sim/qtdragon_hd/qtdragon_hd_xyz/qtdragon_hd_xyzab.ini +++ b/configs/sim/qtdragon_hd/qtdragon_hd_xyz/qtdragon_hd_xyzab.ini @@ -125,7 +125,6 @@ DEFAULT_LINEAR_VELOCITY = 50.00 SPINDLES = 1 [HAL] -HALUI = halui HALBRIDGE = hal_bridge # loads the HAL machine simulation diff --git a/configs/sim/qtdragon_hd/qtdragon_hd_xyz/qtdragon_hd_xyzac.ini b/configs/sim/qtdragon_hd/qtdragon_hd_xyz/qtdragon_hd_xyzac.ini index 2d2c97b1e17..70e904de811 100644 --- a/configs/sim/qtdragon_hd/qtdragon_hd_xyz/qtdragon_hd_xyzac.ini +++ b/configs/sim/qtdragon_hd/qtdragon_hd_xyz/qtdragon_hd_xyzac.ini @@ -125,7 +125,6 @@ DEFAULT_LINEAR_VELOCITY = 50.00 SPINDLES = 1 [HAL] -HALUI = halui HALBRIDGE = hal_bridge # loads the HAL machine simulation diff --git a/configs/sim/qtdragon_hd/qtdragon_hd_xyz/qtdragon_next_xyz.ini b/configs/sim/qtdragon_hd/qtdragon_hd_xyz/qtdragon_next_xyz.ini index aaf67603a23..b99a925b8d9 100644 --- a/configs/sim/qtdragon_hd/qtdragon_hd_xyz/qtdragon_next_xyz.ini +++ b/configs/sim/qtdragon_hd/qtdragon_hd_xyz/qtdragon_next_xyz.ini @@ -120,7 +120,6 @@ DEFAULT_LINEAR_VELOCITY = 50.00 SPINDLES = 1 [HAL] -HALUI = halui HALFILE = core_sim.hal HALFILE = simulated_home.hal # this file is loaded after qtdragon has made it's HAl pins diff --git a/configs/sim/qtdragon_hd/qtdragon_hd_z_compensation/qtdragon_hd_z_compensation.ini b/configs/sim/qtdragon_hd/qtdragon_hd_z_compensation/qtdragon_hd_z_compensation.ini index 274443940af..1e25dd5e056 100644 --- a/configs/sim/qtdragon_hd/qtdragon_hd_z_compensation/qtdragon_hd_z_compensation.ini +++ b/configs/sim/qtdragon_hd/qtdragon_hd_z_compensation/qtdragon_hd_z_compensation.ini @@ -120,7 +120,6 @@ DEFAULT_LINEAR_VELOCITY = 50.00 SPINDLES = 1 [HAL] -HALUI = halui HALBRIDGE = hal_bridge HALFILE = core_sim.hal diff --git a/configs/sim/qtdragon_lathe/basic_xz_lathe/lathe.ini b/configs/sim/qtdragon_lathe/basic_xz_lathe/lathe.ini index 6d5a04b2c14..1c810b286ee 100644 --- a/configs/sim/qtdragon_lathe/basic_xz_lathe/lathe.ini +++ b/configs/sim/qtdragon_lathe/basic_xz_lathe/lathe.ini @@ -56,7 +56,6 @@ SERVO_PERIOD = 1000000 CYCLE_TIME = 0.001 [HAL] -HALUI = halui HALBRIDGE = hal_bridge HALFILE = LIB:basic_sim.tcl diff --git a/configs/sim/qttouchy/qttouchy.ini b/configs/sim/qttouchy/qttouchy.ini index ef616ba42fd..5690b1cae85 100644 --- a/configs/sim/qttouchy/qttouchy.ini +++ b/configs/sim/qttouchy/qttouchy.ini @@ -158,8 +158,6 @@ HALFILE = simulated_home.hal # AXIS at this time (only AXIS creates a HAL component of its own) POSTGUI_HALFILE = qtvcp_postgui.hal -HALUI = halui - # Trajectory planner section -------------------------------------------------- [HALUI] diff --git a/configs/sim/qtvcp_screens/blender.ini b/configs/sim/qtvcp_screens/blender.ini index 6e091cd644b..4ebdd924f49 100644 --- a/configs/sim/qtvcp_screens/blender.ini +++ b/configs/sim/qtvcp_screens/blender.ini @@ -167,8 +167,6 @@ HALFILE = check_constraints.hal # AXIS at this time (only AXIS creates a HAL component of its own) POSTGUI_HALFILE = qtvcp_postgui.hal -HALUI = halui - # Trajectory planner section -------------------------------------------------- [HALUI] diff --git a/configs/sim/qtvcp_screens/industrial_lathe_wear/industrial_lathe_wear.ini b/configs/sim/qtvcp_screens/industrial_lathe_wear/industrial_lathe_wear.ini index 12effa9efe5..992f211af75 100644 --- a/configs/sim/qtvcp_screens/industrial_lathe_wear/industrial_lathe_wear.ini +++ b/configs/sim/qtvcp_screens/industrial_lathe_wear/industrial_lathe_wear.ini @@ -64,7 +64,6 @@ TASK = milltask CYCLE_TIME = 0.001 [HAL] -HALUI = halui HALFILE = LIB:basic_sim.tcl -no_use_hal_manualtoolchange POSTGUI_HALFILE = qtvcp_postgui.hal diff --git a/configs/sim/qtvcp_screens/non-trivial/scara/scara.ini b/configs/sim/qtvcp_screens/non-trivial/scara/scara.ini index 97f588c2e34..d786c83435c 100644 --- a/configs/sim/qtvcp_screens/non-trivial/scara/scara.ini +++ b/configs/sim/qtvcp_screens/non-trivial/scara/scara.ini @@ -120,7 +120,6 @@ JOINTS = 6 KINEMATICS = scarakins coordinates=xyzcab [HAL] -HALUI = halui HALFILE = LIB:basic_sim.tcl [HALUI] diff --git a/configs/sim/qtvcp_screens/qt_800x600.ini b/configs/sim/qtvcp_screens/qt_800x600.ini index ff78136c0b7..2def79cb40b 100644 --- a/configs/sim/qtvcp_screens/qt_800x600.ini +++ b/configs/sim/qtvcp_screens/qt_800x600.ini @@ -124,8 +124,6 @@ HALFILE = check_constraints.hal # AXIS at this time (only AXIS creates a HAL component of its own) POSTGUI_HALFILE = qtvcp_postgui.hal -HALUI = halui - # Trajectory planner section -------------------------------------------------- [HALUI] diff --git a/configs/sim/qtvcp_screens/qtaxis.ini b/configs/sim/qtvcp_screens/qtaxis.ini index c023a0607a8..bc4fe148af4 100644 --- a/configs/sim/qtvcp_screens/qtaxis.ini +++ b/configs/sim/qtvcp_screens/qtaxis.ini @@ -180,8 +180,6 @@ HALFILE = check_constraints.hal # AXIS at this time (only AXIS creates a HAL component of its own) POSTGUI_HALFILE = qtvcp_postgui.hal -HALUI = halui - # Trajectory planner section -------------------------------------------------- [HALUI] diff --git a/configs/sim/qtvcp_screens/qtaxis_lathe/qtaxis_lathe.ini b/configs/sim/qtvcp_screens/qtaxis_lathe/qtaxis_lathe.ini index 0876cac83cc..54ce1466385 100644 --- a/configs/sim/qtvcp_screens/qtaxis_lathe/qtaxis_lathe.ini +++ b/configs/sim/qtvcp_screens/qtaxis_lathe/qtaxis_lathe.ini @@ -154,8 +154,6 @@ POSTGUI_HALFILE = qtvcp_postgui.hal # AXIS at this time (only AXIS creates a HAL component of its own) POSTGUI_HALFILE = qtvcp_postgui.hal -HALUI = halui - [TRAJ] diff --git a/configs/sim/qtvcp_screens/qtaxis_mpg.ini b/configs/sim/qtvcp_screens/qtaxis_mpg.ini index e5bb171e719..bbcc52ad9c1 100644 --- a/configs/sim/qtvcp_screens/qtaxis_mpg.ini +++ b/configs/sim/qtvcp_screens/qtaxis_mpg.ini @@ -207,8 +207,6 @@ POSTGUI_HALCMD = setp qtaxis.mpg-enable 1 #POSTGUI_HALCMD = net mpg-enable qtaxis.mpg-enable sim_panel.selectscroll POSTGUI_HALCMD = net mpg qtaxis.mpg-in sim_panel.MPG-s -HALUI = halui - # Trajectory planner section -------------------------------------------------- [HALUI] diff --git a/configs/sim/qtvcp_screens/qtdefault.ini b/configs/sim/qtvcp_screens/qtdefault.ini index 78061f39987..cb378c86c02 100644 --- a/configs/sim/qtvcp_screens/qtdefault.ini +++ b/configs/sim/qtvcp_screens/qtdefault.ini @@ -170,8 +170,6 @@ HALFILE = check_constraints.hal # AXIS at this time (only AXIS creates a HAL component of its own) POSTGUI_HALFILE = qtvcp_postgui.hal -HALUI = halui - # Trajectory planner section -------------------------------------------------- [HALUI] diff --git a/configs/sim/qtvcp_screens/qtdefault_9axis.ini b/configs/sim/qtvcp_screens/qtdefault_9axis.ini index dad0c31c2e6..419615a9615 100644 --- a/configs/sim/qtvcp_screens/qtdefault_9axis.ini +++ b/configs/sim/qtvcp_screens/qtdefault_9axis.ini @@ -56,7 +56,6 @@ SERVO_PERIOD = 1000000 TOOL_CHANGE_POSITION = 0 0 2 [HAL] - HALUI = halui HALFILE = LIB:basic_sim.tcl -no_use_hal_manualtoolchange HALFILE = locking_indexer.hal diff --git a/configs/sim/qtvcp_screens/qtdefault_mm.ini b/configs/sim/qtvcp_screens/qtdefault_mm.ini index a696d4597e4..de74d574c11 100644 --- a/configs/sim/qtvcp_screens/qtdefault_mm.ini +++ b/configs/sim/qtvcp_screens/qtdefault_mm.ini @@ -110,8 +110,6 @@ HALFILE = simulated_home.hal # Single file that is executed after the GUI has started. POSTGUI_HALFILE = qtvcp_postgui.hal -HALUI = halui - # Trajectory planner section -------------------------------------------------- [TRAJ] COORDINATES = X Y Z diff --git a/configs/sim/qtvcp_screens/qtdragon/qtdragon_mpg.ini b/configs/sim/qtvcp_screens/qtdragon/qtdragon_mpg.ini index a28b0a1e885..534757ff6bc 100644 --- a/configs/sim/qtvcp_screens/qtdragon/qtdragon_mpg.ini +++ b/configs/sim/qtvcp_screens/qtdragon/qtdragon_mpg.ini @@ -110,7 +110,6 @@ DEFAULT_LINEAR_VELOCITY = 50.00 SPINDLES = 1 [HAL] -HALUI = halui HALFILE = core_sim.hal HALFILE = simulated_home.hal #HALFILE = custom.hal diff --git a/configs/sim/qtvcp_screens/qtvcp_custom/qtdefault_ngc.ini b/configs/sim/qtvcp_screens/qtvcp_custom/qtdefault_ngc.ini index 0372ad865c1..0aa0ece3706 100644 --- a/configs/sim/qtvcp_screens/qtvcp_custom/qtdefault_ngc.ini +++ b/configs/sim/qtvcp_screens/qtvcp_custom/qtdefault_ngc.ini @@ -189,8 +189,6 @@ HALFILE = check_constraints.hal # AXIS at this time (only AXIS creates a HAL component of its own) POSTGUI_HALFILE = qtvcp_postgui.hal -HALUI = halui - # Trajectory planner section -------------------------------------------------- [HALUI] diff --git a/configs/sim/qtvcp_screens/qtvcp_experimental/gremlin.ini b/configs/sim/qtvcp_screens/qtvcp_experimental/gremlin.ini index 0270b000131..39961324f7d 100644 --- a/configs/sim/qtvcp_screens/qtvcp_experimental/gremlin.ini +++ b/configs/sim/qtvcp_screens/qtvcp_experimental/gremlin.ini @@ -192,8 +192,6 @@ HALFILE = check_constraints.hal # AXIS at this time (only AXIS creates a HAL component of its own) POSTGUI_HALFILE = qtvcp_postgui.hal -HALUI = halui - # Trajectory planner section -------------------------------------------------- [HALUI] diff --git a/configs/sim/qtvcp_screens/qtvcp_experimental/qtdefault_gladevcp.ini b/configs/sim/qtvcp_screens/qtvcp_experimental/qtdefault_gladevcp.ini index 14820649397..dbcab0b5d15 100644 --- a/configs/sim/qtvcp_screens/qtvcp_experimental/qtdefault_gladevcp.ini +++ b/configs/sim/qtvcp_screens/qtvcp_experimental/qtdefault_gladevcp.ini @@ -192,8 +192,6 @@ HALFILE = check_constraints.hal # AXIS at this time (only AXIS creates a HAL component of its own) POSTGUI_HALFILE = qtvcp_postgui.hal -HALUI = halui - # Trajectory planner section -------------------------------------------------- [HALUI] diff --git a/configs/sim/qtvcp_screens/qtvcp_experimental/qtdefault_ngc.ini b/configs/sim/qtvcp_screens/qtvcp_experimental/qtdefault_ngc.ini index 0372ad865c1..0aa0ece3706 100644 --- a/configs/sim/qtvcp_screens/qtvcp_experimental/qtdefault_ngc.ini +++ b/configs/sim/qtvcp_screens/qtvcp_experimental/qtdefault_ngc.ini @@ -189,8 +189,6 @@ HALFILE = check_constraints.hal # AXIS at this time (only AXIS creates a HAL component of its own) POSTGUI_HALFILE = qtvcp_postgui.hal -HALUI = halui - # Trajectory planner section -------------------------------------------------- [HALUI] diff --git a/configs/sim/qtvcp_screens/qtx1mill.ini b/configs/sim/qtvcp_screens/qtx1mill.ini index 0e3a2d3c334..b9aa6c59dec 100644 --- a/configs/sim/qtvcp_screens/qtx1mill.ini +++ b/configs/sim/qtvcp_screens/qtx1mill.ini @@ -174,8 +174,6 @@ HALFILE = check_constraints.hal # AXIS at this time (only AXIS creates a HAL component of its own) POSTGUI_HALFILE = qtvcp_postgui.hal -HALUI = halui - # Trajectory planner section -------------------------------------------------- [HALUI] diff --git a/configs/sim/qtvcp_screens/tester.ini b/configs/sim/qtvcp_screens/tester.ini index 4cec31b24f5..4b3b493e67b 100644 --- a/configs/sim/qtvcp_screens/tester.ini +++ b/configs/sim/qtvcp_screens/tester.ini @@ -144,8 +144,6 @@ HALFILE = check_constraints.hal # AXIS at this time (only AXIS creates a HAL component of its own) #POSTGUI_HALFILE = qtvcp_postgui.hal -HALUI = halui - # Trajectory planner section -------------------------------------------------- [HALUI] diff --git a/configs/sim/tklinuxcnc/ldelta.ini b/configs/sim/tklinuxcnc/ldelta.ini index c2222ff791e..b2ca19f0afd 100644 --- a/configs/sim/tklinuxcnc/ldelta.ini +++ b/configs/sim/tklinuxcnc/ldelta.ini @@ -46,7 +46,6 @@ SERVO_PERIOD = 1000000 [HAL] HALFILE = sim_ldelta.hal HALFILE = axis_manualtoolchange.hal -HALUI = halui [TRAJ] COORDINATES = X Y Z A diff --git a/configs/sim/touchy/ngcgui/pyngcgui_touchy.ini b/configs/sim/touchy/ngcgui/pyngcgui_touchy.ini index 1297e290e42..858c181fa9c 100644 --- a/configs/sim/touchy/ngcgui/pyngcgui_touchy.ini +++ b/configs/sim/touchy/ngcgui/pyngcgui_touchy.ini @@ -54,7 +54,6 @@ CYCLE_TIME = 0.001 [HAL] HALFILE = LIB:basic_sim.tcl -HALUI = halui [TRAJ] COORDINATES = X Y Z diff --git a/configs/sim/touchy/ngcgui/pyngcgui_touchy_lathe.ini b/configs/sim/touchy/ngcgui/pyngcgui_touchy_lathe.ini index 90918ec728c..3eba2ab765e 100644 --- a/configs/sim/touchy/ngcgui/pyngcgui_touchy_lathe.ini +++ b/configs/sim/touchy/ngcgui/pyngcgui_touchy_lathe.ini @@ -64,7 +64,6 @@ TASK = milltask CYCLE_TIME = 0.001 [HAL] -HALUI = halui HALFILE = LIB:basic_sim.tcl [TRAJ] diff --git a/configs/sim/touchy/ngcgui/pyngcgui_touchy_moveoff.ini b/configs/sim/touchy/ngcgui/pyngcgui_touchy_moveoff.ini index 500bf37ed1c..15b52e9c096 100644 --- a/configs/sim/touchy/ngcgui/pyngcgui_touchy_moveoff.ini +++ b/configs/sim/touchy/ngcgui/pyngcgui_touchy_moveoff.ini @@ -54,7 +54,6 @@ TASK = milltask CYCLE_TIME = 0.001 [HAL] -HALUI = halui HALFILE = LIB:basic_sim.tcl HALFILE = LIB:hookup_moveoff.tcl diff --git a/configs/sim/woodpecker/woodpecker.ini b/configs/sim/woodpecker/woodpecker.ini index fc6b389dc99..fd46471f057 100644 --- a/configs/sim/woodpecker/woodpecker.ini +++ b/configs/sim/woodpecker/woodpecker.ini @@ -78,7 +78,6 @@ DEFAULT_LINEAR_VELOCITY = 50.00 SPINDLES = 1 [HAL] -HALUI = halui HALFILE = core_sim.hal HALFILE = simulated_home.hal #HALFILE = custom.hal diff --git a/configs/sim/woodpecker/woodpecker_auto_tool_probe.ini b/configs/sim/woodpecker/woodpecker_auto_tool_probe.ini index e8fe3935119..07748d5ace9 100644 --- a/configs/sim/woodpecker/woodpecker_auto_tool_probe.ini +++ b/configs/sim/woodpecker/woodpecker_auto_tool_probe.ini @@ -100,7 +100,6 @@ DEFAULT_LINEAR_VELOCITY = 50.00 SPINDLES = 1 [HAL] -HALUI = halui HALFILE = core_sim.hal HALFILE = simulated_home.hal POSTGUI_HALFILE = woodpecker_postgui.hal diff --git a/configs/sim/woodpecker/woodpecker_xyz.ini b/configs/sim/woodpecker/woodpecker_xyz.ini index 911f2c576b0..1631c202240 100644 --- a/configs/sim/woodpecker/woodpecker_xyz.ini +++ b/configs/sim/woodpecker/woodpecker_xyz.ini @@ -87,7 +87,6 @@ SPINDLES = 1 NO_FORCE_HOMING = 1 [HAL] -HALUI = halui HALFILE = core_sim.hal HALFILE = simulated_home.hal #HALFILE = custom.hal diff --git a/configs/sim/woodpecker/woodpecker_xyza.ini b/configs/sim/woodpecker/woodpecker_xyza.ini index 1226c5e7e00..6d2fb66c3b3 100644 --- a/configs/sim/woodpecker/woodpecker_xyza.ini +++ b/configs/sim/woodpecker/woodpecker_xyza.ini @@ -116,7 +116,6 @@ POSITION_FILE = position.txt #NO_FORCE_HOMING = 1 [HAL] -HALUI = halui #HALFILE = core_sim.hal HALFILE = gantrysim.hal HALFILE = simulated-gantry-home.hal diff --git a/configs/sim/woodpecker/woodpecker_xyzab.ini b/configs/sim/woodpecker/woodpecker_xyzab.ini index d6229b133c6..67f1e0f788d 100644 --- a/configs/sim/woodpecker/woodpecker_xyzab.ini +++ b/configs/sim/woodpecker/woodpecker_xyzab.ini @@ -102,7 +102,6 @@ POSITION_FILE = position.txt SPINDLES = 1 [HAL] -HALUI = halui HALFILE = gantrysim-xyzab.hal HALFILE = simulated-gantry-xyzab-home.hal #HALFILE = mpg.hal diff --git a/configs/sim/woodpecker/woodpecker_xyzy.ini b/configs/sim/woodpecker/woodpecker_xyzy.ini index 18f793993f4..bbd8f63a620 100644 --- a/configs/sim/woodpecker/woodpecker_xyzy.ini +++ b/configs/sim/woodpecker/woodpecker_xyzy.ini @@ -84,7 +84,6 @@ DEFAULT_LINEAR_VELOCITY = 50.00 SPINDLES = 1 [HAL] -HALUI = halui #HALFILE = core_sim.hal HALFILE = gantrysim.hal HALFILE = simulated-gantry-home.hal diff --git a/configs/sim/woodpecker/woodpecker_xyzya.ini b/configs/sim/woodpecker/woodpecker_xyzya.ini index 3f0ba0c3b57..87ea1220a07 100644 --- a/configs/sim/woodpecker/woodpecker_xyzya.ini +++ b/configs/sim/woodpecker/woodpecker_xyzya.ini @@ -87,7 +87,6 @@ DEFAULT_LINEAR_VELOCITY = 50.00 SPINDLES = 1 [HAL] -HALUI = halui #HALFILE = core_sim.hal HALFILE = gantrysim.hal HALFILE = simulated-gantry-home.hal From fb2ddb5d8fa81dd529477282220047674621e172 Mon Sep 17 00:00:00 2001 From: Rene Hopf Date: Sun, 20 Sep 2026 17:34:39 +0200 Subject: [PATCH 03/21] remove halui from test configs --- tests/abort/feed-rate/test.ini | 1 - tests/abort/g64/test.ini | 1 - tests/ccomp/early-exit/test.ini | 1 - tests/halui/jogging/halui.ini | 1 - tests/halui/mdi/halui.ini | 1 - tests/interp/g28.2/flush-order/test.ini | 1 - tests/interp/g28.2/home-all-sequence/test.ini | 1 - tests/interp/g28.2/immediate-mode-guard/test.ini | 1 - tests/interp/g28.2/invalid-pword/test.ini | 1 - tests/interp/g28.2/position-model/test.ini | 1 - tests/interp/g28.2/sequencing/test.ini | 1 - tests/interp/mdi-oword-m66/interp.ini | 1 - tests/interp/oword-mdi-sub-update/interp.ini | 1 - tests/interp/subroutine-return/interp.ini | 1 - tests/interp_initcode/test.ini | 1 - tests/matrixkins/test.ini | 1 - tests/maxkins/test.ini | 1 - tests/mdi-queue-length/test.ini | 1 - tests/mdi-while-queuebuster-waitflag/test.ini | 1 - tests/mqtt/simulator.ini | 1 - tests/remap/remap-io/test-ngc.ini | 1 - tests/remap/remap-io/test-py.ini | 1 - tests/remap/remap-reentry/test.ini | 1 - tests/rs274ngc-startup/test.ini | 1 - tests/startup-state/test.ini | 1 - tests/statbuffer-g5x-abort/test.ini | 1 - tests/tlo/g43-test.ini | 1 - tests/tool-info/non-random/test.ini | 1 - tests/tool-info/random-no-startup-tool/test.ini | 1 - tests/tool-info/random-with-startup-tool/test.ini | 1 - tests/toolchanger/abort-during-change/abort-test.ini | 1 - tests/toolchanger/m61/m61-test.ini | 1 - tests/trajectory-planner/circular-arcs/configs/9axis.ini | 2 -- tests/trajectory-planner/circular-arcs/configs/XY.ini | 2 -- tests/trajectory-planner/circular-arcs/configs/XYZ.ini | 2 -- tests/trajectory-planner/circular-arcs/configs/XYZ_fast.ini | 2 -- tests/trajectory-planner/circular-arcs/configs/XYZ_medium.ini | 2 -- .../trajectory-planner/circular-arcs/configs/XYZ_nospindle.ini | 2 -- tests/trajectory-planner/circular-arcs/configs/XYZ_uneven.ini | 2 -- tests/trajectory-planner/circular-arcs/configs/XY_slowZ.ini | 2 -- tests/trajectory-planner/circular-arcs/configs/XZ.ini | 2 -- tests/trajectory-planner/circular-arcs/configs/axis_mm.ini | 2 -- 42 files changed, 52 deletions(-) diff --git a/tests/abort/feed-rate/test.ini b/tests/abort/feed-rate/test.ini index d8acfe5dff9..36b3c1ca150 100644 --- a/tests/abort/feed-rate/test.ini +++ b/tests/abort/feed-rate/test.ini @@ -30,7 +30,6 @@ TASK = milltask CYCLE_TIME = 0.001 [HAL] -HALUI = halui HALFILE = core_sim.hal [HALUI] diff --git a/tests/abort/g64/test.ini b/tests/abort/g64/test.ini index f8dee4fe1ad..051ba44990f 100644 --- a/tests/abort/g64/test.ini +++ b/tests/abort/g64/test.ini @@ -28,7 +28,6 @@ TASK = milltask CYCLE_TIME = 0.001 [HAL] -HALUI = halui HALFILE = LIB:core_sim.hal HALFILE = motion-test.hal diff --git a/tests/ccomp/early-exit/test.ini b/tests/ccomp/early-exit/test.ini index 44e664dc5a0..db7340ab5a7 100644 --- a/tests/ccomp/early-exit/test.ini +++ b/tests/ccomp/early-exit/test.ini @@ -28,7 +28,6 @@ TASK = milltask CYCLE_TIME = 0.001 [HAL] -HALUI = halui HALFILE = core_sim.hal [HALUI] diff --git a/tests/halui/jogging/halui.ini b/tests/halui/jogging/halui.ini index 4fcd2b2b88f..acc1e1a6f94 100644 --- a/tests/halui/jogging/halui.ini +++ b/tests/halui/jogging/halui.ini @@ -22,7 +22,6 @@ BASE_PERIOD = 0 SERVO_PERIOD = 1000000 [HAL] -HALUI = halui HALFILE = LIB:core_sim.hal POSTGUI_HALFILE = postgui.hal diff --git a/tests/halui/mdi/halui.ini b/tests/halui/mdi/halui.ini index 052cd84a331..b55b8215f1b 100644 --- a/tests/halui/mdi/halui.ini +++ b/tests/halui/mdi/halui.ini @@ -22,7 +22,6 @@ CYCLE_TIME = 0.001 MDI_QUEUED_COMMANDS=10000 [HAL] -HALUI = halui HALFILE = LIB:core_sim.hal POSTGUI_HALFILE = postgui.hal diff --git a/tests/interp/g28.2/flush-order/test.ini b/tests/interp/g28.2/flush-order/test.ini index 38b6a739acb..8edb313dd14 100644 --- a/tests/interp/g28.2/flush-order/test.ini +++ b/tests/interp/g28.2/flush-order/test.ini @@ -19,7 +19,6 @@ BASE_PERIOD = 0 SERVO_PERIOD = 1000000 [HAL] -HALUI = halui HALFILE = LIB:core_sim.hal [TRAJ] diff --git a/tests/interp/g28.2/home-all-sequence/test.ini b/tests/interp/g28.2/home-all-sequence/test.ini index b55ba992d9b..2cb34a6e528 100644 --- a/tests/interp/g28.2/home-all-sequence/test.ini +++ b/tests/interp/g28.2/home-all-sequence/test.ini @@ -19,7 +19,6 @@ BASE_PERIOD = 0 SERVO_PERIOD = 1000000 [HAL] -HALUI = halui HALFILE = LIB:core_sim.hal [TRAJ] diff --git a/tests/interp/g28.2/immediate-mode-guard/test.ini b/tests/interp/g28.2/immediate-mode-guard/test.ini index eb1ecd04ca9..95e2516ac87 100644 --- a/tests/interp/g28.2/immediate-mode-guard/test.ini +++ b/tests/interp/g28.2/immediate-mode-guard/test.ini @@ -19,7 +19,6 @@ BASE_PERIOD = 0 SERVO_PERIOD = 1000000 [HAL] -HALUI = halui HALFILE = LIB:core_sim.hal [TRAJ] diff --git a/tests/interp/g28.2/invalid-pword/test.ini b/tests/interp/g28.2/invalid-pword/test.ini index c0b3db5b31a..d3b47c68490 100644 --- a/tests/interp/g28.2/invalid-pword/test.ini +++ b/tests/interp/g28.2/invalid-pword/test.ini @@ -19,7 +19,6 @@ BASE_PERIOD = 0 SERVO_PERIOD = 1000000 [HAL] -HALUI = halui HALFILE = LIB:core_sim.hal [TRAJ] diff --git a/tests/interp/g28.2/position-model/test.ini b/tests/interp/g28.2/position-model/test.ini index c725f5bf718..1f63941b0ab 100644 --- a/tests/interp/g28.2/position-model/test.ini +++ b/tests/interp/g28.2/position-model/test.ini @@ -19,7 +19,6 @@ BASE_PERIOD = 0 SERVO_PERIOD = 1000000 [HAL] -HALUI = halui HALFILE = LIB:core_sim.hal HALFILE = sim_extra.hal diff --git a/tests/interp/g28.2/sequencing/test.ini b/tests/interp/g28.2/sequencing/test.ini index eb1ecd04ca9..95e2516ac87 100644 --- a/tests/interp/g28.2/sequencing/test.ini +++ b/tests/interp/g28.2/sequencing/test.ini @@ -19,7 +19,6 @@ BASE_PERIOD = 0 SERVO_PERIOD = 1000000 [HAL] -HALUI = halui HALFILE = LIB:core_sim.hal [TRAJ] diff --git a/tests/interp/mdi-oword-m66/interp.ini b/tests/interp/mdi-oword-m66/interp.ini index f6eaa099929..ff1128df8d5 100644 --- a/tests/interp/mdi-oword-m66/interp.ini +++ b/tests/interp/mdi-oword-m66/interp.ini @@ -23,7 +23,6 @@ CYCLE_TIME = 0.001 MDI_QUEUED_COMMANDS=10000 [HAL] -HALUI = halui HALFILE = LIB:core_sim.hal POSTGUI_HALFILE = postgui.hal diff --git a/tests/interp/oword-mdi-sub-update/interp.ini b/tests/interp/oword-mdi-sub-update/interp.ini index 0774aa13db5..50f99de9258 100644 --- a/tests/interp/oword-mdi-sub-update/interp.ini +++ b/tests/interp/oword-mdi-sub-update/interp.ini @@ -22,7 +22,6 @@ BASE_PERIOD = 0 SERVO_PERIOD = 1000000 [HAL] -HALUI = halui HALFILE = LIB:core_sim.hal POSTGUI_HALFILE = postgui.hal diff --git a/tests/interp/subroutine-return/interp.ini b/tests/interp/subroutine-return/interp.ini index 18c4e6cb673..3ad89829196 100644 --- a/tests/interp/subroutine-return/interp.ini +++ b/tests/interp/subroutine-return/interp.ini @@ -23,7 +23,6 @@ BASE_PERIOD = 0 SERVO_PERIOD = 1000000 [HAL] -HALUI = halui HALFILE = LIB:core_sim.hal POSTGUI_HALFILE = postgui.hal diff --git a/tests/interp_initcode/test.ini b/tests/interp_initcode/test.ini index d183d9276b9..7e37f25610b 100644 --- a/tests/interp_initcode/test.ini +++ b/tests/interp_initcode/test.ini @@ -29,7 +29,6 @@ TOOL_TABLE = tool.tbl TOOL_CHANGE_POSITION = 0 0 2 [HAL] -HALUI = halui HALFILE = LIB:core_sim.hal HALFILE = LIB:simulated_home.hal HALFILE = LIB:lathe.hal diff --git a/tests/matrixkins/test.ini b/tests/matrixkins/test.ini index 662138a46a7..98be460a21b 100644 --- a/tests/matrixkins/test.ini +++ b/tests/matrixkins/test.ini @@ -27,7 +27,6 @@ TASK = milltask CYCLE_TIME = 0.001 [HAL] -HALUI = halui HALFILE = core_sim.hal [HALUI] diff --git a/tests/maxkins/test.ini b/tests/maxkins/test.ini index 7cf23c05738..8b28d176c3c 100644 --- a/tests/maxkins/test.ini +++ b/tests/maxkins/test.ini @@ -30,7 +30,6 @@ TASK = milltask CYCLE_TIME = 0.001 [HAL] -HALUI = halui HALFILE = core_sim.hal [HALUI] diff --git a/tests/mdi-queue-length/test.ini b/tests/mdi-queue-length/test.ini index c3c867680f3..fbda0260e13 100644 --- a/tests/mdi-queue-length/test.ini +++ b/tests/mdi-queue-length/test.ini @@ -21,7 +21,6 @@ TASK = milltask CYCLE_TIME = 0.001 [HAL] -HALUI = halui HALFILE = core_sim.hal [TRAJ] diff --git a/tests/mdi-while-queuebuster-waitflag/test.ini b/tests/mdi-while-queuebuster-waitflag/test.ini index 574763d8bee..32816c58090 100644 --- a/tests/mdi-while-queuebuster-waitflag/test.ini +++ b/tests/mdi-while-queuebuster-waitflag/test.ini @@ -22,7 +22,6 @@ TASK = milltask CYCLE_TIME = 0.001 [HAL] -HALUI = halui HALFILE = core_sim.hal [TRAJ] diff --git a/tests/mqtt/simulator.ini b/tests/mqtt/simulator.ini index ba7f9fc0232..aa8d6494263 100644 --- a/tests/mqtt/simulator.ini +++ b/tests/mqtt/simulator.ini @@ -25,7 +25,6 @@ TASK = milltask CYCLE_TIME = 0.001 [HAL] -HALUI = halui HALFILE = simulator.hal [HALUI] diff --git a/tests/remap/remap-io/test-ngc.ini b/tests/remap/remap-io/test-ngc.ini index 4ece72c8ff0..5d5250015dd 100644 --- a/tests/remap/remap-io/test-ngc.ini +++ b/tests/remap/remap-io/test-ngc.ini @@ -35,7 +35,6 @@ TASK = milltask CYCLE_TIME = 0.001 [HAL] -HALUI = halui HALFILE = core_sim.hal [HALUI] diff --git a/tests/remap/remap-io/test-py.ini b/tests/remap/remap-io/test-py.ini index d4d110f9948..fe94ace845d 100644 --- a/tests/remap/remap-io/test-py.ini +++ b/tests/remap/remap-io/test-py.ini @@ -35,7 +35,6 @@ TASK = milltask CYCLE_TIME = 0.001 [HAL] -HALUI = halui HALFILE = core_sim.hal [HALUI] diff --git a/tests/remap/remap-reentry/test.ini b/tests/remap/remap-reentry/test.ini index 1dc3cbe953a..46f82e8d21a 100644 --- a/tests/remap/remap-reentry/test.ini +++ b/tests/remap/remap-reentry/test.ini @@ -21,7 +21,6 @@ TASK = milltask CYCLE_TIME = 0.001 [HAL] -HALUI = halui HALFILE = core_sim.hal [TRAJ] diff --git a/tests/rs274ngc-startup/test.ini b/tests/rs274ngc-startup/test.ini index 93bb8db533a..fbb0442d7dc 100644 --- a/tests/rs274ngc-startup/test.ini +++ b/tests/rs274ngc-startup/test.ini @@ -29,7 +29,6 @@ TASK = milltask CYCLE_TIME = 0.001 [HAL] -HALUI = halui HALFILE = core_sim.hal [HALUI] diff --git a/tests/startup-state/test.ini b/tests/startup-state/test.ini index eb6773fbb25..303de104ca4 100644 --- a/tests/startup-state/test.ini +++ b/tests/startup-state/test.ini @@ -28,7 +28,6 @@ TASK = milltask CYCLE_TIME = 0.001 [HAL] -HALUI = halui HALFILE = core_sim.hal [HALUI] diff --git a/tests/statbuffer-g5x-abort/test.ini b/tests/statbuffer-g5x-abort/test.ini index ef2be910f43..80768c3a642 100644 --- a/tests/statbuffer-g5x-abort/test.ini +++ b/tests/statbuffer-g5x-abort/test.ini @@ -28,7 +28,6 @@ TASK = milltask CYCLE_TIME = 0.001 [HAL] -HALUI = halui HALFILE = core_sim.hal [HALUI] diff --git a/tests/tlo/g43-test.ini b/tests/tlo/g43-test.ini index 0b6d9beaa80..b56bb9923d2 100644 --- a/tests/tlo/g43-test.ini +++ b/tests/tlo/g43-test.ini @@ -21,7 +21,6 @@ CYCLE_TIME = 0.001 MDI_QUEUED_COMMANDS=10000 [HAL] -HALUI = halui HALFILE = mod_core_sim.hal POSTGUI_HALFILE = postgui.hal diff --git a/tests/tool-info/non-random/test.ini b/tests/tool-info/non-random/test.ini index 654191fb3f1..a0d34221906 100644 --- a/tests/tool-info/non-random/test.ini +++ b/tests/tool-info/non-random/test.ini @@ -24,7 +24,6 @@ TASK = milltask CYCLE_TIME = 0.001 [HAL] -HALUI = halui HALFILE = core_sim.hal [HALUI] diff --git a/tests/tool-info/random-no-startup-tool/test.ini b/tests/tool-info/random-no-startup-tool/test.ini index c002e1f8b36..a55d6fc7c02 100644 --- a/tests/tool-info/random-no-startup-tool/test.ini +++ b/tests/tool-info/random-no-startup-tool/test.ini @@ -24,7 +24,6 @@ TASK = milltask CYCLE_TIME = 0.001 [HAL] -HALUI = halui HALFILE = core_sim.hal [HALUI] diff --git a/tests/tool-info/random-with-startup-tool/test.ini b/tests/tool-info/random-with-startup-tool/test.ini index c002e1f8b36..a55d6fc7c02 100644 --- a/tests/tool-info/random-with-startup-tool/test.ini +++ b/tests/tool-info/random-with-startup-tool/test.ini @@ -24,7 +24,6 @@ TASK = milltask CYCLE_TIME = 0.001 [HAL] -HALUI = halui HALFILE = core_sim.hal [HALUI] diff --git a/tests/toolchanger/abort-during-change/abort-test.ini b/tests/toolchanger/abort-during-change/abort-test.ini index 3d7fc19cd75..0ee237cc8e6 100644 --- a/tests/toolchanger/abort-during-change/abort-test.ini +++ b/tests/toolchanger/abort-during-change/abort-test.ini @@ -20,7 +20,6 @@ BASE_PERIOD = 0 SERVO_PERIOD = 1000000 [HAL] -HALUI = halui HALFILE = mod_core_sim.hal POSTGUI_HALFILE = postgui.hal diff --git a/tests/toolchanger/m61/m61-test.ini b/tests/toolchanger/m61/m61-test.ini index e3ad9deae49..68e1303ff48 100644 --- a/tests/toolchanger/m61/m61-test.ini +++ b/tests/toolchanger/m61/m61-test.ini @@ -21,7 +21,6 @@ BASE_PERIOD = 0 SERVO_PERIOD = 1000000 [HAL] -HALUI = halui HALFILE = mod_core_sim.hal POSTGUI_HALFILE = postgui.hal diff --git a/tests/trajectory-planner/circular-arcs/configs/9axis.ini b/tests/trajectory-planner/circular-arcs/configs/9axis.ini index 13aa2b2fcd6..c3d93cb363f 100644 --- a/tests/trajectory-planner/circular-arcs/configs/9axis.ini +++ b/tests/trajectory-planner/circular-arcs/configs/9axis.ini @@ -104,8 +104,6 @@ HALFILE = constraint_check_9axis.tcl # AXIS at this time (only AXIS creates a HAL component of its own) POSTGUI_HALFILE = postgui_9axis.hal -HALUI = halui - # Trajectory planner section -------------------------------------------------- [TRAJ] diff --git a/tests/trajectory-planner/circular-arcs/configs/XY.ini b/tests/trajectory-planner/circular-arcs/configs/XY.ini index bd8095ee093..b0b89ef41df 100644 --- a/tests/trajectory-planner/circular-arcs/configs/XY.ini +++ b/tests/trajectory-planner/circular-arcs/configs/XY.ini @@ -112,8 +112,6 @@ HALFILE = sim_spindle_encoder.hal # AXIS at this time (only AXIS creates a HAL component of its own) POSTGUI_HALFILE = postgui.hal -HALUI = halui - # Trajectory planner section -------------------------------------------------- [TRAJ] diff --git a/tests/trajectory-planner/circular-arcs/configs/XYZ.ini b/tests/trajectory-planner/circular-arcs/configs/XYZ.ini index 9af90c0fc52..06ae2217483 100644 --- a/tests/trajectory-planner/circular-arcs/configs/XYZ.ini +++ b/tests/trajectory-planner/circular-arcs/configs/XYZ.ini @@ -111,8 +111,6 @@ HALFILE = sim_spindle_encoder.hal # AXIS at this time (only AXIS creates a HAL component of its own) POSTGUI_HALFILE = postgui.hal -HALUI = halui - # Trajectory planner section -------------------------------------------------- [TRAJ] diff --git a/tests/trajectory-planner/circular-arcs/configs/XYZ_fast.ini b/tests/trajectory-planner/circular-arcs/configs/XYZ_fast.ini index 6927d4f0381..c65bae120fd 100644 --- a/tests/trajectory-planner/circular-arcs/configs/XYZ_fast.ini +++ b/tests/trajectory-planner/circular-arcs/configs/XYZ_fast.ini @@ -111,8 +111,6 @@ HALFILE = sim_spindle_encoder.hal # AXIS at this time (only AXIS creates a HAL component of its own) POSTGUI_HALFILE = postgui.hal -HALUI = halui - # Trajectory planner section -------------------------------------------------- [TRAJ] diff --git a/tests/trajectory-planner/circular-arcs/configs/XYZ_medium.ini b/tests/trajectory-planner/circular-arcs/configs/XYZ_medium.ini index 6996743b6c7..072755a022b 100644 --- a/tests/trajectory-planner/circular-arcs/configs/XYZ_medium.ini +++ b/tests/trajectory-planner/circular-arcs/configs/XYZ_medium.ini @@ -112,8 +112,6 @@ HALFILE = sim_spindle_encoder.hal # AXIS at this time (only AXIS creates a HAL component of its own) POSTGUI_HALFILE = postgui.hal -HALUI = halui - # Trajectory planner section -------------------------------------------------- [TRAJ] diff --git a/tests/trajectory-planner/circular-arcs/configs/XYZ_nospindle.ini b/tests/trajectory-planner/circular-arcs/configs/XYZ_nospindle.ini index fb102d8b355..59728db01bd 100644 --- a/tests/trajectory-planner/circular-arcs/configs/XYZ_nospindle.ini +++ b/tests/trajectory-planner/circular-arcs/configs/XYZ_nospindle.ini @@ -97,8 +97,6 @@ HALFILE = test_status.tcl # AXIS at this time (only AXIS creates a HAL component of its own) POSTGUI_HALFILE = postgui.hal -HALUI = halui - # Trajectory planner section -------------------------------------------------- [TRAJ] diff --git a/tests/trajectory-planner/circular-arcs/configs/XYZ_uneven.ini b/tests/trajectory-planner/circular-arcs/configs/XYZ_uneven.ini index 9969e362ffd..0b2e550e3cd 100644 --- a/tests/trajectory-planner/circular-arcs/configs/XYZ_uneven.ini +++ b/tests/trajectory-planner/circular-arcs/configs/XYZ_uneven.ini @@ -111,8 +111,6 @@ HALFILE = sim_spindle_encoder.hal # AXIS at this time (only AXIS creates a HAL component of its own) POSTGUI_HALFILE = postgui.hal -HALUI = halui - # Trajectory planner section -------------------------------------------------- [TRAJ] diff --git a/tests/trajectory-planner/circular-arcs/configs/XY_slowZ.ini b/tests/trajectory-planner/circular-arcs/configs/XY_slowZ.ini index 7970522cceb..6e3beb171a8 100644 --- a/tests/trajectory-planner/circular-arcs/configs/XY_slowZ.ini +++ b/tests/trajectory-planner/circular-arcs/configs/XY_slowZ.ini @@ -111,8 +111,6 @@ HALFILE = sim_spindle_encoder.hal # AXIS at this time (only AXIS creates a HAL component of its own) POSTGUI_HALFILE = postgui.hal -HALUI = halui - # Trajectory planner section -------------------------------------------------- [TRAJ] diff --git a/tests/trajectory-planner/circular-arcs/configs/XZ.ini b/tests/trajectory-planner/circular-arcs/configs/XZ.ini index 376a5f786f1..866a1245b20 100644 --- a/tests/trajectory-planner/circular-arcs/configs/XZ.ini +++ b/tests/trajectory-planner/circular-arcs/configs/XZ.ini @@ -112,8 +112,6 @@ HALFILE = sim_spindle_encoder.hal # AXIS at this time (only AXIS creates a HAL component of its own) POSTGUI_HALFILE = postgui.hal -HALUI = halui - # Trajectory planner section -------------------------------------------------- [TRAJ] diff --git a/tests/trajectory-planner/circular-arcs/configs/axis_mm.ini b/tests/trajectory-planner/circular-arcs/configs/axis_mm.ini index a87b6f8f398..7c8d8f6a644 100644 --- a/tests/trajectory-planner/circular-arcs/configs/axis_mm.ini +++ b/tests/trajectory-planner/circular-arcs/configs/axis_mm.ini @@ -107,8 +107,6 @@ HALFILE = test_status.tcl # AXIS at this time (only AXIS creates a HAL component of its own) POSTGUI_HALFILE = postgui.hal -HALUI = halui - # Trajectory planner section -------------------------------------------------- [TRAJ] From 99b51400e2d265b418eb257f49a0c6bd063bad03 Mon Sep 17 00:00:00 2001 From: Rene Hopf Date: Sun, 20 Sep 2026 17:41:22 +0200 Subject: [PATCH 04/21] move halui to task --- debian/linuxcnc.install.in | 1 - docs/src/config/ini-config.adoc | 2 - docs/src/config/moveoff.adoc | 5 +- docs/src/gui/halui.adoc | 21 +- docs/src/hal/basic-hal.adoc | 2 +- docs/src/hal/halui-examples.adoc | 7 +- docs/src/hal/twopass.adoc | 1 - docs/src/man/man1/halui.1.adoc | 27 +- docs/src/man/man1/moveoff_gui.1.adoc | 7 - docs/src/plasma/qtplasmac.adoc | 1 - scripts/linuxcnc.in | 15 - src/emc/task/Submakefile | 2 + src/emc/task/cmd_queue.cc | 109 +++++ src/emc/task/cmd_queue.hh | 74 ++++ src/emc/task/emctaskmain.cc | 40 ++ src/emc/{usr_intf => task}/halui.cc | 560 ++++++++++--------------- src/emc/task/halui.hh | 30 ++ src/emc/usr_intf/Submakefile | 10 +- src/emc/usr_intf/pncconf/build_INI.py | 1 - src/emc/usr_intf/stepconf/build_INI.py | 2 - 20 files changed, 493 insertions(+), 424 deletions(-) create mode 100644 src/emc/task/cmd_queue.cc create mode 100644 src/emc/task/cmd_queue.hh rename src/emc/{usr_intf => task}/halui.cc (89%) create mode 100644 src/emc/task/halui.hh diff --git a/debian/linuxcnc.install.in b/debian/linuxcnc.install.in index d66045b43a5..80b405ddf5d 100644 --- a/debian/linuxcnc.install.in +++ b/debian/linuxcnc.install.in @@ -28,7 +28,6 @@ usr/bin/halscope usr/bin/halshow usr/bin/halstreamer usr/bin/haltcl -usr/bin/halui usr/bin/hbmgui usr/bin/hexagui usr/bin/hy_gt_vfd diff --git a/docs/src/config/ini-config.adoc b/docs/src/config/ini-config.adoc index 4980de30b1d..c019009d7de 100644 --- a/docs/src/config/ini-config.adoc +++ b/docs/src/config/ini-config.adoc @@ -778,8 +778,6 @@ For more information see the <> chapter. Some GUIs create HAL pins and support the use of a postgui halfile to use them. GUIs that support postgui HAL files include Touchy, AXIS, Gscreen, and GMOCCAPY. + See section <> for more information. -* `HALUI = halui` - adds the HAL user interface pins. + - For more information see the <> chapter. [[sub:ini:sec:halui]] === [HALUI] section(((INI File,Sections,[HALUI] Section))) diff --git a/docs/src/config/moveoff.adoc b/docs/src/config/moveoff.adoc index 81e1bb7d605..ed57ccc3079 100644 --- a/docs/src/config/moveoff.adoc +++ b/docs/src/config/moveoff.adoc @@ -114,8 +114,7 @@ to the corresponding joint. Modify an existing configuration as follows: -Make sure there is an INI file entry for `[HAL]HALUI` and create a new -`[HAL]HALFILE` entry for LIB:hookup_moveoff.tcl. +Create a new `[HAL]HALFILE` entry for LIB:hookup_moveoff.tcl. The entry for LIB:hookup_moveoff.tcl should follow all `HALFILE=` entries for HAL files that connect the pins for `joint.N.motor-pos-cmd`, `joint.N.motor-pos-fb`, and any components connected to these pins @@ -124,7 +123,6 @@ for HAL files that connect the pins for `joint.N.motor-pos-cmd`, [source,ini] ---- [HAL] -HALUI = halui HALFILE = existing_configuration_halfile_1 # ... HALFILE = existing_configuration_halfile_n @@ -216,7 +214,6 @@ and mv.bactrack-enable pins to signals: [source,ini] ---- [HAL] -HALUI = halui # ... HALFILE = LIB:hookup_moveoff.tcl HALFILE = LIB:moveoff_external.hal diff --git a/docs/src/gui/halui.adoc b/docs/src/gui/halui.adoc index e9c87f8c1ae..d7f501298a8 100644 --- a/docs/src/gui/halui.adoc +++ b/docs/src/gui/halui.adoc @@ -9,25 +9,12 @@ == Introduction Halui is a HAL based user interface for LinuxCNC, it connects HAL pins to -NML commands. Most of the functionality (buttons, indicators etc.) that +machine commands. Most of the functionality (buttons, indicators etc.) that is provided by a traditional GUI (AXIS, GMOCCAPY, QtDragon, etc.), is provided by HAL pins in Halui. -The easiest way to add halui is to add the following to the [HAL] -section of the INI file: - -[source,ini] ----- -[HAL] -HALUI = halui ----- - -An alternate way to invoke it (specially if you generate the configuration with StepConf) is to include the following in your `custom.hal` file. + -Make sure you use the correct path to your INI file. - -[source,hal] ----- -loadusr halui -ini /path/to/inifile.ini ----- +There is nothing to set up: the pins exist in every configuration, created +by the task controller before the HAL files are read, so a HAL file can +connect them straight away. Pins nobody connects cost nothing. == MDI diff --git a/docs/src/hal/basic-hal.adoc b/docs/src/hal/basic-hal.adoc index 0c800c56c9a..73166bd7c55 100644 --- a/docs/src/hal/basic-hal.adoc +++ b/docs/src/hal/basic-hal.adoc @@ -137,7 +137,7 @@ Flags may be one or more of the following: [source,hal] ---- loadusr -loadusr halui +loadusr hal_input loadusr -Wn spindle gs2_vfd -n spindle ---- diff --git a/docs/src/hal/halui-examples.adoc b/docs/src/hal/halui-examples.adoc index 2f237cc14cb..f0f7daab4ad 100644 --- a/docs/src/hal/halui-examples.adoc +++ b/docs/src/hal/halui-examples.adoc @@ -5,12 +5,7 @@ = Halui Examples (((Halui Examples))) -For any Halui examples to work you need to add the following line to the [HAL] section of the INI file. - -[source,ini] ----- -HALUI = halui ----- +The Halui pins are always available, so these examples work as they stand. [[sec:halui-remote-start]] == Remote Start diff --git a/docs/src/hal/twopass.adoc b/docs/src/hal/twopass.adoc index 7fdc48fae2c..fd50a15d5da 100644 --- a/docs/src/hal/twopass.adoc +++ b/docs/src/hal/twopass.adoc @@ -120,7 +120,6 @@ HALFILE = simulated_home.hal HALFILE = load_for_postgui.hal <- loadrt lines for components in postgui.hal POSTGUI_HALFILE = postgui.hal -HALUI = halui ---- == Post GUI diff --git a/docs/src/man/man1/halui.1.adoc b/docs/src/man/man1/halui.1.adoc index 861abcd04c0..d4244078d71 100644 --- a/docs/src/man/man1/halui.1.adoc +++ b/docs/src/man/man1/halui.1.adoc @@ -2,29 +2,24 @@ == NAME -halui - observe HAL pins and command LinuxCNC through NML - -== SYNOPSIS - -*halui* [*-ini* __] +halui - HAL pins to observe and command LinuxCNC == DESCRIPTION -The program *halui* is used to build a User Interface using hardware knobs and switches. -It exports a big number of pins, and acts accordingly when these change. - -== OPTIONS +*halui* is used to build a User Interface using hardware knobs and switches. +It provides a large number of HAL pins, and acts accordingly when these +change. -*-ini* _filename_:: - Use the _filename_ as the configuration file. Note: halui must find - the nml file specified in the INI, usually that file is in the same - folder as the INI, so it makes sense to run halui from that folder. +The pins are part of the LinuxCNC task controller and exist in every +configuration. There is nothing to load and nothing to configure: connect +the pins you want in a HAL file. Earlier versions ran halui as a separate +program, selected with *[HAL]HALUI* in the INI file; that setting is no +longer read. == USAGE -When run, *halui* will export a large number of pins. A user can connect -those to his physical knobs & switches & leds, and when a change is -noticed halui triggers an appropriate event. +A user can connect the pins to his physical knobs & switches & leds, and +when a change is noticed halui triggers an appropriate event. Caveat, *halui* expects the signals to be debounced, so if needed (bad knob contact) connect the physical button to a HAL debounce filter first. diff --git a/docs/src/man/man1/moveoff_gui.1.adoc b/docs/src/man/man1/moveoff_gui.1.adoc index 042b2aead0f..dd82617a6b9 100644 --- a/docs/src/man/man1/moveoff_gui.1.adoc +++ b/docs/src/man/man1/moveoff_gui.1.adoc @@ -73,12 +73,6 @@ These options are available for special cases: LinuxCNC must be running. -Halui must be loaded, typical INI file setting: ----- -[HAL] -HALUI = halui ----- - The moveoff component must be loaded with the name 'mv' as: + **loadrt moveoff names=**_mv **personality=**_number_of_axes_ @@ -107,7 +101,6 @@ HALFILE *hookup_moveoff.tcl* as illustrated below: ---- [HAL] -HALUI = halui HALFILE = user_halfile_1 etc ... HALFILE = user_halfile_n diff --git a/docs/src/plasma/qtplasmac.adoc b/docs/src/plasma/qtplasmac.adoc index bc68a12556c..7a852b00098 100644 --- a/docs/src/plasma/qtplasmac.adoc +++ b/docs/src/plasma/qtplasmac.adoc @@ -570,7 +570,6 @@ These variables are mandatory. [source,ini] ---- -HALUI = halui (required) HALFILE = __.hal (the machine HAL file) HALFILE = plasmac.tcl (the standard QtPlasmaC HAL file) HALFILE = custom.hal (Users custom HAL commands) diff --git a/scripts/linuxcnc.in b/scripts/linuxcnc.in index 3ab645da498..05e028f0d52 100644 --- a/scripts/linuxcnc.in +++ b/scripts/linuxcnc.in @@ -528,10 +528,6 @@ if [ "$EMCTASK" = emctask ]; then EMCTASK=linuxcnctask; fi # so it needs to start by default, as the first process EMCSERVER=linuxcncsvr -# 2.7. get halui information -GetFromIniQuiet HALUI HAL -HALUI=$retval - # 2.7.1 get halbridge info from INI GetFromIniQuiet HALBRIDGE HAL HALBRIDGE=$retval @@ -830,17 +826,6 @@ fi halcmd loadusr -Wn inihal "$EMCTASK" -ini "$INIFILE" -# 4.3.5. Run halui in background, if necessary -if [ -n "$HALUI" ] ; then - echo "Starting HAL User Interface program: $HALUI" >> "$PRINT_FILE" - if ! program_available "$HALUI" ; then - echo "Can't execute halui program $HALUI" - Cleanup - exit 1 - fi - $HALCMD loadusr -Wn halui "$HALUI" -ini "$INIFILE" -fi - # run hal bridge program IF requested if [ -n "$HALBRIDGE" ] ; then echo "Starting HAL User Interface program: $HALBRIDGE" >> "$PRINT_FILE" diff --git a/src/emc/task/Submakefile b/src/emc/task/Submakefile index 9fdab7004d6..3892cdeb7eb 100644 --- a/src/emc/task/Submakefile +++ b/src/emc/task/Submakefile @@ -23,6 +23,8 @@ MILLTASKSRCS := \ emc/motion/stashf.c \ emc/task/taskclass.cc \ emc/task/backtrace.cc \ + emc/task/cmd_queue.cc \ + emc/task/halui.cc \ emc/usr_intf/mapini.cc USERSRCS += $(MILLTASKSRCS) diff --git a/src/emc/task/cmd_queue.cc b/src/emc/task/cmd_queue.cc new file mode 100644 index 00000000000..2ba477d4c1a --- /dev/null +++ b/src/emc/task/cmd_queue.cc @@ -0,0 +1,109 @@ +/******************************************************************** +* Description: cmd_queue.cc +* Command injection point for task-internal command producers. +* See cmd_queue.hh for what it is for. +* +* License: GPL Version 2 +********************************************************************/ + +#include "cmd_queue.hh" + +#include "nml_intf/emc.hh" +#include "nml_intf/emc_nml.hh" + +#include +#include +#include +#include + +namespace { + +struct Entry { + std::vector data; /* the message, byte for byte */ + taskcmd::Ticket ticket = 0; + unsigned long key = 0; /* 0: never superseded */ +}; + +std::mutex g_mu; /* guards everything below */ +std::deque g_queue; +Entry g_current; /* keeps the popped message alive */ +taskcmd::Ticket g_next_ticket = 1; + +/* A backlog this long means the producer is far ahead of task and the + commands are stale anyway; dropping is better than growing without + bound. Jogs coalesce, so reaching this takes a genuine flood. */ +const size_t MAX_QUEUED = 64; + +} // namespace + +taskcmd::Ticket taskcmd::pushRaw(const void *cmd, size_t size, + unsigned long coalesce_key) +{ + if (cmd == NULL || size == 0 || size > MAX_CMD_SIZE) { + return 0; + } + + std::lock_guard lk(g_mu); + + const Ticket ticket = g_next_ticket++; + + if (coalesce_key != 0) { + for (Entry &e : g_queue) { + if (e.key != coalesce_key) { + continue; + } + /* Supersede in place: the newer command takes the older one's + turn, so ordering against other commands is unchanged. */ + e.data.assign(static_cast(cmd), + static_cast(cmd) + size); + e.ticket = ticket; + return ticket; + } + } + + if (g_queue.size() >= MAX_QUEUED) { + return 0; + } + + Entry e; + e.data.assign(static_cast(cmd), + static_cast(cmd) + size); + e.ticket = ticket; + e.key = coalesce_key; + g_queue.push_back(std::move(e)); + + return ticket; +} + +bool taskcmd::pending(Ticket ticket) +{ + if (ticket == 0) { + return false; + } + + std::lock_guard lk(g_mu); + for (const Entry &e : g_queue) { + if (e.ticket == ticket) { + return true; + } + } + return false; +} + +RCS_CMD_MSG *taskcmd::next(int echo_serial_number) +{ + std::lock_guard lk(g_mu); + + if (g_queue.empty()) { + return NULL; + } + + g_current = std::move(g_queue.front()); + g_queue.pop_front(); + + /* Task treats a command as new when its serial differs from the one it + last echoed, so hand it the next serial along. */ + RCS_CMD_MSG *msg = reinterpret_cast(g_current.data.data()); + msg->serial_number = echo_serial_number + 1; + return msg; +} diff --git a/src/emc/task/cmd_queue.hh b/src/emc/task/cmd_queue.hh new file mode 100644 index 00000000000..6e490d0dea4 --- /dev/null +++ b/src/emc/task/cmd_queue.hh @@ -0,0 +1,74 @@ +/******************************************************************** +* Description: cmd_queue.hh +* Command injection point for everything inside task that issues NML +* commands without going through the NML command channel. +* +* Task executes one command per cycle, taken either from the NML command +* buffer or from this queue. A command placed here is therefore judged by +* emcTaskPlan() exactly like one that arrived over NML: same mode and +* state gating, same serial-number echo, same error reporting. +* +* Two producers use it: +* - ws_server.cc, from the websocket server thread +* - halui.cc, from the task thread +* +* License: GPL Version 2 +********************************************************************/ +#ifndef TASK_CMD_QUEUE_HH +#define TASK_CMD_QUEUE_HH + +#include + +class RCS_CMD_MSG; + +namespace taskcmd { + +/* Biggest NML command that can be queued. EMC_TASK_PLAN_OPEN is the large + one (a LINELEN path plus a 4k remote transfer buffer). */ +const size_t MAX_CMD_SIZE = 8192; + +/* Identifies one queued command, so a producer can tell whether task has + taken it yet. Zero is never a valid ticket: push() returns 0 when the + queue is full, and pending(0) is false. */ +typedef unsigned long Ticket; + +/* Queue a copy of a command message. Thread safe. + + coalesce_key, when non-zero, means "this command supersedes any command + still queued under the same key": the pending one is overwritten in + place, keeping its position in the queue. It is for commands that carry + a state rather than an action -- a continuous jog is the case that + matters, where a producer running faster than task drains the queue + would otherwise build a backlog of stale velocities. Never use it for a + command that must happen exactly once, such as an incremental jog. + + The superseded command's ticket stops being pending without ever having + been executed, so a producer that watches a ticket must pass key 0. */ +Ticket pushRaw(const void *cmd, size_t size, unsigned long coalesce_key); + +template +Ticket push(const T &cmd, unsigned long coalesce_key = 0) +{ + static_assert(sizeof(T) <= MAX_CMD_SIZE, "NML command too large to queue"); + return pushRaw(&cmd, sizeof(T), coalesce_key); +} + +/* True while the command is still waiting. False once task has taken it -- + which, for a caller running in the task loop after the status update, + means the command has been issued and the status reflects it. */ +bool pending(Ticket ticket); + +/* Pop the next command, or NULL if none is waiting. Task loop only. + + The returned message stays valid until the next call and is meant to be + consumed exactly like one freshly read from NML. echo_serial_number is + the serial task last echoed; the message gets echo_serial_number + 1 so + that task's "is this a new command?" test fires. Task puts the serial + back afterwards without echoing it: an NML serial is the command + buffer's write id, and echoing one of those here would make task drop + the next command an NML client writes. */ +RCS_CMD_MSG *next(int echo_serial_number); + +} // namespace taskcmd + +#endif /* TASK_CMD_QUEUE_HH */ diff --git a/src/emc/task/emctaskmain.cc b/src/emc/task/emctaskmain.cc index 96fa4951eab..559c53293c5 100644 --- a/src/emc/task/emctaskmain.cc +++ b/src/emc/task/emctaskmain.cc @@ -86,6 +86,8 @@ fpu_control_t __fpu_control = _FPU_IEEE & ~(_FPU_MASK_IM | _FPU_MASK_ZM | _FPU_M #include "taskclass.hh" #include "motion/motion.h" // EMCMOT_ORIENT_* #include "ini/inihal.hh" +#include "halui.hh" // the HAL user interface, in task +#include "cmd_queue.hh" // commands from ws_server and halui using namespace linuxcnc; using namespace std::chrono_literals; @@ -108,6 +110,9 @@ static RCS_CMD_MSG *emcCommand = NULL; // global EMC status EMC_STAT *emcStatus = NULL; +// set while emcCommand points at a command from inside task (the websocket +// server or halui) rather than at the NML command buffer +static bool emcCommandInternal = false; // timer stuff static linuxcnc::CyclicTimer *timer = NULL; @@ -3352,6 +3357,9 @@ static int emctask_shutdown(void) delete timer; timer = NULL; } + // release the halui HAL component + haluiExit(); + // delete the NML channels if (NULL != emcErrorBuffer) { @@ -3523,6 +3531,15 @@ int main(int argc, char *argv[]) exit(1); } + // Create the halui pins before emctask_startup() readies the inihal + // component: halcmd is waiting on that and runs the HAL files next, + // and those may connect halui pins. + if (0 != haluiInit(emc_inifile)) { + log_error("can't initialize halui\n"); + emctask_shutdown(); + exit(1); + } + // initialize everything if (0 != emctask_startup()) { emctask_shutdown(); @@ -3560,6 +3577,17 @@ int main(int argc, char *argv[]) // read command if (0 != emcCommandBuffer->read()) { // got a new command, so clear out errors + emcCommand = emcCommandBuffer->get_address(); + emcCommandInternal = false; + taskPlanError = 0; + taskExecuteError = 0; + } else if (RCS_CMD_MSG *queued = + taskcmd::next(emcStatus->echo_serial_number)) { + // A command came from inside task -- the websocket server or + // halui. Point emcCommand at it and the rest of the loop treats + // it exactly like one read from NML. + emcCommand = queued; + emcCommandInternal = true; taskPlanError = 0; taskExecuteError = 0; } @@ -3703,6 +3731,16 @@ int main(int argc, char *argv[]) // handle RCS_STAT_MSG base class members explicitly, since this // is not an NML_MODULE and they won't be set automatically + // A command from inside task must not consume a serial number. An + // NML serial is the command buffer's write id, so echoing "one past + // the last NML command" is echoing the id the next NML client write + // will get, and task would then drop that command as one it has + // already seen. Leave the echo where the last NML command put it, + // and mark the internal message as seen so that emcTaskPlan() does + // not dispatch it again next cycle. + if (emcCommandInternal) { + emcCommand->serial_number = emcStatus->echo_serial_number; + } else { // do task emcStatus->task.command_type = emcCommand->_type; emcStatus->task.echo_serial_number = emcCommand->serial_number; @@ -3710,6 +3748,7 @@ int main(int argc, char *argv[]) // 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 || @@ -3737,6 +3776,7 @@ int main(int argc, char *argv[]) // will be updated in the _update() functions above. There's // no need to call the individual functions on all WM items. emcStatusBuffer->write(emcStatus); + haluiUpdate(); // wait on timer cycle, if specified, or calculate actual // interval if INI file says to run full out via diff --git a/src/emc/usr_intf/halui.cc b/src/emc/task/halui.cc similarity index 89% rename from src/emc/usr_intf/halui.cc rename to src/emc/task/halui.cc index c40e2831e73..cfbf16166ee 100644 --- a/src/emc/usr_intf/halui.cc +++ b/src/emc/task/halui.cc @@ -1,19 +1,38 @@ /******************************************************************** -* Description: halui.cc -* HAL User-Interface component. -* This file exports various UI related hal pins, and communicates -* with EMC through NML messages +* Description: halui.cc (task) +* The HAL user interface, running inside task. * -* Derived from a work by Fred Proctor & Will Shackleford (emcsh.cc) -* some of the functions (sendFooBar() are adapted from there) +* This was the standalone halui program (src/emc/usr_intf/halui.cc, now +* deleted) with its NML transport taken out. The pin table, the edge +* detection in check_hal_changes() and the status mirroring in +* modify_hal_pins() are the same code, so that behaviour -- including the +* quirks the tests in tests/halui pin down -- is unchanged. * -* Author: Alex Joni -* License: GPL Version 2 -* System: Linux +* What is different, and why: +* +* - No NML. Commands go into the task-internal queue (cmd_queue.hh), so +* they pass through emcTaskPlan() exactly like a command from a UI. +* Nothing waits for an echo: inside task, waiting for task to answer +* is a deadlock, since it is this thread that would have to answer. +* +* - MDI commands become a state machine, see sendMdiCommand() below. +* +* - Status is read straight out of the live EMC_STAT. halui sees it after +* task has finished the cycle's status update, which is the same +* picture an NML client gets, one cycle earlier. +* +* - The pin scan still runs at 20 ms, the standalone halui's loop period. +* The task cycle is typically 1 ms, and jog pins send a command per +* change, so running the whole scan every cycle would put up to a +* thousand commands a second through task's single command slot. +* estop-activate, machine-off, abort and program-stop are checked every +* cycle regardless. * -* Copyright (c) 2006 All rights reserved. +* halui is always there: there is nothing to switch on, and a machine +* that connects none of the pins pays for a pin scan every 20 ms. * -* Last change: +* Derived from the standalone halui.cc by Alex Joni, which this replaces. +* License: GPL Version 2 ********************************************************************/ #include "logutil.hh" @@ -22,9 +41,10 @@ #include #include #include -#include #include +#include + #include /* access to HAL functions/definitions */ #include /* rtapi_print_msg */ #include "rcs_status.hh" @@ -34,15 +54,16 @@ #include "nml_intf/emcglb.h" // EMC_NMLFILE, TRAJ_MAX_VELOCITY, etc. #include "nml_intf/emccfg.h" // DEFAULT_TRAJ_MAX_VELOCITY #include -#include "libnml/nml/nml_oi.hh" #include "timeutil.hh" #include #include "tooldata/tooldata.hh" -#include "mapini.hh" -#include "unitenum.hh" +#include "usr_intf/mapini.hh" +#include "usr_intf/unitenum.hh" + +#include "halui.hh" +#include "cmd_queue.hh" using namespace linuxcnc; -using namespace std::chrono_literals; /* Using halui: see the man page */ @@ -236,7 +257,7 @@ static char *mdi_commands[MDI_MAX]; static int num_mdi_commands=0; static int have_home_all = 0; -static int comp_id, done; /* component ID, main while loop */ +static int comp_id = -1; /* HAL component ID */ static int num_axes = 0; //number of axes, taken from the INI [TRAJ] section static int num_joints = 3; //number of joints, taken from the INI [KINS] section @@ -249,220 +270,38 @@ static double maxSpindleOverride=1.0; static EMC_TASK_MODE halui_old_mode = EMC_TASK_MODE::MANUAL; static int halui_sent_mdi = 0; -// the NML channels to the EMC task -static RCS_CMD_CHANNEL *emcCommandBuffer = NULL; -static RCS_STAT_CHANNEL *emcStatusBuffer = NULL; -EMC_STAT *emcStatus = NULL; - -// the NML channel for errors -static NML *emcErrorBuffer = NULL; - -// the serial number to use. -static int emcCommandSerialNumber = 0; - -// how long to wait for Task to report that it has received our command -static double receiveTimeout = 10.0; - -// how long to wait for Task to finish running our command -static double doneTimeout = 60.; - -static void quit(int /*sig*/) -{ - done = 1; -} - -static int emcTaskNmlGet() -{ - int retval = 0; - - // try to connect to EMC cmd - if (emcCommandBuffer == NULL) { - emcCommandBuffer = - new RCS_CMD_CHANNEL(emcFormat, "emcCommand", "xemc", - emc_nmlfile); - if (!emcCommandBuffer->valid()) { - delete emcCommandBuffer; - emcCommandBuffer = NULL; - retval = -1; - } - } - // try to connect to EMC status - if (emcStatusBuffer == NULL) { - emcStatusBuffer = - new RCS_STAT_CHANNEL(emcFormat, "emcStatus", "xemc", - emc_nmlfile); - if (!emcStatusBuffer->valid()) { - delete emcStatusBuffer; - emcStatusBuffer = NULL; - emcStatus = NULL; - retval = -1; - } else { - emcStatus = reinterpret_cast(emcStatusBuffer->get_address()); - } - } - - return retval; -} - -static int emcErrorNmlGet() -{ - int retval = 0; - - if (emcErrorBuffer == NULL) { - emcErrorBuffer = - new NML(nmlErrorFormat, "emcError", "xemc", emc_nmlfile); - if (!emcErrorBuffer->valid()) { - delete emcErrorBuffer; - emcErrorBuffer = NULL; - retval = -1; - } - } - - return retval; -} - -static int tryNml() -{ - std::chrono::seconds end; - int good; -constexpr auto RETRY_TIME = 10s; // wait for subsystems to come up -constexpr auto RETRY_INTERVAL = 1s; // between wait tries for a subsystem - - end = RETRY_TIME; - good = 0; - do { - if (0 == emcTaskNmlGet()) { - good = 1; - break; - } - esleep(RETRY_INTERVAL); - end -= RETRY_INTERVAL; - } while (end > 0s); - - if (!good) { - return -1; - } - end = RETRY_TIME; - good = 0; - do { - if (0 == emcErrorNmlGet()) { - good = 1; - break; - } - esleep(RETRY_INTERVAL); - end -= RETRY_INTERVAL; - } while (end > 0s); +// How often the pin scan runs, the standalone halui's loop period. +static const double HALUI_PERIOD = 0.020; - if (!good) { - return -1; - } - - return 0; +static double last_pass = 0.0; -} +// MDI state machine, see sendMdiCommand() +static std::deque mdi_pending; +static taskcmd::Ticket mdi_mode_ticket = 0; +static taskcmd::Ticket mdi_exec_ticket = 0; -static int updateStatus() +// Queue a command for task to execute on one of the next cycles. This is +// where the standalone halui wrote to the NML command channel and then +// waited for task to echo the serial number back. +// +// coalesce_key is passed for jogs only: see cmd_queue.hh. Returns 0 like +// the NML send it replaces, -1 if the queue is full. +template +static int emcCommandSend(const T &cmd, unsigned long coalesce_key = 0) { - NMLTYPE type; - - if (NULL == emcStatus || NULL == emcStatusBuffer) { - rtapi_print("halui: %s: no status buffer\n", __func__); + if (taskcmd::push(cmd, coalesce_key) == 0) { + rtapi_print("halui: %s: command queue full, dropping a command\n", __func__); return -1; } - - if (!emcStatusBuffer->valid()) { - rtapi_print("halui: %s: status buffer is not valid\n", __func__); - return -1; - } - - switch (type = emcStatusBuffer->peek()) { - case -1: - // error on CMS channel - rtapi_print("halui: %s: error peeking status buffer\n", __func__); - return -1; - break; - - case 0: // no new data - case EMC_STAT_TYPE: // new data - break; - - default: - rtapi_print("halui: %s: unknown error peeking status buffer\n", __func__); - return -1; - break; - } - return 0; } - -constexpr auto EMC_COMMAND_DELAY = 100ms; // how long to sleep between checks - -static int emcCommandWaitDone() -{ - for (auto end = 0ms; end < std::chrono::duration(doneTimeout); - end += EMC_COMMAND_DELAY) { - updateStatus(); - int serial_diff = emcStatus->echo_serial_number - emcCommandSerialNumber; - - if (serial_diff < 0) { - continue; - } - - if (serial_diff > 0) { - return 0; - } - - if (emcStatus->status == RCS_STATUS::DONE) { - return 0; - } - - if (emcStatus->status == RCS_STATUS::ERROR) { - return -1; - } - - esleep(EMC_COMMAND_DELAY); - } - - return -1; -} - -static int emcCommandSend(RCS_CMD_MSG & cmd) -{ - // write command - if (emcCommandBuffer->write(&cmd)) { - rtapi_print("halui: %s: error writing to Task\n", __func__); - return -1; - } - emcCommandSerialNumber = cmd.serial_number; - - // wait for receive - for (auto end = 0ms; end < std::chrono::duration(receiveTimeout); - end += EMC_COMMAND_DELAY) { - updateStatus(); - int serial_diff = emcStatus->echo_serial_number - emcCommandSerialNumber; - - if (serial_diff >= 0) { - return 0; - } - - esleep(EMC_COMMAND_DELAY); - } - - rtapi_print("halui: %s: no echo from Task after %.3f seconds\n", __func__, receiveTimeout); - return -1; -} - -static void thisQuit() +// One key per jog target, so that a new jog for a joint or axis replaces +// the one still waiting for it rather than queueing behind it. +static unsigned long jog_key(int ja, int jjogmode) { - //don't forget the big HAL sin ;) - hal_exit(comp_id); - - if(emcCommandBuffer) { delete emcCommandBuffer; emcCommandBuffer = NULL; } - if(emcStatusBuffer) { delete emcStatusBuffer; emcStatusBuffer = NULL; } - if(emcErrorBuffer) { delete emcErrorBuffer; emcErrorBuffer = NULL; } - exit(0); + return 1 + (unsigned long)(jjogmode ? 1 : 0) * 1024 + (unsigned long)ja; } static LINEAR_UNIT_CONVERSION linearUnitConversion = LINEAR_UNITS_AUTO; @@ -831,61 +670,95 @@ static int sendMdi() return emcCommandSend(mode_msg); } -static int sendMdiCommand(int n) +// Start an [HALUI]MDI_COMMAND. The standalone halui could block here: it +// sent the switch to MDI, waited for task to echo it, checked the mode and +// only then sent the command itself. Inside task nothing may block, so the +// sequence becomes a state machine, driven by service_mdi() below: +// +// press -> queue SET_MODE(MDI) -> task reaches MDI -> queue EXECUTE +// +// What the pins do is unchanged, including the two known quirks the tests +// pin down: halui-mdi-is-running goes true at the press, before task has +// accepted anything, and a command task refuses leaves it stuck until the +// next command finishes DONE. +static void sendMdiCommand(int n) { - EMC_TASK_PLAN_EXECUTE emc_task_plan_execute_msg; - - if (updateStatus()) { - return -1; - } - if (!halui_sent_mdi) { // There is currently no MDI command from halui executing, we're // currently starting the first one. Record what the Task mode is, // so we can restore it when all the MDI commands finish. halui_old_mode = emcStatus->task.mode; } - + halui_sent_mdi = 1; - if (num_mdi_commands>0){ - hal_set_bool(halui_data->halui_mdi_is_running, halui_sent_mdi); - updateStatus(); + if (num_mdi_commands > 0) { + hal_set_bool(halui_data->halui_mdi_is_running, halui_sent_mdi); } - + + mdi_pending.push_back(n); + // switch to MDI mode if needed - if (emcStatus->task.mode != EMC_TASK_MODE::MDI) { - if (sendMdi() != 0) { - rtapi_print("halui: %s: failed to Set Mode MDI\n", __func__); - return -1; - } - if (updateStatus() != 0) { - rtapi_print("halui: %s: failed to update status\n", __func__); - return -1; - } - if (emcStatus->task.mode != EMC_TASK_MODE::MDI) { - rtapi_print("halui: %s: switched mode, but got %d instead of mdi\n", __func__, (int)emcStatus->task.mode); - return -1; - } + if (emcStatus->task.mode != EMC_TASK_MODE::MDI && mdi_mode_ticket == 0) { + EMC_TASK_SET_MODE mode_msg; + mode_msg.mode = EMC_TASK_MODE::MDI; + mdi_mode_ticket = taskcmd::push(mode_msg); } - rtapi_strxcpy(emc_task_plan_execute_msg.command, mdi_commands[n]); - if (emcCommandSend(emc_task_plan_execute_msg)) { - rtapi_print("halui: %s: failed to send mdi command %d\n", __func__, n); - return -1; +} + +// Issue the MDI commands waiting for task to be in MDI mode, or give up on +// them if task did not go there. Runs every task cycle. +static void service_mdi() +{ + if (mdi_pending.empty()) { + return; } - return 0; + if (emcStatus->task.mode == EMC_TASK_MODE::MDI) { + mdi_mode_ticket = 0; + while (!mdi_pending.empty()) { + EMC_TASK_PLAN_EXECUTE emc_task_plan_execute_msg; + rtapi_strxcpy(emc_task_plan_execute_msg.command, + mdi_commands[mdi_pending.front()]); + mdi_exec_ticket = taskcmd::push(emc_task_plan_execute_msg); + mdi_pending.pop_front(); + } + return; + } + + if (!taskcmd::pending(mdi_mode_ticket)) { + // Task has been through the mode change and is not in MDI, so it + // refused it -- while a program runs, for instance. Drop the + // commands, exactly as the standalone halui did when its mode + // check failed. halui_sent_mdi deliberately stays set: the pins + // recover on the next command that ends DONE. + rtapi_print("halui: %s: could not switch task to mdi, dropping %d command(s)\n", + __func__, (int)mdi_pending.size()); + mdi_pending.clear(); + mdi_mode_ticket = 0; + } } +// True once the MDI command halui started has actually been issued by task +// (not merely queued), which is what the standalone halui knew by waiting +// for the echo before it returned from sendMdiCommand(). +static bool mdi_settled() +{ + return halui_sent_mdi + && mdi_pending.empty() + && !taskcmd::pending(mdi_mode_ticket) + && !taskcmd::pending(mdi_exec_ticket); +} + +// The standalone halui waited here for task to finish the mode change, +// up to 60 seconds. Inside task that wait is the deadlock it sounds like: +// task cannot finish anything while halui holds the loop. static int sendTeleop() { EMC_TRAJ_SET_TELEOP_ENABLE emc_set_teleop_enable_msg; emc_set_teleop_enable_msg.enable = 1; - if (emcCommandSend(emc_set_teleop_enable_msg)) { - return -1; - } - return emcCommandWaitDone(); + return emcCommandSend(emc_set_teleop_enable_msg); } static int sendJoint() @@ -893,10 +766,7 @@ static int sendJoint() EMC_TRAJ_SET_TELEOP_ENABLE emc_set_teleop_enable_msg; emc_set_teleop_enable_msg.enable = 0; - if (emcCommandSend(emc_set_teleop_enable_msg)) { - return -1; - } - return emcCommandWaitDone(); + return emcCommandSend(emc_set_teleop_enable_msg); } static int sendMistOn() @@ -935,8 +805,6 @@ static int sendProgramRun(int line) { EMC_TASK_PLAN_RUN emc_task_plan_run_msg; - updateStatus(); - if (0 == emcStatus->task.file[0]) { return -1; // no program open } @@ -1093,7 +961,7 @@ static void sendJogStop(int ja, int jjogmode) emc_jog_stop_msg.jjogmode = jjogmode; emc_jog_stop_msg.joint_or_axis = ja; - emcCommandSend(emc_jog_stop_msg); + emcCommandSend(emc_jog_stop_msg, jog_key(ja, jjogmode)); } @@ -1116,7 +984,7 @@ static void sendJogCont(int ja, double speed, int jjogmode) emc_jog_cont_msg.joint_or_axis = ja; emc_jog_cont_msg.vel = speed / 60.0; - emcCommandSend(emc_jog_cont_msg); + emcCommandSend(emc_jog_cont_msg, jog_key(ja, jjogmode)); } static void sendJogIncr(int ja, double speed, double incr, int jjogmode) @@ -1207,7 +1075,7 @@ static int sendSpindleOverride(int spindle, double override) return emcCommandSend(emc_traj_set_spindle_scale_msg); } -static int iniLoad(const char *filename) +static int haluiIniLoad(const char *filename) { IniFile inifile(filename); @@ -1215,24 +1083,6 @@ static int iniLoad(const char *filename) return -1; } - // EMC debugging flags - emc_debug = (unsigned)inifile.findUIntV("DEBUG", "EMC", 0); - - if (emc_debug & EMC_DEBUG_CONFIG) { - std::string version = inifile.findStringV("VERSION", "EMC", ""); - std::string machine = inifile.findStringV("MACHINE", "EMC", ""); - extern char *program_invocation_short_name; - log_info( - "{} ({}) halui: machine '{}' version '{}'\n", - program_invocation_short_name, getpid(), machine, version - ); - } - - if (auto inistring = inifile.findString("NML_FILE", "EMC")) { - // copy to global - rtapi_strxcpy(emc_nmlfile, inistring->c_str()); - } // else not found, use default - if (auto inival = inifile.findReal("MAX_FEED_OVERRIDE", "DISPLAY")) { if (*inival > 0.0) { maxFeedOverride = *inival; @@ -1423,6 +1273,28 @@ static bool jogging_selected_axis(local_halui_str &hal) { } +// The pins where a 20 ms sampling period is the wrong answer. They are +// checked every task cycle; check_bit_changed() updates old_halui_data, so +// the full pass below does not see the same edge a second time. +static void check_safety_pins() +{ + if (check_bit_changed(hal_get_bool(halui_data->estop_activate), + old_halui_data.estop_activate) != 0) + sendEstop(); + + if (check_bit_changed(hal_get_bool(halui_data->machine_off), + old_halui_data.machine_off) != 0) + sendMachineOff(); + + if (check_bit_changed(hal_get_bool(halui_data->abort), + old_halui_data.abort) != 0) + sendAbort(); + + if (check_bit_changed(hal_get_bool(halui_data->program_stop), + old_halui_data.program_stop) != 0) + sendAbort(); +} + // this function looks if any of the hal pins has changed // and sends appropriate messages if so static void check_hal_changes() @@ -1907,10 +1779,10 @@ static void modify_hal_pins() hal_set_bool(halui_data->estop_is_activated, emcStatus->task.state == EMC_TASK_STATE::ESTOP); // Decide once whether an ongoing halui MDI command has finished: the mode - // restore below refreshes emcStatus, and Task may echo it while still EXEC. - bool mdi_finished = halui_sent_mdi && emcStatus->status == RCS_STATUS::DONE; + // restore below may refresh emcStatus, and Task may echo it while still EXEC. + bool mdi_finished = mdi_settled() && emcStatus->status == RCS_STATUS::DONE; - if (halui_sent_mdi) { // we have an ongoing MDI command + if (mdi_settled()) { // we have an ongoing MDI command if (mdi_finished) { //which seems to have finished switch (halui_old_mode) { case EMC_TASK_MODE::MANUAL: sendManual();break; @@ -1935,12 +1807,12 @@ static void modify_hal_pins() if (num_mdi_commands>0){ // we wants initialize program_is_idle and mode_is_mdi before halui_sent_mdi - if (halui_sent_mdi) { // we have an ongoing MDI command + if (mdi_settled()) { // we have an ongoing MDI command if (mdi_finished) { //which seems to have finished halui_sent_mdi = 0; - esleep(20ms); //sleep for a while - updateStatus(); - esleep(20ms); //sleep for a while + mdi_exec_ticket = 0; + // the standalone halui slept 2x20ms around a status + // re-read here; in task the status is already current } } hal_set_bool(halui_data->halui_mdi_is_running, halui_sent_mdi); @@ -2097,68 +1969,74 @@ static void modify_hal_pins() -int main(int argc, char *argv[]) -{ - // process command line args - if (0 != emcGetArgs(argc, argv)) { - log_error("error in argument list\n"); - exit(1); - } - // get configuration information - if (0 != iniLoad(emc_inifile)) { - log_error("iniLoad error\n"); - exit(2); +/******************************************************************** +* +* The three entry points task uses. See halui.hh. +* +********************************************************************/ + +int haluiInit(const char *filename) +{ + if (0 != haluiIniLoad(filename)) { + log_error("halui: iniLoad error\n"); + return -1; } - //init HAL and export pins if (0 != halui_hal_init()) { - log_error("hal_init error\n"); - exit(1); + log_error("halui: hal_init error\n"); + // the export helpers hal_exit() the component themselves + comp_id = -1; + return -1; } - //initialize safe values hal_init_pins(); + return 0; +} - // init NML - if (0 != tryNml()) { - log_error("can't connect to emc\n"); - thisQuit(); - exit(1); - } - -#ifdef TOOL_NML //{ - //fprintf(stderr,"%8d HALUI REGISTER %p\n",getpid(), - tool_nml_register((CANON_TOOL_TABLE*)&emcStatus->io.tool.toolTable); -#else //}{ - tool_mmap_user(); -#endif //} - - // get current serial number, and save it for restoring when we quit - // so as not to interfere with real operator interface - updateStatus(); - - done = 0; - /* Register the routine that catches the SIGINT signal */ - signal(SIGINT, quit); - /* catch SIGTERM too - the run script uses it to shut things down */ - signal(SIGTERM, quit); - - while (!done) { - static bool task_start_synced = 0; - if (!task_start_synced) { - // wait for task to establish nonzero linearUnits - if (emcStatus->motion.traj.linearUnits != 0) { - // set once at startup, no changes are expected: - hal_set_real(halui_data->units_per_mm, emcStatus->motion.traj.linearUnits); - task_start_synced = 1; - } +void haluiUpdate(void) +{ + if (comp_id < 0) { + return; + } + + static bool task_start_synced = false; + if (!task_start_synced) { + // wait for task to establish nonzero linearUnits + if (emcStatus->motion.traj.linearUnits != 0) { + // set once at startup, no changes are expected: + hal_set_real(halui_data->units_per_mm, emcStatus->motion.traj.linearUnits); + task_start_synced = true; } - check_hal_changes(); //if anything changed send NML messages + } + + // every cycle: the pins that should not wait for the next pass + check_safety_pins(); + + const double now = etime(); + const bool due = (now - last_pass) >= HALUI_PERIOD; + + if (due) { + last_pass = now; + check_hal_changes(); //if anything changed send commands + } + + // every cycle, and after check_hal_changes() so that a button pressed + // in this pass is acted on in it + service_mdi(); + + if (due) { modify_hal_pins(); //if status changed modify HAL too - esleep(20ms); //sleep for a while - updateStatus(); } - thisQuit(); - return 0; +} + +void haluiExit(void) +{ + if (comp_id < 0) { + return; + } + + //don't forget the big HAL sin ;) + hal_exit(comp_id); + comp_id = -1; } diff --git a/src/emc/task/halui.hh b/src/emc/task/halui.hh new file mode 100644 index 00000000000..c825b70dd75 --- /dev/null +++ b/src/emc/task/halui.hh @@ -0,0 +1,30 @@ +/******************************************************************** +* Description: halui.hh +* The HAL user interface, running inside task. +* +* This is the whole interface task sees; everything else lives in +* halui.cc, the way ws_server.cc holds the websocket transport. +* +* License: GPL Version 2 +********************************************************************/ +#ifndef TASK_HALUI_HH +#define TASK_HALUI_HH + +/* Create the halui HAL component and its pins. Returns 0, or -1 on + failure. There is nothing to configure: the pins are always there, and + cost nothing to a machine that connects none of them. + + Call this before ini_hal_init(): halcmd's "loadusr -Wn inihal" returns as + soon as the inihal component is ready, and the HAL files -- which may + well "net" halui pins -- run immediately afterwards. */ +int haluiInit(const char *inifile); + +/* Read the input pins, write the status pins. Called once per task cycle. + Most of the work is internally rate limited to 20 ms, which was the + standalone halui's loop period. */ +void haluiUpdate(void); + +/* Release the HAL component. Safe to call if haluiInit() never ran. */ +void haluiExit(void); + +#endif /* TASK_HALUI_HH */ diff --git a/src/emc/usr_intf/Submakefile b/src/emc/usr_intf/Submakefile index 33c030bea38..121bcfe3b0a 100644 --- a/src/emc/usr_intf/Submakefile +++ b/src/emc/usr_intf/Submakefile @@ -13,10 +13,7 @@ EMCLCDSRCS := emc/usr_intf/emclcd.cc \ emc/usr_intf/shcom.cc \ emc/usr_intf/sockets.cc -HALUISRCS := emc/usr_intf/halui.cc \ - emc/usr_intf/mapini.cc - -USERSRCS += $(EMCSHSRCS) $(EMCRSHSRCS) $(EMCSCHEDSRCS) $(EMCLCDSRCS) $(USRMOTSRCS) $(HALUISRCS) +USERSRCS += $(EMCSHSRCS) $(EMCRSHSRCS) $(EMCSCHEDSRCS) $(EMCLCDSRCS) $(USRMOTSRCS) $(call TOOBJSDEPS, $(EMCSHSRCS)) : EXTRAFLAGS = $(ULFLAGS) $(TCL_CFLAGS) -fPIC @@ -41,8 +38,3 @@ TARGETS += ../bin/schedrmt $(ECHO) Linking $(notdir $@) $(Q)$(CXX) -o $@ $(ULFLAGS) $^ -lfmt $(LDFLAGS) TARGETS += ../bin/linuxcnclcd - -../bin/halui: $(call TOOBJS, $(HALUISRCS)) ../lib/liblinuxcnc.a ../lib/liblinuxcncini.so.1 ../lib/libnml.so.0 ../lib/liblinuxcnchal.so.0 ../lib/libtooldata.so.0 - $(ECHO) Linking $(notdir $@) - $(Q)$(CXX) $(CXXFLAGS) -o $@ $(ULFLAGS) $^ -lfmt $(LDFLAGS) -TARGETS += ../bin/halui diff --git a/src/emc/usr_intf/pncconf/build_INI.py b/src/emc/usr_intf/pncconf/build_INI.py index 379978a4cff..b2529e683c6 100644 --- a/src/emc/usr_intf/pncconf/build_INI.py +++ b/src/emc/usr_intf/pncconf/build_INI.py @@ -267,7 +267,6 @@ def write_inifile(self, base): print("%s=%s"%(a,b), file=file) print(file=file) print("[HAL]", file=file) - print("HALUI = halui", file=file) print("HALFILE = %s.hal" % self.d.machinename, file=file) # qtplasmac requires the qtplasmac_comp file to connect the plasmac component if self.d.frontend == _PD._QTPLASMAC: diff --git a/src/emc/usr_intf/stepconf/build_INI.py b/src/emc/usr_intf/stepconf/build_INI.py index 6bf173b3ce8..0bfb550a1cc 100644 --- a/src/emc/usr_intf/stepconf/build_INI.py +++ b/src/emc/usr_intf/stepconf/build_INI.py @@ -212,8 +212,6 @@ def write_inifile(self, base): print(file=file) print("[HAL]", file=file) - if self.d.halui or self.d.select_qtplasmac: - print("HALUI = halui", file=file) print("HALFILE = %s.hal" % self.d.machinename, file=file) # qtplasmac requires custom, custom_postgui and shutdown hal files if self.d.select_qtplasmac: From bdf222d4b4f53e76e0eab95ba1a7f210be777e4b Mon Sep 17 00:00:00 2001 From: Rene Hopf Date: Sun, 20 Sep 2026 18:44:00 +0200 Subject: [PATCH 05/21] remove halui from ci --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d412317f24f..12bcaf82254 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -108,7 +108,7 @@ jobs: fi done for f in scripts/linuxcnc scripts/halrun bin/linuxcncrsh bin/linuxcncsvr \ - bin/halcmd bin/halui bin/mdi bin/linuxcnctop; do + bin/halcmd bin/mdi bin/linuxcnctop; do if test ! -x "$f"; then echo "error: missing headless artifact: $f" exit 1 From 02f1522052bdef87be96fb344e8e9c6c72aa1b59 Mon Sep 17 00:00:00 2001 From: Rene Hopf Date: Mon, 21 Sep 2026 12:16:17 +0200 Subject: [PATCH 06/21] fix halui tests --- tests/halui/_lib/halui_test.py | 36 +++++++++++++++++++++++++++------- tests/halui/axes/test-ui.py | 16 +++++++++++---- 2 files changed, 41 insertions(+), 11 deletions(-) diff --git a/tests/halui/_lib/halui_test.py b/tests/halui/_lib/halui_test.py index 6911f786a02..6a4fd54c465 100644 --- a/tests/halui/_lib/halui_test.py +++ b/tests/halui/_lib/halui_test.py @@ -40,6 +40,14 @@ HALUI_PERIOD = 0.02 HOLD = 0.15 TIMEOUT = 5.0 +# Per-attempt wait for a task_state change, and how many times to reissue it. +# The transition normally lands well under a second, but the first one after +# startup can be refused outright: task is still coming up while the harness +# is still enumerating and wiring halui's ~250 pins, so nothing has settled +# by the time the first section runs. ui-smoke's ensure_state() reissues for +# the same reason (see tests/ui-smoke/_lib/drive.py). +STATE_ATTEMPT_TIMEOUT = 3.0 +STATE_RETRY_BUDGET = 6 COMP = 'halui-test' @@ -95,8 +103,14 @@ def __init__(self): self.cmd = linuxcnc.command() self.errors = linuxcnc.error_channel() self.poll() - self.log('harness up: %d halui pins, %d wired externally' - % (len(self.pins), len(self.external))) + # Until task publishes its first status, task_state reads 0, which is + # not STATE_ESTOP and not STATE_ON -- branching on it would skip the + # estop clear below and leave every later state(ON) refused. The + # harness can be up 4ms after launch, so this is reached routinely. + if not self.wait_for(lambda: self.stat.task_state != 0): + raise RuntimeError('setup: task never published a state') + self.log('harness up: %d halui pins, %d wired externally, task_state=%d' + % (len(self.pins), len(self.external), self.stat.task_state)) # -- reporting --------------------------------------------------------- @@ -246,15 +260,23 @@ def nml_state(self, state): # task has no distinct OFF state: a request for OFF reads back as # ESTOP_RESET want = linuxcnc.STATE_ESTOP_RESET if state == linuxcnc.STATE_OFF else state - self.cmd.state(state) - self.cmd.wait_complete() - return self.wait_for(lambda: self.stat.task_state == want) + for attempt in range(1, STATE_RETRY_BUDGET + 1): + self.cmd.state(state) + self.cmd.wait_complete() + if self.wait_for(lambda: self.stat.task_state == want, + timeout=STATE_ATTEMPT_TIMEOUT): + return True + self.log('task_state %d not reached on attempt %d, retrying' + % (want, attempt)) + return False def machine_on(self): if self.poll().task_state == linuxcnc.STATE_ON: return - if self.stat.task_state == linuxcnc.STATE_ESTOP: - self.nml_state(linuxcnc.STATE_ESTOP_RESET) + # Unconditional: a machine that is not ON may be in estop whatever the + # last poll said, and STATE_ON is refused until estop is cleared. + if not self.nml_state(linuxcnc.STATE_ESTOP_RESET): + raise RuntimeError('setup: could not clear estop') if not self.nml_state(linuxcnc.STATE_ON): raise RuntimeError('setup: could not turn the machine on') diff --git a/tests/halui/axes/test-ui.py b/tests/halui/axes/test-ui.py index 83217d91b8d..034580b0ef4 100755 --- a/tests/halui/axes/test-ui.py +++ b/tests/halui/axes/test-ui.py @@ -254,9 +254,17 @@ def selected_jog(h): h.nml_abort() -def expected_relative(s): - """halui's own formula (modify_hal_pins) from task's offsets.""" - ax, ay, az = s.actual_position[:3] +def expected_relative(s, machine=None): + """halui's own formula (modify_hal_pins) from task's offsets. + + `machine` is the machine position to model from. Pass the position the + caller has just asserted rather than letting it default: a move is only + confirmed to expect_at()'s 1e-4, so actual_position can still be settling + by that much, while expect_positions() compares the result at 1e-6. Under + load that gap shows up as a ~5e-5 miss on pos-relative alone -- the + commanded/feedback checks compare against exact literals and pass. + """ + ax, ay, az = machine if machine is not None else s.actual_position[:3] g5x, g92, tlo, rot = s.g5x_offset, s.g92_offset, s.tool_offset, s.rotation_xy x = ax - g5x[0] - tlo[0] y = ay - g5x[1] - tlo[1] @@ -307,7 +315,7 @@ def positions(h): h.set('axis.x.increment', 0.5) h.pulse('axis.x.increment-plus') expect_at(h, 'x', 3.5, 'after an increment in teleop') - rel = expected_relative(h.poll()) + rel = expected_relative(h.poll(), (3.5, 4, 1)) expect_positions(h, (3.5, 4, 1), rel, 'after moving X by 0.5') for code in ('G92.1', 'G49', 'G10 L2 P1 X0 Y0 Z0 R0', 'M61 Q0'): From 3c5ccb07fd37deadef4846901556e161083a76e2 Mon Sep 17 00:00:00 2001 From: Rene Hopf Date: Fri, 16 Oct 2026 11:12:00 +0200 Subject: [PATCH 07/21] remove remaining HALUI settings from configs and tests --- configs/sim/axis/db_demo/base.inc | 1 - configs/sim/axis/ini_with_includes/hal.inc | 1 - configs/sim/axis/ja_tests/xz/xzbase.inc | 1 - configs/sim/axis/xhc-hb04/README | 1 - configs/sim/qtplasmac/qtplasmac_imperial_ini.inc | 1 - configs/sim/qtplasmac/qtplasmac_metric_ini.inc | 1 - configs/sim/tklinuxcnc/trivkins/xzbase.inc | 1 - configs/sim/touchy/ngcgui/pyngcgui_touchy_moveoff.txt | 1 - configs/sim/touchy/ngcgui/pyngcgui_touchy_moveoff_es.txt | 1 - tests/workplane-preview/test.ini | 1 - tests/workplane-retain/clear.ini | 1 - tests/workplane-retain/test.ini | 1 - 12 files changed, 12 deletions(-) diff --git a/configs/sim/axis/db_demo/base.inc b/configs/sim/axis/db_demo/base.inc index 8330fee7eb5..142df4c93e4 100644 --- a/configs/sim/axis/db_demo/base.inc +++ b/configs/sim/axis/db_demo/base.inc @@ -20,7 +20,6 @@ EMCMOT = motmod SERVO_PERIOD = 1000000 [HAL] -HALUI=halui HALFILE = LIB:basic_sim.tcl -no_use_hal_manualtoolchange POSTGUI_HALFILE = db_postgui.hal diff --git a/configs/sim/axis/ini_with_includes/hal.inc b/configs/sim/axis/ini_with_includes/hal.inc index f627913c476..25843406070 100644 --- a/configs/sim/axis/ini_with_includes/hal.inc +++ b/configs/sim/axis/ini_with_includes/hal.inc @@ -5,4 +5,3 @@ # list of hal config files to run through halcmd # files are executed in the order in which they appear HALFILE = LIB:basic_sim.tcl -HALUI = halui diff --git a/configs/sim/axis/ja_tests/xz/xzbase.inc b/configs/sim/axis/ja_tests/xz/xzbase.inc index 0ed6ec2841a..bf35154d4a3 100644 --- a/configs/sim/axis/ja_tests/xz/xzbase.inc +++ b/configs/sim/axis/ja_tests/xz/xzbase.inc @@ -1,6 +1,5 @@ [HAL] HALFILE = LIB:basic_sim.tcl - HALUI = halui [TRAJ] COORDINATES = XZ diff --git a/configs/sim/axis/xhc-hb04/README b/configs/sim/axis/xhc-hb04/README index 6b7aba395c3..8468387af72 100644 --- a/configs/sim/axis/xhc-hb04/README +++ b/configs/sim/axis/xhc-hb04/README @@ -162,7 +162,6 @@ For example, the organization for the xhc-hb04-layout2.ini file is: ... | HALFILE = | HALFILE = LIB:xhc-hb04.tcl | xhc-hb04 configuration script - HALUI = halui | Halui specifier [XHC_HB04_CONFIG] | All config items used by LIB:xhc-hb04.tcl layout = | diff --git a/configs/sim/qtplasmac/qtplasmac_imperial_ini.inc b/configs/sim/qtplasmac/qtplasmac_imperial_ini.inc index 23f990a8d0e..881a6872d59 100644 --- a/configs/sim/qtplasmac/qtplasmac_imperial_ini.inc +++ b/configs/sim/qtplasmac/qtplasmac_imperial_ini.inc @@ -19,7 +19,6 @@ HALFILE = qtplasmac_comp.hal HALFILE = custom.hal POSTGUI_HALFILE = custom_postgui.hal POSTGUI_HALFILE = sim_postgui.hal -HALUI = halui [EMC] VERSION = 1.1 diff --git a/configs/sim/qtplasmac/qtplasmac_metric_ini.inc b/configs/sim/qtplasmac/qtplasmac_metric_ini.inc index 12e6c3fb39e..82f0df7c161 100644 --- a/configs/sim/qtplasmac/qtplasmac_metric_ini.inc +++ b/configs/sim/qtplasmac/qtplasmac_metric_ini.inc @@ -19,7 +19,6 @@ HALFILE = qtplasmac_comp.hal HALFILE = custom.hal POSTGUI_HALFILE = custom_postgui.hal POSTGUI_HALFILE = sim_postgui.hal -HALUI = halui [EMC] VERSION = 1.1 diff --git a/configs/sim/tklinuxcnc/trivkins/xzbase.inc b/configs/sim/tklinuxcnc/trivkins/xzbase.inc index b78b08f35f5..6bb1b111101 100644 --- a/configs/sim/tklinuxcnc/trivkins/xzbase.inc +++ b/configs/sim/tklinuxcnc/trivkins/xzbase.inc @@ -1,6 +1,5 @@ [HAL] HALFILE = LIB:basic_sim.tcl - HALUI = halui [TRAJ] COORDINATES = XZ diff --git a/configs/sim/touchy/ngcgui/pyngcgui_touchy_moveoff.txt b/configs/sim/touchy/ngcgui/pyngcgui_touchy_moveoff.txt index df58dc90c87..8154e407807 100644 --- a/configs/sim/touchy/ngcgui/pyngcgui_touchy_moveoff.txt +++ b/configs/sim/touchy/ngcgui/pyngcgui_touchy_moveoff.txt @@ -5,7 +5,6 @@ modifies pyngcgui_touchy.ini to use: [HAL] ... HALFILE = hookup_move.tcl -HALUI = halui APP = moveoff_gui \ -size 20 -loc center \ diff --git a/configs/sim/touchy/ngcgui/pyngcgui_touchy_moveoff_es.txt b/configs/sim/touchy/ngcgui/pyngcgui_touchy_moveoff_es.txt index 4c920b3708e..84b30d69da0 100644 --- a/configs/sim/touchy/ngcgui/pyngcgui_touchy_moveoff_es.txt +++ b/configs/sim/touchy/ngcgui/pyngcgui_touchy_moveoff_es.txt @@ -5,7 +5,6 @@ modifica pyngcgui_touchy.ini para usar: [HAL] ... HALFILE = hookup_move.tcl -HALUI = halui APP = moveoff_gui \ -size 20 -loc center \ diff --git a/tests/workplane-preview/test.ini b/tests/workplane-preview/test.ini index 51a235f0cff..1f8daf8cb04 100644 --- a/tests/workplane-preview/test.ini +++ b/tests/workplane-preview/test.ini @@ -29,7 +29,6 @@ TOOL_TABLE = tool.tbl TOOL_CHANGE_POSITION = 0 0 2 [HAL] -HALUI = halui HALFILE = LIB:core_sim.hal HALFILE = LIB:simulated_home.hal HALFILE = LIB:lathe.hal diff --git a/tests/workplane-retain/clear.ini b/tests/workplane-retain/clear.ini index 891b931cef0..cd41d92f2c4 100644 --- a/tests/workplane-retain/clear.ini +++ b/tests/workplane-retain/clear.ini @@ -29,7 +29,6 @@ TOOL_TABLE = tool.tbl TOOL_CHANGE_POSITION = 0 0 2 [HAL] -HALUI = halui HALFILE = LIB:core_sim.hal HALFILE = LIB:simulated_home.hal HALFILE = LIB:lathe.hal diff --git a/tests/workplane-retain/test.ini b/tests/workplane-retain/test.ini index 2fd2850e903..e58fa29def4 100644 --- a/tests/workplane-retain/test.ini +++ b/tests/workplane-retain/test.ini @@ -30,7 +30,6 @@ TOOL_TABLE = tool.tbl TOOL_CHANGE_POSITION = 0 0 2 [HAL] -HALUI = halui HALFILE = LIB:core_sim.hal HALFILE = LIB:simulated_home.hal HALFILE = LIB:lathe.hal From 235032b01c9e6c4057777c72487f8ab2331cb6d3 Mon Sep 17 00:00:00 2001 From: Rene Hopf Date: Fri, 16 Oct 2026 11:12:00 +0200 Subject: [PATCH 08/21] halui: fix comments and docs Drop references to a websocket server that is not in the tree, list the INI settings halui still reads, and state the cost of unused pins consistently. --- docs/src/gui/halui.adoc | 9 +++++++-- docs/src/man/man1/halui.1.adoc | 22 ++++++++++++++++++---- src/emc/task/cmd_queue.hh | 6 +++--- src/emc/task/emctaskmain.cc | 12 ++++++------ src/emc/task/halui.hh | 7 ++++--- 5 files changed, 38 insertions(+), 18 deletions(-) diff --git a/docs/src/gui/halui.adoc b/docs/src/gui/halui.adoc index d7f501298a8..18d287ac60b 100644 --- a/docs/src/gui/halui.adoc +++ b/docs/src/gui/halui.adoc @@ -12,9 +12,14 @@ Halui is a HAL based user interface for LinuxCNC, it connects HAL pins to machine commands. Most of the functionality (buttons, indicators etc.) that is provided by a traditional GUI (AXIS, GMOCCAPY, QtDragon, etc.), is provided by HAL pins in Halui. -There is nothing to set up: the pins exist in every configuration, created +There is nothing to load: the pins exist in every configuration, created by the task controller before the HAL files are read, so a HAL file can -connect them straight away. Pins nobody connects cost nothing. +connect them straight away. A configuration that connects none of them +pays only for a pin scan every 20 ms. + +Earlier versions ran halui as a separate program, started with +`[HAL]HALUI = halui` in the INI file or `loadusr halui` in a HAL file. +Neither is needed any more; remove them from existing configurations. == MDI diff --git a/docs/src/man/man1/halui.1.adoc b/docs/src/man/man1/halui.1.adoc index d4244078d71..8f3fdc853c6 100644 --- a/docs/src/man/man1/halui.1.adoc +++ b/docs/src/man/man1/halui.1.adoc @@ -11,10 +11,24 @@ It provides a large number of HAL pins, and acts accordingly when these change. The pins are part of the LinuxCNC task controller and exist in every -configuration. There is nothing to load and nothing to configure: connect -the pins you want in a HAL file. Earlier versions ran halui as a separate -program, selected with *[HAL]HALUI* in the INI file; that setting is no -longer read. +configuration. There is nothing to load: connect the pins you want in a +HAL file. Earlier versions ran halui as a separate program, selected with +*[HAL]HALUI* in the INI file or started with *loadusr halui*; neither is +needed any more. + +== INI FILE + +halui still reads these INI settings: + +*[HALUI]MDI_COMMAND*:: + An MDI command to run when the matching *halui.mdi-command-NN* pin goes + true. May be given up to 64 times. +*[DISPLAY]MAX_FEED_OVERRIDE*:: + Upper limit for the feed override set through halui. +*[DISPLAY]MIN_SPINDLE_OVERRIDE*, *[DISPLAY]MAX_SPINDLE_OVERRIDE*:: + Limits for the spindle override set through halui. +*[TRAJ]COORDINATES*:: + Which *halui.axis.L.\** pins are created. == USAGE diff --git a/src/emc/task/cmd_queue.hh b/src/emc/task/cmd_queue.hh index 6e490d0dea4..d05f6f6f493 100644 --- a/src/emc/task/cmd_queue.hh +++ b/src/emc/task/cmd_queue.hh @@ -8,9 +8,9 @@ * emcTaskPlan() exactly like one that arrived over NML: same mode and * state gating, same serial-number echo, same error reporting. * -* Two producers use it: -* - ws_server.cc, from the websocket server thread -* - halui.cc, from the task thread +* halui.cc, running in the task thread, is the only producer today. +* push() is thread safe, so a transport running in its own thread can +* use it too. * * License: GPL Version 2 ********************************************************************/ diff --git a/src/emc/task/emctaskmain.cc b/src/emc/task/emctaskmain.cc index 559c53293c5..bbe9a8b2cc7 100644 --- a/src/emc/task/emctaskmain.cc +++ b/src/emc/task/emctaskmain.cc @@ -87,7 +87,7 @@ fpu_control_t __fpu_control = _FPU_IEEE & ~(_FPU_MASK_IM | _FPU_MASK_ZM | _FPU_M #include "motion/motion.h" // EMCMOT_ORIENT_* #include "ini/inihal.hh" #include "halui.hh" // the HAL user interface, in task -#include "cmd_queue.hh" // commands from ws_server and halui +#include "cmd_queue.hh" // commands from inside task (halui) using namespace linuxcnc; using namespace std::chrono_literals; @@ -110,8 +110,8 @@ static RCS_CMD_MSG *emcCommand = NULL; // global EMC status EMC_STAT *emcStatus = NULL; -// set while emcCommand points at a command from inside task (the websocket -// server or halui) rather than at the NML command buffer +// set while emcCommand points at a command from inside task (halui) +// rather than at the NML command buffer static bool emcCommandInternal = false; // timer stuff @@ -3583,9 +3583,9 @@ int main(int argc, char *argv[]) taskExecuteError = 0; } else if (RCS_CMD_MSG *queued = taskcmd::next(emcStatus->echo_serial_number)) { - // A command came from inside task -- the websocket server or - // halui. Point emcCommand at it and the rest of the loop treats - // it exactly like one read from NML. + // A command came from inside task (halui). Point emcCommand at + // it and the rest of the loop treats it exactly like one read + // from NML. emcCommand = queued; emcCommandInternal = true; taskPlanError = 0; diff --git a/src/emc/task/halui.hh b/src/emc/task/halui.hh index c825b70dd75..7a64e5d1f55 100644 --- a/src/emc/task/halui.hh +++ b/src/emc/task/halui.hh @@ -3,7 +3,7 @@ * The HAL user interface, running inside task. * * This is the whole interface task sees; everything else lives in -* halui.cc, the way ws_server.cc holds the websocket transport. +* halui.cc. * * License: GPL Version 2 ********************************************************************/ @@ -11,8 +11,9 @@ #define TASK_HALUI_HH /* Create the halui HAL component and its pins. Returns 0, or -1 on - failure. There is nothing to configure: the pins are always there, and - cost nothing to a machine that connects none of them. + failure. There is nothing to load: the pins are always there, and a + machine that connects none of them pays only for a pin scan every + 20 ms. Call this before ini_hal_init(): halcmd's "loadusr -Wn inihal" returns as soon as the inihal component is ready, and the HAL files -- which may From 355af12c91918671a7c9d9aae639ad7152d961ff Mon Sep 17 00:00:00 2001 From: Rene Hopf Date: Fri, 16 Oct 2026 11:12:00 +0200 Subject: [PATCH 09/21] halui: keep a compatibility stub and warn about [HAL]HALUI Configurations that still run 'loadusr halui' would fail to start now that the program is gone. Install a halui stub that prints a warning and exits successfully, warn at startup when [HAL]HALUI is set, and add a migration note to the update docs. --- debian/linuxcnc.install.in | 1 + docs/src/getting-started/updating-linuxcnc.adoc | 15 +++++++++++++++ scripts/halui | 9 +++++++++ scripts/linuxcnc.in | 7 +++++++ src/Makefile | 1 + 5 files changed, 33 insertions(+) create mode 100755 scripts/halui diff --git a/debian/linuxcnc.install.in b/debian/linuxcnc.install.in index 80b405ddf5d..d66045b43a5 100644 --- a/debian/linuxcnc.install.in +++ b/debian/linuxcnc.install.in @@ -28,6 +28,7 @@ usr/bin/halscope usr/bin/halshow usr/bin/halstreamer usr/bin/haltcl +usr/bin/halui usr/bin/hbmgui usr/bin/hexagui usr/bin/hy_gt_vfd diff --git a/docs/src/getting-started/updating-linuxcnc.adoc b/docs/src/getting-started/updating-linuxcnc.adoc index 63decc6e5e2..2f9e5960909 100644 --- a/docs/src/getting-started/updating-linuxcnc.adoc +++ b/docs/src/getting-started/updating-linuxcnc.adoc @@ -232,6 +232,21 @@ link:../man/man1/mesambccc.1.html[mesambccc(1)]. The 2.9 release retains the framework, so its documentation remains available in the http://linuxcnc.org/docs/2.9/html/drivers/mesa_modbus.html[2.9 docs]. +=== halui is part of the task controller + +halui is no longer a separate program. Its pins are created by the task +controller in every configuration, before the HAL files are read, so +there is nothing to start. Remove these from existing configurations: + +* `HALUI = halui` in the `[HAL]` section of the INI file. It is no longer + read; LinuxCNC prints a warning at startup while it is still there. +* `loadusr halui` (with or without `-W`/`-Wn halui` and `-ini ...`) in a + HAL file. A compatibility `halui` stub still accepts this and prints a + warning; it will be removed in a later release. + +The pins, `[HALUI]MDI_COMMAND` and the `[DISPLAY]` override limits work +as before, see link:../gui/halui.html[HAL User Interface]. + == Preview renderer now requires OpenGL 3.3 core diff --git a/scripts/halui b/scripts/halui new file mode 100755 index 00000000000..15921048e43 --- /dev/null +++ b/scripts/halui @@ -0,0 +1,9 @@ +#!/bin/sh +# halui used to be a separate program. Its pins are now created by the task +# controller in every configuration, so there is nothing left to start. +# This stub keeps configurations that still run "loadusr halui" working, +# and tells their owners to remove that line. +echo "halui: the halui pins are built into the task controller now;" \ + "remove 'loadusr halui' from your HAL file (and [HAL]HALUI from" \ + "your INI file). This compatibility stub will be removed." >&2 +exit 0 diff --git a/scripts/linuxcnc.in b/scripts/linuxcnc.in index 05e028f0d52..5edb0990ba4 100644 --- a/scripts/linuxcnc.in +++ b/scripts/linuxcnc.in @@ -528,6 +528,13 @@ if [ "$EMCTASK" = emctask ]; then EMCTASK=linuxcnctask; fi # so it needs to start by default, as the first process EMCSERVER=linuxcncsvr +# 2.7. halui is part of task now; [HAL]HALUI is no longer read +GetFromIniQuiet HALUI HAL +if [ -n "$retval" ] ; then + echo "Warning: [HAL]HALUI is no longer needed, the halui pins are built" \ + "into the task controller. Remove it from $INIFILE." >&2 +fi + # 2.7.1 get halbridge info from INI GetFromIniQuiet HALBRIDGE HAL HALBRIDGE=$retval diff --git a/src/Makefile b/src/Makefile index df19b0c3dc7..3bd45ec6775 100644 --- a/src/Makefile +++ b/src/Makefile @@ -664,6 +664,7 @@ endif $(EXE) ../scripts/latency-plot $(DESTDIR)$(bindir) $(EXE) ../scripts/latency-histogram $(DESTDIR)$(bindir) $(EXE) ../scripts/moveoff_gui $(DESTDIR)$(bindir) + $(EXE) ../scripts/halui $(DESTDIR)$(bindir) $(EXE) ../scripts/hal-histogram $(DESTDIR)$(bindir) $(EXE) ../scripts/xhc-hb04-accels $(DESTDIR)$(bindir) $(EXE) ../scripts/pyvcp_demo $(DESTDIR)$(bindir) From 77a491fdb36218c4b0f6c8a17c1e6512915908b7 Mon Sep 17 00:00:00 2001 From: Rene Hopf Date: Fri, 16 Oct 2026 11:58:34 +0200 Subject: [PATCH 10/21] tests: remove the halui move verification tests They pinned down halui's behaviour so the move into task could be checked for changes. That is done; the pre-existing halui/jogging and halui/mdi tests stay. --- tests/halui/.gitignore | 5 - tests/halui/_lib/coverage.py | 60 --- tests/halui/_lib/halui_test.py | 369 ----------------- tests/halui/_lib/launch.sh | 8 - tests/halui/_lib/tool.tbl | 3 - tests/halui/axes/checkresult | 2 - tests/halui/axes/halui.ini | 100 ----- tests/halui/axes/test-ui.py | 332 ---------------- tests/halui/axes/test.sh | 2 - tests/halui/config-9axis/checkresult | 2 - tests/halui/config-9axis/halui.ini | 194 --------- tests/halui/config-9axis/nine.hal | 19 - tests/halui/config-9axis/test-ui.py | 130 ------ tests/halui/config-9axis/test.sh | 2 - tests/halui/config-minimal/checkresult | 2 - tests/halui/config-minimal/halui.ini | 74 ---- tests/halui/config-minimal/minimal.hal | 12 - tests/halui/config-minimal/test-ui.py | 172 -------- tests/halui/config-minimal/test.sh | 2 - tests/halui/joints/checkresult | 2 - tests/halui/joints/halui.ini | 100 ----- tests/halui/joints/test-ui.py | 442 --------------------- tests/halui/joints/test.sh | 2 - tests/halui/machine-state/checkresult | 2 - tests/halui/machine-state/halui.ini | 100 ----- tests/halui/machine-state/test-ui.py | 188 --------- tests/halui/machine-state/test.sh | 2 - tests/halui/mdi-commands/checkresult | 2 - tests/halui/mdi-commands/halui.ini | 102 ----- tests/halui/mdi-commands/long.ngc | 5 - tests/halui/mdi-commands/test-ui.py | 182 --------- tests/halui/mdi-commands/test.sh | 2 - tests/halui/overrides/checkresult | 2 - tests/halui/overrides/halui.ini | 100 ----- tests/halui/overrides/test-ui.py | 230 ----------- tests/halui/overrides/test.sh | 2 - tests/halui/program/block-delete.ngc | 4 - tests/halui/program/checkresult | 2 - tests/halui/program/halui.ini | 100 ----- tests/halui/program/long.ngc | 5 - tests/halui/program/optional-stop.ngc | 5 - tests/halui/program/step.ngc | 5 - tests/halui/program/test-ui.py | 295 -------------- tests/halui/program/test.sh | 2 - tests/halui/spindle-coolant/checkresult | 2 - tests/halui/spindle-coolant/halui.ini | 100 ----- tests/halui/spindle-coolant/test-ui.py | 171 -------- tests/halui/spindle-coolant/test.sh | 2 - tests/halui/startup-halfile/checkresult | 2 - tests/halui/startup-halfile/halui-nets.hal | 7 - tests/halui/startup-halfile/halui.ini | 102 ----- tests/halui/startup-halfile/test-ui.py | 67 ---- tests/halui/startup-halfile/test.sh | 2 - tests/halui/tool/checkresult | 2 - tests/halui/tool/halui.ini | 100 ----- tests/halui/tool/test-ui.py | 112 ------ tests/halui/tool/test.sh | 2 - 57 files changed, 4044 deletions(-) delete mode 100644 tests/halui/_lib/coverage.py delete mode 100644 tests/halui/_lib/halui_test.py delete mode 100755 tests/halui/_lib/launch.sh delete mode 100644 tests/halui/_lib/tool.tbl delete mode 100755 tests/halui/axes/checkresult delete mode 100644 tests/halui/axes/halui.ini delete mode 100755 tests/halui/axes/test-ui.py delete mode 100755 tests/halui/axes/test.sh delete mode 100755 tests/halui/config-9axis/checkresult delete mode 100644 tests/halui/config-9axis/halui.ini delete mode 100644 tests/halui/config-9axis/nine.hal delete mode 100755 tests/halui/config-9axis/test-ui.py delete mode 100755 tests/halui/config-9axis/test.sh delete mode 100755 tests/halui/config-minimal/checkresult delete mode 100644 tests/halui/config-minimal/halui.ini delete mode 100644 tests/halui/config-minimal/minimal.hal delete mode 100755 tests/halui/config-minimal/test-ui.py delete mode 100755 tests/halui/config-minimal/test.sh delete mode 100755 tests/halui/joints/checkresult delete mode 100644 tests/halui/joints/halui.ini delete mode 100755 tests/halui/joints/test-ui.py delete mode 100755 tests/halui/joints/test.sh delete mode 100755 tests/halui/machine-state/checkresult delete mode 100644 tests/halui/machine-state/halui.ini delete mode 100755 tests/halui/machine-state/test-ui.py delete mode 100755 tests/halui/machine-state/test.sh delete mode 100755 tests/halui/mdi-commands/checkresult delete mode 100644 tests/halui/mdi-commands/halui.ini delete mode 100644 tests/halui/mdi-commands/long.ngc delete mode 100755 tests/halui/mdi-commands/test-ui.py delete mode 100755 tests/halui/mdi-commands/test.sh delete mode 100755 tests/halui/overrides/checkresult delete mode 100644 tests/halui/overrides/halui.ini delete mode 100755 tests/halui/overrides/test-ui.py delete mode 100755 tests/halui/overrides/test.sh delete mode 100644 tests/halui/program/block-delete.ngc delete mode 100755 tests/halui/program/checkresult delete mode 100644 tests/halui/program/halui.ini delete mode 100644 tests/halui/program/long.ngc delete mode 100644 tests/halui/program/optional-stop.ngc delete mode 100644 tests/halui/program/step.ngc delete mode 100755 tests/halui/program/test-ui.py delete mode 100755 tests/halui/program/test.sh delete mode 100755 tests/halui/spindle-coolant/checkresult delete mode 100644 tests/halui/spindle-coolant/halui.ini delete mode 100755 tests/halui/spindle-coolant/test-ui.py delete mode 100755 tests/halui/spindle-coolant/test.sh delete mode 100755 tests/halui/startup-halfile/checkresult delete mode 100644 tests/halui/startup-halfile/halui-nets.hal delete mode 100644 tests/halui/startup-halfile/halui.ini delete mode 100755 tests/halui/startup-halfile/test-ui.py delete mode 100755 tests/halui/startup-halfile/test.sh delete mode 100755 tests/halui/tool/checkresult delete mode 100644 tests/halui/tool/halui.ini delete mode 100755 tests/halui/tool/test-ui.py delete mode 100755 tests/halui/tool/test.sh diff --git a/tests/halui/.gitignore b/tests/halui/.gitignore index 31d40592f97..b23febc81d7 100644 --- a/tests/halui/.gitignore +++ b/tests/halui/.gitignore @@ -1,7 +1,2 @@ sim.var.bak sim.var -# the halui pin tests copy _lib/tool.tbl in fresh on every run -*/tool.tbl -!_lib/tool.tbl -# per-run list of the halui pins a test touched -*/touched-pins.txt diff --git a/tests/halui/_lib/coverage.py b/tests/halui/_lib/coverage.py deleted file mode 100644 index 8cf13f34b6a..00000000000 --- a/tests/halui/_lib/coverage.py +++ /dev/null @@ -1,60 +0,0 @@ -#!/usr/bin/env python3 -"""Report which halui pins the halui test suite exercises. - -Each test run leaves touched-pins.txt in its directory. This merges them and -matches them against every pin name pattern in halui.cc, so the report stays -honest when halui gains or loses pins. - - python3 tests/halui/_lib/coverage.py -""" - -import glob -import os -import re -import sys - -HERE = os.path.dirname(os.path.abspath(__file__)) -SUITE = os.path.dirname(HERE) -HALUI_CC = os.path.join(SUITE, '..', '..', 'src', 'emc', 'usr_intf', 'halui.cc') - -SPEC = re.compile(r'%[-+ #0]*\d*(?:\.\d+)?[diouxXcs]') - - -def pattern_regex(pattern): - parts = SPEC.split(pattern) - out = re.escape(parts[0]) - for rest in parts[1:]: - out += r'[A-Za-z0-9_]+' + re.escape(rest) - return re.compile('^' + out + '$') - - -def main(): - with open(HALUI_CC) as f: - patterns = sorted(set(p[len('halui.'):] for p in - re.findall(r'"(halui\.[A-Za-z0-9_.%\-]+)"', f.read()))) - - touched, runs = set(), [] - for path in sorted(glob.glob(os.path.join(SUITE, '*', 'touched-pins.txt'))): - runs.append(os.path.basename(os.path.dirname(path))) - with open(path) as f: - touched.update(line.strip() for line in f if line.strip()) - - if not runs: - print('no touched-pins.txt found; run the halui tests first') - return 1 - - covered = [p for p in patterns if any(pattern_regex(p).match(t) for t in touched)] - missing = [p for p in patterns if p not in covered] - - print('halui pin coverage from %d test runs: %s' % (len(runs), ', '.join(runs))) - print('%d of %d pin patterns exercised (%.0f%%)' - % (len(covered), len(patterns), 100.0 * len(covered) / len(patterns))) - if missing: - print('not exercised:') - for p in missing: - print(' halui.' + p) - return 0 - - -if __name__ == '__main__': - sys.exit(main()) diff --git a/tests/halui/_lib/halui_test.py b/tests/halui/_lib/halui_test.py deleted file mode 100644 index 6a4fd54c465..00000000000 --- a/tests/halui/_lib/halui_test.py +++ /dev/null @@ -1,369 +0,0 @@ -"""Shared harness for the halui pin tests. - -Each test directory runs linuxcnc with its test-ui.py as the [DISPLAY] -program, so the harness starts once halui and task are both up. It: - - - Finds every pin halui exported and creates a mirror pin with the opposite - direction on its own HAL component, wired straight to it. Tests drive - halui's inputs and read its outputs by suffix: - h.set('machine.on', 1) - h.get('machine.is-on') - - - Talks to task through the stock linuxcnc python module. That is used only - for test setup (opening a program, homing before a jog test, ...) and as - ground truth for what task actually did -- never as the thing under test. - - - Records every check. A failed check is reported and the run carries on, - so one run shows everything that is broken. The process exits non-zero at - the end if anything failed. - -The tests assert what halui does today. Where today's behaviour is a bug, the -check goes through known_bug() with an explanation: the suite is a baseline -that flags any change in behaviour, and fixing one of those bugs has to -update its test deliberately. - -The tests only look at pins and task state, so the same suite applies -whether halui runs as its own process or inside task. -""" - -import math -import os -import sys -import time -import traceback - -import hal -import linuxcnc - -# halui polls its pins and task's status every 20 ms. Holding an input for a -# few of those guarantees halui samples both edges. -HALUI_PERIOD = 0.02 -HOLD = 0.15 -TIMEOUT = 5.0 -# Per-attempt wait for a task_state change, and how many times to reissue it. -# The transition normally lands well under a second, but the first one after -# startup can be refused outright: task is still coming up while the harness -# is still enumerating and wiring halui's ~250 pins, so nothing has settled -# by the time the first section runs. ui-smoke's ensure_state() reissues for -# the same reason (see tests/ui-smoke/_lib/drive.py). -STATE_ATTEMPT_TIMEOUT = 3.0 -STATE_RETRY_BUDGET = 6 - -COMP = 'halui-test' - - -class Halui: - - def __init__(self): - self.t0 = time.time() - self.checks = 0 - self.failures = [] - self.known_bugs = [] - self.touched = set() - - # Every pin halui exported, by suffix: {'machine.on': (type, dir)}, - # and the value each input had before we wired it (halui's default). - self.pins = {} - self.defaults = {} - for p in hal.get_info_pins(): - if p['NAME'].startswith('halui.'): - sfx = p['NAME'][len('halui.'):] - self.pins[sfx] = (p['TYPE'], p['DIRECTION']) - if p['DIRECTION'] == hal.HAL_IN: - self.defaults[sfx] = p['VALUE'] - if not self.pins: - raise RuntimeError('no halui pins found -- is halui running?') - - self.comp = hal.component(COMP) - for sfx, (typ, d) in sorted(self.pins.items()): - mirror = hal.HAL_OUT if d == hal.HAL_IN else hal.HAL_IN - self.comp.newpin(sfx, typ, mirror) - # Wiring our output to halui's input makes the signal carry our - # value, so start from halui's own default (scales, deadbands, - # count-enable...) rather than silently replacing it with 0. - if d == hal.HAL_IN: - self.comp[sfx] = self.defaults[sfx] - self.comp.ready() - - # Pins the config already wired elsewhere cannot be driven from here. - self.external = set() - for sfx, (typ, d) in sorted(self.pins.items()): - # hal.connect() does not raise when the link fails: it returns - # True (hal_link() != 0). A failed link here means the config - # already wired this halui pin. - sig = 'ht.' + sfx - hal.new_sig(sig, typ) - if hal.connect('halui.' + sfx, sig): - self.external.add(sfx) - continue - if hal.connect(COMP + '.' + sfx, sig): - raise RuntimeError('could not wire %s.%s' % (COMP, sfx)) - - self.stat = linuxcnc.stat() - self.cmd = linuxcnc.command() - self.errors = linuxcnc.error_channel() - self.poll() - # Until task publishes its first status, task_state reads 0, which is - # not STATE_ESTOP and not STATE_ON -- branching on it would skip the - # estop clear below and leave every later state(ON) refused. The - # harness can be up 4ms after launch, so this is reached routinely. - if not self.wait_for(lambda: self.stat.task_state != 0): - raise RuntimeError('setup: task never published a state') - self.log('harness up: %d halui pins, %d wired externally, task_state=%d' - % (len(self.pins), len(self.external), self.stat.task_state)) - - # -- reporting --------------------------------------------------------- - - def log(self, msg): - print('%7.3f: %s' % (time.time() - self.t0, msg), flush=True) - - def section(self, name): - self.log('') - self.log('==== %s ====' % name) - - def check(self, name, ok, detail=''): - self.checks += 1 - self.log('%s %s%s' % ('PASS' if ok else 'FAIL', name, - (' -- ' + detail) if detail else '')) - if not ok: - self.failures.append(name) - return ok - - def known_bug(self, name, ok, explanation): - """Assert today's buggy behaviour, and say why it is a bug.""" - self.known_bugs.append(name) - return self.check('KNOWN-BUG ' + name, ok, explanation) - - def finish(self): - here = os.path.dirname(os.path.abspath(sys.argv[0])) - with open(os.path.join(here, 'touched-pins.txt'), 'w') as f: - for p in sorted(self.touched): - f.write(p + '\n') - self.log('') - self.log('%d checks, %d failed, %d known bugs, %d/%d halui pins exercised' - % (self.checks, len(self.failures), len(self.known_bugs), - len(self.touched & set(self.pins)), len(self.pins))) - for f in self.failures: - self.log(' FAILED: ' + f) - sys.exit(1 if self.failures else 0) - - # -- halui pins -------------------------------------------------------- - - def has(self, sfx): - return sfx in self.pins - - def _pin(self, sfx, want_input): - if sfx not in self.pins: - raise KeyError('halui has no pin %r' % sfx) - is_input = self.pins[sfx][1] == hal.HAL_IN - if is_input != want_input: - raise KeyError('halui.%s is an %s pin' % (sfx, 'input' if is_input else 'output')) - self.touched.add(sfx) - - def set(self, sfx, value): - self._pin(sfx, want_input=True) - if sfx in self.external: - raise KeyError('halui.%s is wired by the config; cannot drive it' % sfx) - self.comp[sfx] = value - - def get(self, sfx): - self._pin(sfx, want_input=False) - return self.comp[sfx] - - def default(self, sfx): - """halui's value for an input pin before the harness wired it.""" - self._pin(sfx, want_input=True) - return self.defaults[sfx] - - def pulse(self, sfx, hold=HOLD): - """Rising edge, held long enough for halui to see it, then released.""" - self.set(sfx, 1) - time.sleep(hold) - self.set(sfx, 0) - time.sleep(hold) - - def settle(self, t=HOLD): - time.sleep(t) - - # -- waiting ----------------------------------------------------------- - - def poll(self): - self.stat.poll() - return self.stat - - def wait_for(self, fn, timeout=TIMEOUT): - end = time.time() + timeout - while True: - self.poll() - try: - if fn(): - return True - except Exception: - pass - if time.time() > end: - return False - time.sleep(HALUI_PERIOD / 2) - - def expect(self, name, fn, timeout=TIMEOUT, detail=None): - ok = self.wait_for(fn, timeout) - return self.check(name, ok, detail() if callable(detail) else (detail or '')) - - def stays(self, fn, duration=0.5): - """True if fn holds for the whole duration (records nothing).""" - end = time.time() + duration - while time.time() < end: - self.poll() - if not fn(): - return False - time.sleep(HALUI_PERIOD / 2) - return True - - def expect_steady(self, name, fn, duration=0.5, detail=None): - """fn must stay true for the whole duration.""" - ok = self.stays(fn, duration) - return self.check(name, ok, detail() if callable(detail) else (detail or '')) - - def expect_pin(self, name, sfx, want, timeout=TIMEOUT, tol=1e-6): - is_float = self.pins[sfx][0] == hal.HAL_FLOAT - - def match(): - v = self.get(sfx) - if is_float: - return abs(v - want) <= tol - return v == want - return self.expect(name, match, timeout, - detail=lambda: 'halui.%s = %r, want %r' % (sfx, self.get(sfx), want)) - - def drain_errors(self): - out = [] - while True: - e = self.errors.poll() - if not e: - return out - out.append(e[1]) - - def reset_between_sections(self): - for sfx in sorted(self.touched): - if self.pins[sfx][1] == hal.HAL_IN and sfx not in self.external: - self.comp[sfx] = self.defaults[sfx] - time.sleep(0.3) - self.nml_abort() - - # -- task setup, via NML (not under test) ------------------------------ - - def nml_abort(self): - self.cmd.abort() - self.cmd.wait_complete() - self.wait_for(lambda: self.stat.interp_state == linuxcnc.INTERP_IDLE) - - def nml_state(self, state): - # task has no distinct OFF state: a request for OFF reads back as - # ESTOP_RESET - want = linuxcnc.STATE_ESTOP_RESET if state == linuxcnc.STATE_OFF else state - for attempt in range(1, STATE_RETRY_BUDGET + 1): - self.cmd.state(state) - self.cmd.wait_complete() - if self.wait_for(lambda: self.stat.task_state == want, - timeout=STATE_ATTEMPT_TIMEOUT): - return True - self.log('task_state %d not reached on attempt %d, retrying' - % (want, attempt)) - return False - - def machine_on(self): - if self.poll().task_state == linuxcnc.STATE_ON: - return - # Unconditional: a machine that is not ON may be in estop whatever the - # last poll said, and STATE_ON is refused until estop is cleared. - if not self.nml_state(linuxcnc.STATE_ESTOP_RESET): - raise RuntimeError('setup: could not clear estop') - if not self.nml_state(linuxcnc.STATE_ON): - raise RuntimeError('setup: could not turn the machine on') - - def machine_estop(self): - self.nml_state(linuxcnc.STATE_ESTOP) - - def nml_mode(self, mode): - self.cmd.mode(mode) - self.cmd.wait_complete() - if not self.wait_for(lambda: self.stat.task_mode == mode): - raise RuntimeError('setup: could not switch to mode %d' % mode) - - def nml_teleop(self, enable): - self.cmd.teleop_enable(enable) - self.cmd.wait_complete() - want = linuxcnc.TRAJ_MODE_TELEOP if enable else linuxcnc.TRAJ_MODE_FREE - if not self.wait_for(lambda: self.stat.motion_mode == want): - raise RuntimeError('setup: could not set teleop=%d' % enable) - - def nml_home_all(self): - # Note: once every joint is homed, task switches an identity-kins - # machine to teleop by itself. - self.nml_mode(linuxcnc.MODE_MANUAL) - self.cmd.home(-1) - self.cmd.wait_complete() - if not self.wait_for(lambda: all(self.stat.homed[:self.stat.joints]), 20): - raise RuntimeError('setup: homing failed') - - def nml_unhome_all(self): - # motion refuses to unhome in teleop ("must be in joint mode or - # disabled to unhome"), which is where homing leaves the machine - self.nml_mode(linuxcnc.MODE_MANUAL) - if self.poll().motion_mode == linuxcnc.TRAJ_MODE_TELEOP: - self.nml_teleop(0) - self.cmd.unhome(-1) - self.cmd.wait_complete() - if not self.wait_for(lambda: not any(self.stat.homed[:self.stat.joints])): - raise RuntimeError('setup: unhoming failed') - - def wait_idle(self, timeout=20): - return self.wait_for(lambda: self.stat.interp_state == linuxcnc.INTERP_IDLE - and self.stat.exec_state == linuxcnc.EXEC_DONE, timeout) - - def nml_mdi(self, code, timeout=20): - self.nml_mode(linuxcnc.MODE_MDI) - self.cmd.mdi(code) - self.cmd.wait_complete() - if not self.wait_idle(timeout): - raise RuntimeError('setup: MDI %r did not finish' % code) - - def joint_pos(self, j): - return self.stat.joint_actual_position[j] - - def axis_pos(self, a): - return self.stat.actual_position['xyzabcuvw'.index(a)] - - def wait_joint_still(self, j, timeout=10): - last = [None] - def still(): - p = self.joint_pos(j) - done = last[0] is not None and abs(p - last[0]) < 1e-9 and self.stat.inpos - last[0] = p - return done - return self.wait_for(still, timeout) - - -def run(*sections): - """Run each section function against one harness; report at the end. - - Between sections every input a test drove goes back to halui's default and - task is aborted, so a section cannot leave a held jog, a paused program or - a half-finished MDI behind for the next one. - """ - h = Halui() - for fn in sections: - h.section(fn.__name__) - try: - fn(h) - except Exception: - h.log(traceback.format_exc()) - h.check('%s ran to completion' % fn.__name__, False, 'exception, see above') - h.reset_between_sections() - h.finish() - - -def close(a, b, tol=1e-6): - return abs(a - b) <= tol - - -INCH_PER_MM = 1 / 25.4 diff --git a/tests/halui/_lib/launch.sh b/tests/halui/_lib/launch.sh deleted file mode 100755 index abb5f798f01..00000000000 --- a/tests/halui/_lib/launch.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/bash -# Shared launcher for the halui pin tests. Each test directory's test.sh -# execs this from inside that directory. -# -# task rewrites the tool table (G10 L1, tool changes), so every run starts -# from a fresh copy of the shared one; tool.tbl is ignored by git. -cp ../_lib/tool.tbl tool.tbl -exec linuxcnc -r halui.ini diff --git a/tests/halui/_lib/tool.tbl b/tests/halui/_lib/tool.tbl deleted file mode 100644 index 25496163e24..00000000000 --- a/tests/halui/_lib/tool.tbl +++ /dev/null @@ -1,3 +0,0 @@ -T1 P1 Z0.5 D0.25 ;tool one -T2 P2 Z1.0 D0.5 ;tool two -T3 P3 Z0.0 D0.125 ;tool three diff --git a/tests/halui/axes/checkresult b/tests/halui/axes/checkresult deleted file mode 100755 index 73e90a43dfc..00000000000 --- a/tests/halui/axes/checkresult +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/sh -exit 0 # test failure is indicated by test.sh exit value diff --git a/tests/halui/axes/halui.ini b/tests/halui/axes/halui.ini deleted file mode 100644 index 4d21b0429ec..00000000000 --- a/tests/halui/axes/halui.ini +++ /dev/null @@ -1,100 +0,0 @@ -# Test machine shared by the halui pin tests: XYZ trivkins, one spindle, -# a tool table, a home sequence (so halui.home-all exists) and two MDI -# commands (so halui.halui-mdi-is-running and halui.mdi-command-NN exist). - -[EMC] -VERSION = 1.1 -DEBUG = 0 - -[DISPLAY] -DISPLAY = ./test-ui.py -MAX_FEED_OVERRIDE = 1.5 -MIN_SPINDLE_OVERRIDE = 0.5 -MAX_SPINDLE_OVERRIDE = 1.2 - -[TASK] -TASK = milltask -CYCLE_TIME = 0.001 - -[RS274NGC] -PARAMETER_FILE = sim.var - -[EMCMOT] -EMCMOT = motmod -COMM_TIMEOUT = 4.0 -BASE_PERIOD = 0 -SERVO_PERIOD = 1000000 - -[EMCIO] -TOOL_TABLE = tool.tbl - -[HAL] -HALFILE = LIB:core_sim.hal - -[HALUI] -MDI_COMMAND = G0 X1 Y0 Z0 -MDI_COMMAND = G0 X0 Y0 Z0 - -[TRAJ] -COORDINATES = X Y Z -LINEAR_UNITS = inch -ANGULAR_UNITS = degree -DEFAULT_LINEAR_VELOCITY = 1.2 -MAX_LINEAR_VELOCITY = 4 -SPINDLES = 1 -NO_FORCE_HOMING = 1 - -[KINS] -KINEMATICS = trivkins -JOINTS = 3 - -[AXIS_X] -MIN_LIMIT = -40.0 -MAX_LIMIT = 40.0 -MAX_VELOCITY = 4 -MAX_ACCELERATION = 1000.0 - -[AXIS_Y] -MIN_LIMIT = -40.0 -MAX_LIMIT = 40.0 -MAX_VELOCITY = 4 -MAX_ACCELERATION = 1000.0 - -[AXIS_Z] -MIN_LIMIT = -4.0 -MAX_LIMIT = 4.0 -MAX_VELOCITY = 4 -MAX_ACCELERATION = 1000.0 - -[JOINT_0] -TYPE = LINEAR -HOME = 0.0 -MAX_VELOCITY = 4 -MAX_ACCELERATION = 1000.0 -MIN_LIMIT = -40.0 -MAX_LIMIT = 40.0 -FERROR = 0.050 -MIN_FERROR = 0.010 -HOME_SEQUENCE = 0 - -[JOINT_1] -TYPE = LINEAR -HOME = 0.0 -MAX_VELOCITY = 4 -MAX_ACCELERATION = 1000.0 -MIN_LIMIT = -40.0 -MAX_LIMIT = 40.0 -FERROR = 0.050 -MIN_FERROR = 0.010 -HOME_SEQUENCE = 0 - -[JOINT_2] -TYPE = LINEAR -HOME = 0.0 -MAX_VELOCITY = 4 -MAX_ACCELERATION = 1000.0 -MIN_LIMIT = -4.0 -MAX_LIMIT = 4.0 -FERROR = 0.050 -MIN_FERROR = 0.010 -HOME_SEQUENCE = 0 diff --git a/tests/halui/axes/test-ui.py b/tests/halui/axes/test-ui.py deleted file mode 100755 index 034580b0ef4..00000000000 --- a/tests/halui/axes/test-ui.py +++ /dev/null @@ -1,332 +0,0 @@ -#!/usr/bin/env python3 -"""halui: axis selection, teleop jogging and axis positions. - -Pins: axis.L.select, axis.L.is-selected, axis.selected, - axis.jog-speed, axis.jog-deadband, - axis.L.plus, axis.L.minus, axis.L.analog, - axis.L.increment, axis.L.increment-plus, axis.L.increment-minus, - axis.selected.plus, axis.selected.minus, axis.selected.increment, - axis.selected.increment-plus, axis.selected.increment-minus, - axis.L.pos-commanded, axis.L.pos-feedback, axis.L.pos-relative - -The machine is XYZ trivkins, so axis x/y/z is joint 0/1/2 one to one and -axis motion is measured through the joint velocities. Axis jog speed is in -units per minute; halui divides it by 60. -""" - -import math -import os -import sys - -sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', '_lib')) -from halui_test import run, close # noqa: E402 - -import linuxcnc as L # noqa: E402 - -LETTERS = 'xyzabcuvw' -CONFIGURED = 'xyz' - - -def idx(a): - return LETTERS.index(a) - - -def av(h, a): - return h.stat.joint[idx(a)]['velocity'] - - -def pos(h, a): - return h.stat.actual_position[idx(a)] - - -def expect_velocity(h, a, v, why): - return h.expect('axis %s moves at %+.2f %s' % (a, v, why), - lambda: close(av(h, a), v, 1e-3), - detail=lambda: 'velocity %+.4f' % av(h, a)) - - -def expect_stopped(h, a, why): - h.expect('axis %s stops %s' % (a, why), lambda: close(av(h, a), 0.0, 1e-9) and h.stat.inpos, - detail=lambda: 'velocity %+.4f' % av(h, a)) - - -def expect_not_moving(h, a, why): - h.expect_steady('axis %s does not move %s' % (a, why), - lambda: close(av(h, a), 0.0, 1e-9), - detail=lambda: 'velocity %+.4f' % av(h, a)) - - -def expect_at(h, a, p, why): - return h.expect('axis %s ends at %+.3f %s' % (a, p, why), - lambda: close(pos(h, a), p, 1e-4) and h.stat.inpos, - timeout=10, detail=lambda: 'position %+.4f' % pos(h, a)) - - -def teleop(h): - h.machine_on() - h.nml_mode(L.MODE_MANUAL) - if not all(h.poll().homed[:3]): - h.nml_home_all() - if h.stat.motion_mode != L.TRAJ_MODE_TELEOP: - h.nml_teleop(1) - - -def to_zero(h): - h.machine_on() - if not all(h.poll().homed[:3]): - h.nml_home_all() - h.nml_mdi('G20 G90 G53 G0 X0 Y0 Z0') - teleop(h) - - -def expect_selected(h, a, why): - h.expect_pin('axis.selected is %d (%s) %s' % (idx(a), a, why), 'axis.selected', idx(a)) - for b in CONFIGURED: - h.expect_pin('axis.%s.is-selected is %s %s' % (b, a == b, why), - 'axis.%s.is-selected' % b, a == b) - - -def pins_and_defaults(h): - # input pins exist for all nine axes; status pins only for configured ones - for a in LETTERS: - for p in ('select', 'plus', 'minus', 'analog', 'increment', - 'increment-plus', 'increment-minus'): - if not h.has('axis.%s.%s' % (a, p)): - h.check('axis.%s.%s exists' % (a, p), False) - for p in ('is-selected', 'pos-commanded', 'pos-feedback', 'pos-relative'): - if h.has('axis.%s.%s' % (a, p)) != (a in CONFIGURED): - h.check('axis.%s.%s exists only if %s is configured' % (a, p, a), False) - h.check('axis input pins exist for all nine axes', True) - h.check('axis.jog-speed defaults to 0', close(h.default('axis.jog-speed'), 0.0)) - h.check('axis.jog-deadband defaults to 0.2', close(h.default('axis.jog-deadband'), 0.2)) - expect_selected(h, 'x', 'at startup') - - -def select(h): - h.pulse('axis.z.select') - expect_selected(h, 'z', 'after axis.z.select') - h.pulse('axis.y.select') - expect_selected(h, 'y', 'after axis.y.select') - h.pulse('axis.a.select') - expect_selected(h, 'y', 'after axis.a.select (A is not configured, ignored)') - h.set('axis.x.select', 1) - expect_selected(h, 'x', 'while axis.x.select is held') - h.pulse('axis.z.select') - expect_selected(h, 'z', 'after axis.z.select while axis.x.select is still held') - h.set('axis.x.select', 0) - h.settle() - expect_selected(h, 'z', 'after releasing axis.x.select') - - -def continuous_jog(h): - to_zero(h) - h.set('axis.jog-speed', 60) - for a in CONFIGURED: - h.set('axis.%s.plus' % a, 1) - expect_velocity(h, a, 1.0, 'while axis.%s.plus is held at jog-speed 60' % a) - h.set('axis.%s.plus' % a, 0) - expect_stopped(h, a, 'when axis.%s.plus is released' % a) - h.set('axis.%s.minus' % a, 1) - expect_velocity(h, a, -1.0, 'while axis.%s.minus is held' % a) - h.set('axis.%s.minus' % a, 0) - expect_stopped(h, a, 'when axis.%s.minus is released' % a) - - to_zero(h) - h.set('axis.jog-speed', 60) - h.set('axis.x.plus', 1) - expect_velocity(h, 'x', 1.0, 'at jog-speed 60') - h.set('axis.jog-speed', 120) - expect_velocity(h, 'x', 2.0, 'after jog-speed changes to 120 mid-jog') - h.set('axis.x.plus', 0) - expect_stopped(h, 'x', 'on release') - h.set('axis.jog-speed', 60) - - # pins for an axis the machine does not have do nothing - h.set('axis.b.plus', 1) - for a in CONFIGURED: - expect_not_moving(h, a, 'while axis.b.plus is held') - h.set('axis.b.plus', 0) - - -def jog_is_gated(h): - to_zero(h) - h.set('axis.jog-speed', 60) - h.nml_teleop(0) - h.set('axis.x.plus', 1) - expect_not_moving(h, 'x', 'in joint (free) mode') - h.set('axis.x.plus', 0) - - h.nml_state(L.STATE_OFF) - h.set('axis.y.plus', 1) - expect_not_moving(h, 'y', 'when the machine is off') - h.set('axis.y.plus', 0) - - -def analog_jog(h): - to_zero(h) - h.set('axis.jog-speed', 60) - h.set('axis.x.analog', 0.5) - expect_velocity(h, 'x', 0.5, 'at analog 0.5') - h.set('axis.x.analog', -0.8) - expect_velocity(h, 'x', -0.8, 'at analog -0.8') - h.set('axis.x.analog', 0.15) - expect_stopped(h, 'x', 'at analog 0.15, inside the 0.2 deadband') - h.set('axis.x.analog', 0.0) - h.set('axis.jog-deadband', 0.6) - h.set('axis.y.analog', 0.5) - expect_not_moving(h, 'y', 'at analog 0.5 with a 0.6 deadband') - h.set('axis.y.analog', 0.9) - expect_velocity(h, 'y', 0.9, 'at analog 0.9 with a 0.6 deadband') - h.set('axis.jog-speed', 30) - expect_velocity(h, 'y', 0.45, 'at analog 0.9 after jog-speed changes to 30') - h.set('axis.y.analog', 0.0) - expect_stopped(h, 'y', 'at analog 0') - h.set('axis.jog-deadband', 0.2) - h.set('axis.jog-speed', 60) - h.set('axis.z.analog', -0.4) - expect_velocity(h, 'z', -0.4, 'at analog -0.4') - h.set('axis.z.analog', 0.0) - expect_stopped(h, 'z', 'at analog 0') - - -def incremental_jog(h): - to_zero(h) - h.set('axis.jog-speed', 60) - for a in CONFIGURED: - h.set('axis.%s.increment' % a, 0.25) - h.pulse('axis.%s.increment-plus' % a) - expect_at(h, a, 0.25, 'after increment-plus') - h.pulse('axis.%s.increment-minus' % a) - expect_at(h, a, 0.0, 'after increment-minus') - - h.pulse('axis.y.select') - h.set('axis.selected.increment', 0.5) - h.pulse('axis.selected.increment-plus') - expect_at(h, 'y', 0.5, 'after axis.selected.increment-plus with y selected') - h.pulse('axis.selected.increment-minus') - expect_at(h, 'y', 0.0, 'after axis.selected.increment-minus') - h.check('the selected increment moved only y', - close(pos(h, 'x'), 0.0, 1e-4) and close(pos(h, 'z'), 0.0, 1e-4), - 'x=%+.4f z=%+.4f' % (pos(h, 'x'), pos(h, 'z'))) - - -def selected_jog(h): - to_zero(h) - h.set('axis.jog-speed', 60) - h.pulse('axis.x.select') - h.set('axis.selected.plus', 1) - expect_velocity(h, 'x', 1.0, 'while axis.selected.plus is held with x selected') - h.set('axis.selected.plus', 0) - expect_stopped(h, 'x', 'on release') - h.set('axis.selected.minus', 1) - expect_velocity(h, 'x', -1.0, 'while axis.selected.minus is held') - h.set('axis.selected.minus', 0) - expect_stopped(h, 'x', 'on release') - - # Changing the selection mid-jog should stop the old axis and start the - # new one, as it does for joints. For axes the restart looks at - # ajog_plus[num_axes] / ajog_minus[num_axes] -- the pins of the axis whose - # index equals the number of configured axes (A on this XYZ machine) -- - # instead of the selected slot ajog_*[EMCMOT_MAX_AXIS]. - h.set('axis.selected.plus', 1) - expect_velocity(h, 'x', 1.0, 'before the selection changes') - h.pulse('axis.y.select') - expect_stopped(h, 'x', 'when the selection moves to y mid-jog') - h.known_bug('a selected jog does not carry over to the newly selected axis', - h.stays(lambda: close(av(h, 'y'), 0.0, 1e-9), 0.8), - 'halui.cc check_hal_changes(): axis reselect reads ajog_plus[num_axes] ' - 'instead of ajog_plus[EMCMOT_MAX_AXIS]; y should be jogging at +1') - h.set('axis.selected.plus', 0) - h.nml_abort() - to_zero(h) - - # the same index error from the other side: A's pin (inert on this - # machine) starts a jog on whichever axis gets selected - h.pulse('axis.x.select') - h.set('axis.a.plus', 1) - expect_not_moving(h, 'x', 'while only axis.a.plus is held (A is not configured)') - h.pulse('axis.z.select') - h.known_bug('holding axis.a.plus makes a newly selected axis jog', - h.wait_for(lambda: close(av(h, 'z'), 1.0, 1e-3), 1.0), - 'same ajog_plus[num_axes] index: num_axes is 3 here, which is axis A; ' - 'z should stay still') - h.set('axis.a.plus', 0) - h.nml_abort() - - -def expected_relative(s, machine=None): - """halui's own formula (modify_hal_pins) from task's offsets. - - `machine` is the machine position to model from. Pass the position the - caller has just asserted rather than letting it default: a move is only - confirmed to expect_at()'s 1e-4, so actual_position can still be settling - by that much, while expect_positions() compares the result at 1e-6. Under - load that gap shows up as a ~5e-5 miss on pos-relative alone -- the - commanded/feedback checks compare against exact literals and pass. - """ - ax, ay, az = machine if machine is not None else s.actual_position[:3] - g5x, g92, tlo, rot = s.g5x_offset, s.g92_offset, s.tool_offset, s.rotation_xy - x = ax - g5x[0] - tlo[0] - y = ay - g5x[1] - tlo[1] - c, sn = math.cos(-rot * math.pi / 180), math.sin(-rot * math.pi / 180) - return (x * c - y * sn - g92[0], - y * c + x * sn - g92[1], - az - g5x[2] - g92[2] - tlo[2]) - - -def expect_positions(h, machine, relative, why): - for i, a in enumerate(CONFIGURED): - h.expect_pin('axis.%s.pos-commanded is %+.3f %s' % (a, machine[i], why), - 'axis.%s.pos-commanded' % a, machine[i], tol=1e-6) - h.expect_pin('axis.%s.pos-feedback is %+.3f %s' % (a, machine[i], why), - 'axis.%s.pos-feedback' % a, machine[i], tol=1e-6) - h.expect_pin('axis.%s.pos-relative is %+.3f %s' % (a, relative[i], why), - 'axis.%s.pos-relative' % a, relative[i], tol=1e-6) - - -def positions(h): - h.machine_on() - h.nml_home_all() - for code in ('G20 G90 G54', 'G92.1', 'G49', 'G10 L2 P1 X0 Y0 Z0 R0', 'M61 Q0', - 'G53 G0 X1 Y2 Z0.5'): - h.nml_mdi(code) - expect_positions(h, (1, 2, 0.5), (1, 2, 0.5), 'with no offsets') - - for code in ('G10 L2 P1 X1 Y2 Z0.5 R30', 'M61 Q1', 'G43', 'G53 G0 X3 Y4 Z1', - 'G92 X0.5 Y-0.5'): - h.nml_mdi(code) - s = h.poll() - h.check('setup: task has a G54 offset, G92 offset, rotation and tool offset', - close(s.g5x_offset[0], 1) and close(s.rotation_xy, 30) and close(s.tool_offset[2], 0.5) - and not close(s.g92_offset[0], 0), - 'g5x=%s g92=%s rot=%s tlo=%s' % (s.g5x_offset[:3], s.g92_offset[:3], - s.rotation_xy, s.tool_offset[:3])) - rel = expected_relative(s) - expect_positions(h, (3, 4, 1), rel, 'with G54 + G92 + R30 + G43') - # G92 X0.5 Y-0.5 defines the current point as X0.5 Y-0.5 in program - # coordinates, and Z is machine 1 - G54 0.5 - tool 0.5 = 0 - for a, want in (('x', 0.5), ('y', -0.5), ('z', 0.0)): - h.expect_pin('axis.%s.pos-relative agrees with program coordinates (%+.2f)' % (a, want), - 'axis.%s.pos-relative' % a, want, tol=1e-6) - - # the pins follow motion - teleop(h) - h.set('axis.jog-speed', 60) - h.set('axis.x.increment', 0.5) - h.pulse('axis.x.increment-plus') - expect_at(h, 'x', 3.5, 'after an increment in teleop') - rel = expected_relative(h.poll(), (3.5, 4, 1)) - expect_positions(h, (3.5, 4, 1), rel, 'after moving X by 0.5') - - for code in ('G92.1', 'G49', 'G10 L2 P1 X0 Y0 Z0 R0', 'M61 Q0'): - h.nml_mdi(code) - - -run(pins_and_defaults, - select, - continuous_jog, - jog_is_gated, - analog_jog, - incremental_jog, - selected_jog, - positions) diff --git a/tests/halui/axes/test.sh b/tests/halui/axes/test.sh deleted file mode 100755 index fd122f82169..00000000000 --- a/tests/halui/axes/test.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/bash -exec ../_lib/launch.sh diff --git a/tests/halui/config-9axis/checkresult b/tests/halui/config-9axis/checkresult deleted file mode 100755 index 73e90a43dfc..00000000000 --- a/tests/halui/config-9axis/checkresult +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/sh -exit 0 # test failure is indicated by test.sh exit value diff --git a/tests/halui/config-9axis/halui.ini b/tests/halui/config-9axis/halui.ini deleted file mode 100644 index e7501e2a64d..00000000000 --- a/tests/halui/config-9axis/halui.ini +++ /dev/null @@ -1,194 +0,0 @@ -# Nine-axis machine for the halui pin tests: trivkins XYZABCUVW, one joint -# per axis, so every per-axis halui pin exists and does something. - -[EMC] -VERSION = 1.1 -DEBUG = 0 - -[DISPLAY] -DISPLAY = ./test-ui.py - -[TASK] -TASK = milltask -CYCLE_TIME = 0.001 - -[RS274NGC] -PARAMETER_FILE = sim.var - -[EMCMOT] -EMCMOT = motmod -COMM_TIMEOUT = 4.0 -BASE_PERIOD = 0 -SERVO_PERIOD = 1000000 - -[EMCIO] -TOOL_TABLE = tool.tbl - -[HAL] -HALFILE = nine.hal - -[TRAJ] -COORDINATES = X Y Z A B C U V W -LINEAR_UNITS = inch -ANGULAR_UNITS = degree -DEFAULT_LINEAR_VELOCITY = 1.2 -MAX_LINEAR_VELOCITY = 4 -MAX_ANGULAR_VELOCITY = 60 -NO_FORCE_HOMING = 1 - -[KINS] -KINEMATICS = trivkins coordinates=XYZABCUVW -JOINTS = 9 - -[AXIS_X] -MIN_LIMIT = -40.0 -MAX_LIMIT = 40.0 -MAX_VELOCITY = 4 -MAX_ACCELERATION = 1000.0 - -[AXIS_Y] -MIN_LIMIT = -40.0 -MAX_LIMIT = 40.0 -MAX_VELOCITY = 4 -MAX_ACCELERATION = 1000.0 - -[AXIS_Z] -MIN_LIMIT = -40.0 -MAX_LIMIT = 40.0 -MAX_VELOCITY = 4 -MAX_ACCELERATION = 1000.0 - -[AXIS_A] -MIN_LIMIT = -360.0 -MAX_LIMIT = 360.0 -MAX_VELOCITY = 60 -MAX_ACCELERATION = 1000.0 - -[AXIS_B] -MIN_LIMIT = -360.0 -MAX_LIMIT = 360.0 -MAX_VELOCITY = 60 -MAX_ACCELERATION = 1000.0 - -[AXIS_C] -MIN_LIMIT = -360.0 -MAX_LIMIT = 360.0 -MAX_VELOCITY = 60 -MAX_ACCELERATION = 1000.0 - -[AXIS_U] -MIN_LIMIT = -40.0 -MAX_LIMIT = 40.0 -MAX_VELOCITY = 4 -MAX_ACCELERATION = 1000.0 - -[AXIS_V] -MIN_LIMIT = -40.0 -MAX_LIMIT = 40.0 -MAX_VELOCITY = 4 -MAX_ACCELERATION = 1000.0 - -[AXIS_W] -MIN_LIMIT = -40.0 -MAX_LIMIT = 40.0 -MAX_VELOCITY = 4 -MAX_ACCELERATION = 1000.0 - -[JOINT_0] -TYPE = LINEAR -HOME = 0.0 -MAX_VELOCITY = 4 -MAX_ACCELERATION = 1000.0 -MIN_LIMIT = -40.0 -MAX_LIMIT = 40.0 -FERROR = 1.0 -MIN_FERROR = 0.5 -HOME_SEQUENCE = 0 - -[JOINT_1] -TYPE = LINEAR -HOME = 0.0 -MAX_VELOCITY = 4 -MAX_ACCELERATION = 1000.0 -MIN_LIMIT = -40.0 -MAX_LIMIT = 40.0 -FERROR = 1.0 -MIN_FERROR = 0.5 -HOME_SEQUENCE = 0 - -[JOINT_2] -TYPE = LINEAR -HOME = 0.0 -MAX_VELOCITY = 4 -MAX_ACCELERATION = 1000.0 -MIN_LIMIT = -40.0 -MAX_LIMIT = 40.0 -FERROR = 1.0 -MIN_FERROR = 0.5 -HOME_SEQUENCE = 0 - -[JOINT_3] -TYPE = ANGULAR -HOME = 0.0 -MAX_VELOCITY = 60 -MAX_ACCELERATION = 1000.0 -MIN_LIMIT = -360.0 -MAX_LIMIT = 360.0 -FERROR = 1.0 -MIN_FERROR = 0.5 -HOME_SEQUENCE = 0 - -[JOINT_4] -TYPE = ANGULAR -HOME = 0.0 -MAX_VELOCITY = 60 -MAX_ACCELERATION = 1000.0 -MIN_LIMIT = -360.0 -MAX_LIMIT = 360.0 -FERROR = 1.0 -MIN_FERROR = 0.5 -HOME_SEQUENCE = 0 - -[JOINT_5] -TYPE = ANGULAR -HOME = 0.0 -MAX_VELOCITY = 60 -MAX_ACCELERATION = 1000.0 -MIN_LIMIT = -360.0 -MAX_LIMIT = 360.0 -FERROR = 1.0 -MIN_FERROR = 0.5 -HOME_SEQUENCE = 0 - -[JOINT_6] -TYPE = LINEAR -HOME = 0.0 -MAX_VELOCITY = 4 -MAX_ACCELERATION = 1000.0 -MIN_LIMIT = -40.0 -MAX_LIMIT = 40.0 -FERROR = 1.0 -MIN_FERROR = 0.5 -HOME_SEQUENCE = 0 - -[JOINT_7] -TYPE = LINEAR -HOME = 0.0 -MAX_VELOCITY = 4 -MAX_ACCELERATION = 1000.0 -MIN_LIMIT = -40.0 -MAX_LIMIT = 40.0 -FERROR = 1.0 -MIN_FERROR = 0.5 -HOME_SEQUENCE = 0 - -[JOINT_8] -TYPE = LINEAR -HOME = 0.0 -MAX_VELOCITY = 4 -MAX_ACCELERATION = 1000.0 -MIN_LIMIT = -40.0 -MAX_LIMIT = 40.0 -FERROR = 1.0 -MIN_FERROR = 0.5 -HOME_SEQUENCE = 0 diff --git a/tests/halui/config-9axis/nine.hal b/tests/halui/config-9axis/nine.hal deleted file mode 100644 index e90685ec8ab..00000000000 --- a/tests/halui/config-9axis/nine.hal +++ /dev/null @@ -1,19 +0,0 @@ -# nine joints, looped back -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 j0pos joint.0.motor-pos-cmd => joint.0.motor-pos-fb -net j1pos joint.1.motor-pos-cmd => joint.1.motor-pos-fb -net j2pos joint.2.motor-pos-cmd => joint.2.motor-pos-fb -net j3pos joint.3.motor-pos-cmd => joint.3.motor-pos-fb -net j4pos joint.4.motor-pos-cmd => joint.4.motor-pos-fb -net j5pos joint.5.motor-pos-cmd => joint.5.motor-pos-fb -net j6pos joint.6.motor-pos-cmd => joint.6.motor-pos-fb -net j7pos joint.7.motor-pos-cmd => joint.7.motor-pos-fb -net j8pos joint.8.motor-pos-cmd => joint.8.motor-pos-fb - -net estop-loop iocontrol.0.user-enable-out iocontrol.0.emc-enable-in -net tool-prep-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/halui/config-9axis/test-ui.py b/tests/halui/config-9axis/test-ui.py deleted file mode 100755 index 25f33eb7c03..00000000000 --- a/tests/halui/config-9axis/test-ui.py +++ /dev/null @@ -1,130 +0,0 @@ -#!/usr/bin/env python3 -"""halui on a nine-axis machine (trivkins XYZABCUVW, joint N drives axis N). - -Every per-axis halui pin exists here, so this covers selection, jogging, -positions and tool length offsets for A, B, C, U, V and W too. -""" - -import os -import sys - -sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', '_lib')) -from halui_test import run, close # noqa: E402 - -import linuxcnc as L # noqa: E402 - -LETTERS = 'xyzabcuvw' - - -def jv(h, j): - return h.stat.joint[j]['velocity'] - - -def teleop(h): - h.machine_on() - h.nml_mode(L.MODE_MANUAL) - if not all(h.poll().homed[:9]): - h.nml_home_all() - if h.stat.motion_mode != L.TRAJ_MODE_TELEOP: - h.nml_teleop(1) - - -def pins(h): - missing = ['axis.%s.%s' % (a, p) for a in LETTERS - for p in ('is-selected', 'pos-commanded', 'pos-feedback', 'pos-relative', - 'select', 'plus', 'minus', 'analog', 'increment', - 'increment-plus', 'increment-minus') - if not h.has('axis.%s.%s' % (a, p))] - h.check('every axis has its full set of pins', not missing, 'missing: %s' % missing) - h.check('joint pins exist for all nine joints', - all(h.has('joint.%d.is-homed' % j) for j in range(9))) - - -def select_every_axis(h): - for i, a in enumerate(LETTERS): - h.pulse('axis.%s.select' % a) - h.expect_pin('axis.selected is %d after axis.%s.select' % (i, a), 'axis.selected', i) - wrong = [b for b in LETTERS if h.get('axis.%s.is-selected' % b) != (a == b)] - h.check('only axis.%s.is-selected is set' % a, not wrong, 'also set/unset: %s' % wrong) - - -def jog_every_axis(h): - teleop(h) - h.set('axis.jog-speed', 60) - for i, a in enumerate(LETTERS): - h.set('axis.%s.plus' % a, 1) - h.expect('axis.%s.plus jogs joint %d' % (a, i), lambda i=i: close(jv(h, i), 1.0, 1e-3), - detail=lambda i=i: 'joint %d velocity %+.4f' % (i, jv(h, i))) - others = [j for j in range(9) if j != i and not close(jv(h, j), 0.0, 1e-9)] - h.check('only joint %d moves' % i, not others, 'also moving: %s' % others) - h.set('axis.%s.plus' % a, 0) - h.expect('axis %s stops on release' % a, - lambda i=i: close(jv(h, i), 0.0, 1e-9) and h.stat.inpos) - - -def reselect_carries_over(h): - # On an XYZ machine this is a known bug (see tests/halui/axes): the - # restart reads ajog_plus[num_axes]. Here num_axes == EMCMOT_MAX_AXIS == 9, - # which happens to be the right slot, so the jog does carry over. - teleop(h) - h.set('axis.jog-speed', 60) - h.pulse('axis.x.select') - h.set('axis.selected.plus', 1) - h.expect('x jogs as the selected axis', lambda: close(jv(h, 0), 1.0, 1e-3)) - h.pulse('axis.y.select') - h.expect('x stops when the selection moves to y', lambda: close(jv(h, 0), 0.0, 1e-9)) - h.expect('y picks up the selected jog (correct only because num_axes is 9 here)', - lambda: close(jv(h, 1), 1.0, 1e-3)) - h.set('axis.selected.plus', 0) - h.expect('y stops on release', lambda: close(jv(h, 1), 0.0, 1e-9) and h.stat.inpos) - - -def expect_positions(h, machine, relative, why): - for i, a in enumerate(LETTERS): - h.expect_pin('axis.%s.pos-commanded is %g %s' % (a, machine[i], why), - 'axis.%s.pos-commanded' % a, machine[i], tol=1e-6) - h.expect_pin('axis.%s.pos-feedback is %g %s' % (a, machine[i], why), - 'axis.%s.pos-feedback' % a, machine[i], tol=1e-6) - h.expect_pin('axis.%s.pos-relative is %g %s' % (a, relative[i], why), - 'axis.%s.pos-relative' % a, relative[i], tol=1e-6) - - -def expect_tool_offsets(h, offsets, why): - for i, a in enumerate(LETTERS): - h.expect_pin('tool.length_offset.%s is %g %s' % (a, offsets[i], why), - 'tool.length_offset.' + a, offsets[i], tol=1e-6) - - -def positions_and_offsets(h): - h.machine_on() - h.nml_home_all() - for code in ('G20 G90 G54 G49', 'G92.1', 'G10 L2 P1 X0 Y0 Z0 A0 B0 C0 U0 V0 W0 R0'): - h.nml_mdi(code) - - machine = [i + 2 for i in range(9)] - h.nml_mdi('G53 G0 X2 Y3 Z4 A5 B6 C7 U8 V9 W10') - expect_positions(h, machine, machine, 'with no offsets') - expect_tool_offsets(h, [0] * 9, 'with no tool offset') - - h.nml_mdi('G10 L2 P1 X1 Y2 Z3 A4 B5 C6 U7 V8 W9') - work = [1 + i for i in range(9)] - expect_positions(h, machine, [m - w for m, w in zip(machine, work)], 'with a G54 offset on every axis') - - tlo = [round(0.1 * (i + 1), 1) for i in range(9)] - h.nml_mdi('G43.1 X0.1 Y0.2 Z0.3 A0.4 B0.5 C0.6 U0.7 V0.8 W0.9') - expect_tool_offsets(h, tlo, 'after G43.1 on every axis') - expect_positions(h, machine, [m - w - t for m, w, t in zip(machine, work, tlo)], - 'with G54 and a tool offset on every axis') - - h.nml_mdi('G92 A0 U0 W0') - s = h.poll() - for i, a in ((3, 'a'), (6, 'u'), (8, 'w')): - h.expect_pin('axis.%s.pos-relative is 0 after G92 %s0' % (a, a.upper()), - 'axis.%s.pos-relative' % a, 0.0, tol=1e-6) - h.check('setup: G92 left the other axes alone', close(s.g92_offset[4], 0.0)) - - for code in ('G92.1', 'G49', 'G10 L2 P1 X0 Y0 Z0 A0 B0 C0 U0 V0 W0'): - h.nml_mdi(code) - - -run(pins, select_every_axis, jog_every_axis, reselect_carries_over, positions_and_offsets) diff --git a/tests/halui/config-9axis/test.sh b/tests/halui/config-9axis/test.sh deleted file mode 100755 index fd122f82169..00000000000 --- a/tests/halui/config-9axis/test.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/bash -exec ../_lib/launch.sh diff --git a/tests/halui/config-minimal/checkresult b/tests/halui/config-minimal/checkresult deleted file mode 100755 index 73e90a43dfc..00000000000 --- a/tests/halui/config-minimal/checkresult +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/sh -exit 0 # test failure is indicated by test.sh exit value diff --git a/tests/halui/config-minimal/halui.ini b/tests/halui/config-minimal/halui.ini deleted file mode 100644 index f6e70986383..00000000000 --- a/tests/halui/config-minimal/halui.ini +++ /dev/null @@ -1,74 +0,0 @@ -# Minimal/odd machine for the halui pin tests: two joints driving Y and Z, -# two spindles, no home sequence and no MDI commands -- so halui.home-all, -# halui.halui-mdi-is-running and halui.mdi-command-NN must not exist. - -[EMC] -VERSION = 1.1 -DEBUG = 0 - -[DISPLAY] -DISPLAY = ./test-ui.py - -[TASK] -TASK = milltask -CYCLE_TIME = 0.001 - -[RS274NGC] -PARAMETER_FILE = sim.var - -[EMCMOT] -EMCMOT = motmod -COMM_TIMEOUT = 4.0 -BASE_PERIOD = 0 -SERVO_PERIOD = 1000000 - -[EMCIO] -TOOL_TABLE = tool.tbl - -[HAL] -HALFILE = minimal.hal - -[TRAJ] -COORDINATES = Y Z -LINEAR_UNITS = inch -ANGULAR_UNITS = degree -DEFAULT_LINEAR_VELOCITY = 1.2 -MAX_LINEAR_VELOCITY = 4 -SPINDLES = 2 -NO_FORCE_HOMING = 1 - -[KINS] -KINEMATICS = trivkins coordinates=YZ -JOINTS = 2 - -[AXIS_Y] -MIN_LIMIT = -40.0 -MAX_LIMIT = 40.0 -MAX_VELOCITY = 4 -MAX_ACCELERATION = 1000.0 - -[AXIS_Z] -MIN_LIMIT = -4.0 -MAX_LIMIT = 4.0 -MAX_VELOCITY = 4 -MAX_ACCELERATION = 1000.0 - -[JOINT_0] -TYPE = LINEAR -HOME = 0.0 -MAX_VELOCITY = 4 -MAX_ACCELERATION = 1000.0 -MIN_LIMIT = -40.0 -MAX_LIMIT = 40.0 -FERROR = 0.050 -MIN_FERROR = 0.010 - -[JOINT_1] -TYPE = LINEAR -HOME = 0.0 -MAX_VELOCITY = 4 -MAX_ACCELERATION = 1000.0 -MIN_LIMIT = -4.0 -MAX_LIMIT = 4.0 -FERROR = 0.050 -MIN_FERROR = 0.010 diff --git a/tests/halui/config-minimal/minimal.hal b/tests/halui/config-minimal/minimal.hal deleted file mode 100644 index c9cbd1effbf..00000000000 --- a/tests/halui/config-minimal/minimal.hal +++ /dev/null @@ -1,12 +0,0 @@ -# two joints, two spindles, everything looped back -loadrt [KINS]KINEMATICS -loadrt [EMCMOT]EMCMOT base_period_nsec=[EMCMOT]BASE_PERIOD servo_period_nsec=[EMCMOT]SERVO_PERIOD num_joints=[KINS]JOINTS num_spindles=[TRAJ]SPINDLES -addf motion-command-handler servo-thread -addf motion-controller servo-thread - -net j0pos joint.0.motor-pos-cmd => joint.0.motor-pos-fb -net j1pos joint.1.motor-pos-cmd => joint.1.motor-pos-fb - -net estop-loop iocontrol.0.user-enable-out iocontrol.0.emc-enable-in -net tool-prep-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/halui/config-minimal/test-ui.py b/tests/halui/config-minimal/test-ui.py deleted file mode 100755 index 69d8488810b..00000000000 --- a/tests/halui/config-minimal/test-ui.py +++ /dev/null @@ -1,172 +0,0 @@ -#!/usr/bin/env python3 -"""halui on a two-joint YZ machine with two spindles, no home sequence and -no MDI commands. - -Checks which pins exist for this configuration, that a second spindle is -driven independently, and how axis selection starts up when the first -configured axis is not X. Joint 0 drives Y and joint 1 drives Z. -""" - -import os -import sys - -sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', '_lib')) -from halui_test import run, close # noqa: E402 - -import linuxcnc as L # noqa: E402 - -LETTERS = 'xyzabcuvw' -CONFIGURED = 'yz' -JOINT_OF = {'y': 0, 'z': 1} - - -def jv(h, j): - return h.stat.joint[j]['velocity'] - - -def home_each(h): - # there is no home sequence, so home-all is not an option: one at a time - h.machine_on() - h.nml_mode(L.MODE_MANUAL) - for j in (0, 1): - if not h.poll().homed[j]: - h.cmd.home(j) - h.cmd.wait_complete() - if not h.wait_for(lambda j=j: h.stat.homed[j]): - raise RuntimeError('setup: could not home joint %d' % j) - - -def teleop(h): - home_each(h) - if h.poll().motion_mode != L.TRAJ_MODE_TELEOP: - h.nml_teleop(1) - - -def pins(h): - h.check('no home-all pin without [JOINT_n]HOME_SEQUENCE', not h.has('home-all')) - h.check('no halui-mdi-is-running pin without [HALUI]MDI_COMMAND', - not h.has('halui-mdi-is-running')) - h.check('no mdi-command pins without [HALUI]MDI_COMMAND', - not any(p.startswith('mdi-command-') for p in h.pins)) - h.check('joint pins exist for joints 0 and 1', - all(h.has('joint.%d.%s' % (j, p)) for j in (0, 1) for p in ('home', 'is-homed', 'plus'))) - h.check('no pins for joint 2', not any(p.startswith('joint.2.') for p in h.pins)) - h.check('spindle pins exist for spindles 0 and 1', - all(h.has('spindle.%d.%s' % (s, p)) for s in (0, 1) - for p in ('start', 'is-on', 'brake-on', 'override.value'))) - h.check('no pins for spindle 2', not any(p.startswith('spindle.2.') for p in h.pins)) - wrong = [a for a in LETTERS - for p in ('is-selected', 'pos-commanded', 'pos-feedback', 'pos-relative') - if h.has('axis.%s.%s' % (a, p)) != (a in CONFIGURED)] - h.check('axis status pins exist only for Y and Z', not wrong, 'wrong: %s' % wrong) - h.check('axis input pins exist for all nine axes', - all(h.has('axis.%s.plus' % a) for a in LETTERS)) - - -def startup_selection(h): - h.expect_pin('joint.0.is-selected is true at startup', 'joint.0.is-selected', True) - h.expect_pin('axis.y.is-selected marks the first configured axis', 'axis.y.is-selected', True) - h.expect_pin('axis.z.is-selected is false at startup', 'axis.z.is-selected', False) - h.known_bug('axis.selected is 0 (X, not on this machine) at startup', - h.get('axis.selected') == 0, - 'hal_init_pins() sets axis_selected to 0 while halui_hal_init() marks the ' - 'first configured axis (Y, index 1) as selected; should be 1') - - teleop(h) - h.set('axis.jog-speed', 60) - h.set('axis.selected.plus', 1) - h.known_bug('axis.selected.plus at startup does not jog the axis shown as selected', - h.stays(lambda: close(jv(h, JOINT_OF['y']), 0.0, 1e-9), 0.8), - 'the jog goes to axis index 0 (X), which halui then drops as not configured') - h.set('axis.selected.plus', 0) - h.settle() - - h.pulse('axis.y.select') - h.expect_pin('pressing axis.y.select makes axis.selected 1', 'axis.selected', 1) - h.set('axis.selected.plus', 1) - h.expect('after that, axis.selected.plus jogs Y', - lambda: close(jv(h, JOINT_OF['y']), 1.0, 1e-3), - detail=lambda: 'joint 0 velocity %+.4f' % jv(h, 0)) - h.set('axis.selected.plus', 0) - h.expect('Y stops on release', lambda: close(jv(h, 0), 0.0, 1e-9) and h.stat.inpos) - - -def second_spindle(h): - h.machine_on() - h.nml_mode(L.MODE_MANUAL) - - def sp(s): - return h.stat.spindle[s] - - h.pulse('spindle.1.start') - h.expect('spindle.1.start turns spindle 1 on', - lambda: sp(1)['enabled'] and sp(1)['speed'] == 1) - h.check('spindle 0 stays off', not sp(0)['enabled']) - h.expect_pin('spindle.1.is-on sets', 'spindle.1.is-on', True) - h.expect_pin('spindle.1.runs-forward sets', 'spindle.1.runs-forward', True) - h.expect_pin('spindle.0.is-on stays false', 'spindle.0.is-on', False) - - h.pulse('spindle.1.reverse') - h.expect('spindle.1.reverse reverses spindle 1', lambda: sp(1)['direction'] == -1) - h.expect_pin('spindle.1.runs-backward sets', 'spindle.1.runs-backward', True) - h.pulse('spindle.1.stop') - h.expect('spindle.1.stop stops spindle 1', lambda: not sp(1)['enabled']) - h.expect_pin('spindle.1.is-on clears', 'spindle.1.is-on', False) - - brake0 = sp(0)['brake'] - h.pulse('spindle.1.brake-on') - h.expect('spindle.1.brake-on engages brake 1', lambda: sp(1)['brake'] == 1) - h.expect_pin('spindle.1.brake-is-on sets', 'spindle.1.brake-is-on', True) - h.check('brake 0 is untouched', sp(0)['brake'] == brake0, - 'brake 0 was %d, now %d' % (brake0, sp(0)['brake'])) - h.pulse('spindle.1.brake-off') - h.expect_pin('spindle.1.brake-is-on clears', 'spindle.1.brake-is-on', False) - - # no [DISPLAY] spindle override limits here: halui clamps to 0 .. 1.0 - h.pulse('spindle.1.override.decrease') - h.expect('spindle.1.override.decrease lowers override 1', - lambda: close(sp(1)['override'], 0.9)) - h.check('override 0 is untouched', close(sp(0)['override'], 1.0)) - h.expect_pin('spindle.1.override.value follows', 'spindle.1.override.value', 0.9) - h.pulse('spindle.1.override.increase') - h.pulse('spindle.1.override.increase') - h.expect('spindle 1 override is clamped at the default maximum of 1.0', - lambda: close(sp(1)['override'], 1.0)) - h.set('spindle.1.override.counts', -3) - h.expect('spindle.1.override.counts moves override 1', lambda: close(sp(1)['override'], 0.7)) - h.pulse('spindle.1.override.reset') - h.expect('spindle.1.override.reset puts it back to 1.0', lambda: close(sp(1)['override'], 1.0)) - - -def motion(h): - home_each(h) - if h.poll().motion_mode != L.TRAJ_MODE_FREE: - h.nml_teleop(0) - h.set('joint.jog-speed', 60) - h.set('joint.1.plus', 1) - h.expect('joint.1.plus jogs joint 1', lambda: close(jv(h, 1), 1.0, 1e-3)) - h.set('joint.1.plus', 0) - h.expect('joint 1 stops on release', lambda: close(jv(h, 1), 0.0, 1e-9) and h.stat.inpos) - - teleop(h) - h.set('axis.jog-speed', 60) - h.set('axis.z.plus', 1) - h.expect('axis.z.plus moves joint 1 (Z)', lambda: close(jv(h, 1), 1.0, 1e-3)) - h.set('axis.z.plus', 0) - h.expect('Z stops on release', lambda: close(jv(h, 1), 0.0, 1e-9) and h.stat.inpos) - h.set('axis.y.minus', 1) - h.expect('axis.y.minus moves joint 0 (Y) backwards', lambda: close(jv(h, 0), -1.0, 1e-3)) - h.set('axis.y.minus', 0) - h.expect('Y stops on release', lambda: close(jv(h, 0), 0.0, 1e-9) and h.stat.inpos) - - h.set('axis.x.plus', 1) - h.expect_steady('axis.x.plus moves nothing on a machine without X', - lambda: close(jv(h, 0), 0.0, 1e-9) and close(jv(h, 1), 0.0, 1e-9)) - h.set('axis.x.plus', 0) - - h.nml_mdi('G20 G90 G53 G0 Y1.5 Z-0.5') - h.expect_pin('axis.y.pos-feedback shows Y', 'axis.y.pos-feedback', 1.5) - h.expect_pin('axis.z.pos-feedback shows Z', 'axis.z.pos-feedback', -0.5) - - -run(pins, startup_selection, second_spindle, motion) diff --git a/tests/halui/config-minimal/test.sh b/tests/halui/config-minimal/test.sh deleted file mode 100755 index fd122f82169..00000000000 --- a/tests/halui/config-minimal/test.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/bash -exec ../_lib/launch.sh diff --git a/tests/halui/joints/checkresult b/tests/halui/joints/checkresult deleted file mode 100755 index 73e90a43dfc..00000000000 --- a/tests/halui/joints/checkresult +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/sh -exit 0 # test failure is indicated by test.sh exit value diff --git a/tests/halui/joints/halui.ini b/tests/halui/joints/halui.ini deleted file mode 100644 index 4d21b0429ec..00000000000 --- a/tests/halui/joints/halui.ini +++ /dev/null @@ -1,100 +0,0 @@ -# Test machine shared by the halui pin tests: XYZ trivkins, one spindle, -# a tool table, a home sequence (so halui.home-all exists) and two MDI -# commands (so halui.halui-mdi-is-running and halui.mdi-command-NN exist). - -[EMC] -VERSION = 1.1 -DEBUG = 0 - -[DISPLAY] -DISPLAY = ./test-ui.py -MAX_FEED_OVERRIDE = 1.5 -MIN_SPINDLE_OVERRIDE = 0.5 -MAX_SPINDLE_OVERRIDE = 1.2 - -[TASK] -TASK = milltask -CYCLE_TIME = 0.001 - -[RS274NGC] -PARAMETER_FILE = sim.var - -[EMCMOT] -EMCMOT = motmod -COMM_TIMEOUT = 4.0 -BASE_PERIOD = 0 -SERVO_PERIOD = 1000000 - -[EMCIO] -TOOL_TABLE = tool.tbl - -[HAL] -HALFILE = LIB:core_sim.hal - -[HALUI] -MDI_COMMAND = G0 X1 Y0 Z0 -MDI_COMMAND = G0 X0 Y0 Z0 - -[TRAJ] -COORDINATES = X Y Z -LINEAR_UNITS = inch -ANGULAR_UNITS = degree -DEFAULT_LINEAR_VELOCITY = 1.2 -MAX_LINEAR_VELOCITY = 4 -SPINDLES = 1 -NO_FORCE_HOMING = 1 - -[KINS] -KINEMATICS = trivkins -JOINTS = 3 - -[AXIS_X] -MIN_LIMIT = -40.0 -MAX_LIMIT = 40.0 -MAX_VELOCITY = 4 -MAX_ACCELERATION = 1000.0 - -[AXIS_Y] -MIN_LIMIT = -40.0 -MAX_LIMIT = 40.0 -MAX_VELOCITY = 4 -MAX_ACCELERATION = 1000.0 - -[AXIS_Z] -MIN_LIMIT = -4.0 -MAX_LIMIT = 4.0 -MAX_VELOCITY = 4 -MAX_ACCELERATION = 1000.0 - -[JOINT_0] -TYPE = LINEAR -HOME = 0.0 -MAX_VELOCITY = 4 -MAX_ACCELERATION = 1000.0 -MIN_LIMIT = -40.0 -MAX_LIMIT = 40.0 -FERROR = 0.050 -MIN_FERROR = 0.010 -HOME_SEQUENCE = 0 - -[JOINT_1] -TYPE = LINEAR -HOME = 0.0 -MAX_VELOCITY = 4 -MAX_ACCELERATION = 1000.0 -MIN_LIMIT = -40.0 -MAX_LIMIT = 40.0 -FERROR = 0.050 -MIN_FERROR = 0.010 -HOME_SEQUENCE = 0 - -[JOINT_2] -TYPE = LINEAR -HOME = 0.0 -MAX_VELOCITY = 4 -MAX_ACCELERATION = 1000.0 -MIN_LIMIT = -4.0 -MAX_LIMIT = 4.0 -FERROR = 0.050 -MIN_FERROR = 0.010 -HOME_SEQUENCE = 0 diff --git a/tests/halui/joints/test-ui.py b/tests/halui/joints/test-ui.py deleted file mode 100755 index 77affb3603f..00000000000 --- a/tests/halui/joints/test-ui.py +++ /dev/null @@ -1,442 +0,0 @@ -#!/usr/bin/env python3 -"""halui: joint selection, homing, joint status and joint jogging. - -Pins: joint.N.select, joint.N.is-selected, joint.selected, - joint.N.home, joint.N.unhome, joint.selected.home, joint.selected.unhome, - home-all, joint.N.is-homed, joint.selected.is-homed, - joint.N.on-{soft,hard}-{min,max}-limit, joint.N.has-fault, - joint.N.override-limits and the joint.selected.* mirrors of those, - joint.jog-speed, joint.jog-deadband, - joint.N.plus, joint.N.minus, joint.N.analog, - joint.N.increment, joint.N.increment-plus, joint.N.increment-minus, - joint.selected.plus, joint.selected.minus, joint.selected.increment, - joint.selected.increment-plus, joint.selected.increment-minus - -Joint jog speed is in units per minute; halui divides it by 60. -""" - -import os -import sys -import time - -sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', '_lib')) -from halui_test import run, close # noqa: E402 - -import hal # noqa: E402 -import linuxcnc as L # noqa: E402 - -JOINTS = 3 - - -def jv(h, j): - return h.stat.joint[j]['velocity'] - - -def expect_velocity(h, j, v, why): - return h.expect('joint %d moves at %+.2f %s' % (j, v, why), - lambda: close(jv(h, j), v, 1e-3), - detail=lambda: 'velocity %+.4f' % jv(h, j)) - - -def expect_stopped(h, j, why): - # per joint: the global in-position flag stays false while another joint - # is still moving - ok = h.wait_for(lambda: close(jv(h, j), 0.0, 1e-9)) and \ - h.stays(lambda: close(jv(h, j), 0.0, 1e-9), 0.2) - h.check('joint %d stops %s' % (j, why), ok, 'velocity %+.4f' % jv(h, j)) - - -def expect_not_moving(h, j, why): - h.expect_steady('joint %d does not move %s' % (j, why), - lambda: close(jv(h, j), 0.0, 1e-9), - detail=lambda: 'velocity %+.4f' % jv(h, j)) - - -def manual_joint_mode(h, homed=False): - h.machine_on() - h.nml_mode(L.MODE_MANUAL) - if homed: - h.nml_home_all() - if h.poll().motion_mode != L.TRAJ_MODE_FREE: - h.nml_teleop(0) - - -def to_zero(h): - manual_joint_mode(h) - h.nml_mdi('G20 G90 G53 G0 X0 Y0 Z0') - h.nml_mode(L.MODE_MANUAL) - if h.poll().motion_mode != L.TRAJ_MODE_FREE: - h.nml_teleop(0) - - -def expect_selected(h, j, why): - h.expect_pin('joint.selected is %d %s' % (j, why), 'joint.selected', j) - for k in range(JOINTS): - h.expect_pin('joint.%d.is-selected is %s %s' % (k, k == j, why), - 'joint.%d.is-selected' % k, k == j) - - -def pins_and_defaults(h): - for j in range(JOINTS): - for p in ('select', 'is-selected', 'home', 'unhome', 'is-homed', 'plus', 'minus', - 'analog', 'increment', 'increment-plus', 'increment-minus', - 'on-soft-min-limit', 'on-soft-max-limit', 'on-hard-min-limit', - 'on-hard-max-limit', 'has-fault', 'override-limits'): - if not h.has('joint.%d.%s' % (j, p)): - h.check('joint.%d.%s exists' % (j, p), False) - h.check('there are no pins for a joint the machine does not have', - not any(s.startswith('joint.%d.' % JOINTS) for s in h.pins)) - h.check('home-all exists because [JOINT_0]HOME_SEQUENCE is set', h.has('home-all')) - h.check('joint.jog-speed defaults to 0', close(h.default('joint.jog-speed'), 0.0)) - h.check('joint.jog-deadband defaults to 0.2', close(h.default('joint.jog-deadband'), 0.2)) - expect_selected(h, 0, 'at startup') - - -def select(h): - h.pulse('joint.2.select') - expect_selected(h, 2, 'after joint.2.select') - h.pulse('joint.1.select') - expect_selected(h, 1, 'after joint.1.select') - - # selection follows the latest rising edge, even while another select is held - h.set('joint.0.select', 1) - expect_selected(h, 0, 'while joint.0.select is held') - h.pulse('joint.2.select') - expect_selected(h, 2, 'after joint.2.select while joint.0.select is still held') - h.set('joint.0.select', 0) - h.settle() - expect_selected(h, 2, 'after releasing joint.0.select (falling edges do nothing)') - - -def homing(h): - manual_joint_mode(h) - h.nml_unhome_all() - for j in range(JOINTS): - h.expect_pin('joint.%d.is-homed is false after unhoming' % j, 'joint.%d.is-homed' % j, False) - - h.pulse('joint.1.home') - h.expect('joint.1.home homes joint 1', lambda: h.stat.homed[1]) - h.expect_pin('joint.1.is-homed sets', 'joint.1.is-homed', True) - h.pulse('joint.1.unhome') - h.expect('joint.1.unhome unhomes joint 1', lambda: not h.stat.homed[1]) - h.expect_pin('joint.1.is-homed clears', 'joint.1.is-homed', False) - - h.pulse('joint.2.select') - h.expect_pin('joint.selected.is-homed is false for unhomed joint 2', - 'joint.selected.is-homed', False) - h.pulse('joint.selected.home') - h.expect('joint.selected.home homes the selected joint (2)', lambda: h.stat.homed[2]) - h.expect_pin('joint.selected.is-homed follows joint 2', 'joint.selected.is-homed', True) - h.pulse('joint.selected.unhome') - h.expect('joint.selected.unhome unhomes the selected joint (2)', lambda: not h.stat.homed[2]) - h.expect_pin('joint.selected.is-homed clears', 'joint.selected.is-homed', False) - - h.pulse('home-all') - h.expect('home-all homes every joint', lambda: all(h.stat.homed[:JOINTS]), timeout=20) - for j in range(JOINTS): - h.expect_pin('joint.%d.is-homed is true after home-all' % j, 'joint.%d.is-homed' % j, True) - h.expect_pin('joint.selected.is-homed is true after home-all', 'joint.selected.is-homed', True) - # task puts an identity-kins machine into teleop once everything is homed - h.expect_pin('mode.is-teleop reports the switch to teleop after homing', 'mode.is-teleop', True) - - # homing is refused while in ESTOP - h.nml_unhome_all() - h.machine_estop() - h.pulse('joint.0.home') - h.expect_steady('joint.0.home in ESTOP does not home', lambda: not h.stat.homed[0]) - h.pulse('home-all') - h.expect_steady('home-all in ESTOP does not home', lambda: not any(h.stat.homed[:JOINTS])) - - -def hard_limits_and_fault(h): - manual_joint_mode(h, homed=True) - h.set('joint.jog-speed', 60) - h.set('joint.0.increment', 0.1) - for kind, motion_pin, key in (('min', 'neg-lim-sw-in', 'min_hard_limit'), - ('max', 'pos-lim-sw-in', 'max_hard_limit')): - manual_joint_mode(h) - h.pulse('joint.0.select') - pin = 'joint.0.on-hard-%s-limit' % kind - sel = 'joint.selected.on-hard-%s-limit' % kind - h.expect_pin('%s is false with the switch open' % pin, pin, False) - hal.set_p('joint.0.' + motion_pin, '1') - h.expect('task sees joint 0 on its hard %s limit' % kind, - lambda k=key: h.stat.joint[0][k]) - h.expect_pin('%s sets' % pin, pin, True) - h.expect_pin('%s follows selected joint 0' % sel, sel, True) - for other in (1, 2): - h.expect_pin('joint.%d.on-hard-%s-limit stays false' % (other, kind), - 'joint.%d.on-hard-%s-limit' % (other, kind), False) - h.pulse('joint.1.select') - h.expect_pin('%s is false while joint 1 is selected' % sel, sel, False) - h.expect_pin('%s is still set for joint 0' % pin, pin, True) - h.pulse('joint.0.select') - h.expect_pin('%s follows joint 0 again once it is reselected' % sel, sel, True) - - # override-limits is a status pin in halui; the override comes over - # NML. task reports one flag for all joints (taskintf.cc: - # overrideLimits = !!overrideLimitMask), so every joint shows it. - h.cmd.override_limits() - h.cmd.wait_complete() - h.expect('task reports the limits overridden', lambda: h.stat.joint[0]['override_limits']) - for j in range(JOINTS): - h.expect_pin('joint.%d.override-limits is set (one flag for all joints)' % j, - 'joint.%d.override-limits' % j, True) - h.expect_pin('joint.selected.override-limits is set', 'joint.selected.override-limits', True) - - hal.set_p('joint.0.' + motion_pin, '0') - h.expect('the hard %s limit clears in task' % kind, lambda k=key: not h.stat.joint[0][k]) - h.expect_pin('%s clears' % pin, pin, False) - h.expect_pin('%s clears' % sel, sel, False) - - # motion drops the override once a jog made while overridden finishes - manual_joint_mode(h) - h.expect_pin('override-limits is still set before any jog', 'joint.0.override-limits', True) - h.pulse('joint.0.increment-plus' if kind == 'min' else 'joint.0.increment-minus') - h.expect('the jog off the switch completes', lambda: h.stat.inpos and close(jv(h, 0), 0.0, 1e-9)) - for j in range(JOINTS): - h.expect_pin('joint.%d.override-limits clears after that jog' % j, - 'joint.%d.override-limits' % j, False) - - manual_joint_mode(h) - h.pulse('joint.2.select') - h.expect_pin('joint.2.has-fault is false', 'joint.2.has-fault', False) - hal.set_p('joint.2.amp-fault-in', '1') - h.expect('task sees the joint 2 amp fault', lambda: h.stat.joint[2]['fault']) - h.expect_pin('joint.2.has-fault sets', 'joint.2.has-fault', True) - h.expect_pin('joint.selected.has-fault follows joint 2', 'joint.selected.has-fault', True) - h.expect_pin('joint.0.has-fault stays false', 'joint.0.has-fault', False) - hal.set_p('joint.2.amp-fault-in', '0') - manual_joint_mode(h) - h.expect('the fault clears in task', lambda: not h.stat.joint[2]['fault']) - h.expect_pin('joint.2.has-fault clears', 'joint.2.has-fault', False) - h.expect_pin('joint.selected.has-fault clears', 'joint.selected.has-fault', False) - - -def soft_limit_pins_never_set(h): - # task never reports per-joint soft limits: taskintf.cc hard-codes - # minSoftLimit/maxSoftLimit to 0 ("soft limits are now applied to the - # command, and should never happen"). motion does still detect a joint - # beyond its soft limit and says so on motion.on-soft-limit. - # - # [JOINT_2] limits are -4 .. 4 and the joint sits at 0. Move the limit - # past the joint through task's ini.N.* pins -- the case motion's own - # comment names as the way this happens. motion then wants the joint - # unhomed before it will move again, so this runs last. - to_zero(h) - manual_joint_mode(h, homed=True) - h.pulse('joint.2.select') - for kind, ini_pin, value in (('min', 'ini.2.min_limit', 1.0), - ('max', 'ini.2.max_limit', -1.0)): - pin = 'joint.2.on-soft-%s-limit' % kind - sel = 'joint.selected.on-soft-%s-limit' % kind - h.expect_pin('%s is false inside the limits' % pin, pin, False) - old = hal.get_value(ini_pin) - hal.set_p(ini_pin, str(value)) - h.expect('motion reports joint 2 beyond its soft %s limit' % kind, - lambda: hal.get_value('motion.on-soft-limit')) - h.known_bug('%s stays false while joint 2 is past that limit' % pin, - h.stays(lambda p=pin, s=sel: not h.get(p) and not h.get(s), 0.5), - 'task hard-codes minSoftLimit/maxSoftLimit to 0 (taskintf.cc), so ' - 'halui.joint.N.on-soft-*-limit and the selected mirrors can never be set') - hal.set_p(ini_pin, str(old)) - h.expect('motion clears on-soft-limit once the limit is restored', - lambda: not hal.get_value('motion.on-soft-limit')) - h.check('the ini limit is back to %g' % old, close(hal.get_value(ini_pin), old)) - h.nml_unhome_all() - - -def continuous_jog(h): - to_zero(h) - h.set('joint.jog-speed', 60) - for j in range(JOINTS): - h.set('joint.%d.plus' % j, 1) - expect_velocity(h, j, 1.0, 'while joint.%d.plus is held at jog-speed 60' % j) - h.set('joint.%d.plus' % j, 0) - expect_stopped(h, j, 'when joint.%d.plus is released' % j) - h.set('joint.%d.minus' % j, 1) - expect_velocity(h, j, -1.0, 'while joint.%d.minus is held' % j) - h.set('joint.%d.minus' % j, 0) - expect_stopped(h, j, 'when joint.%d.minus is released' % j) - - to_zero(h) - h.set('joint.0.plus', 1) - expect_velocity(h, 0, 1.0, 'at jog-speed 60') - h.set('joint.jog-speed', 120) - expect_velocity(h, 0, 2.0, 'after jog-speed changes to 120 mid-jog') - h.set('joint.jog-speed', 30) - expect_velocity(h, 0, 0.5, 'after jog-speed changes to 30 mid-jog') - h.set('joint.0.plus', 0) - expect_stopped(h, 0, 'on release') - - h.set('joint.jog-speed', 60) - h.set('joint.1.plus', 1) - h.set('joint.2.minus', 1) - expect_velocity(h, 1, 1.0, 'together with joint 2') - expect_velocity(h, 2, -1.0, 'together with joint 1') - h.set('joint.1.plus', 0) - expect_stopped(h, 1, 'on release while joint 2 keeps going') - expect_velocity(h, 2, -1.0, 'after joint 1 is released') - h.set('joint.2.minus', 0) - expect_stopped(h, 2, 'on release') - - h.set('joint.jog-speed', 0) - h.set('joint.0.plus', 1) - expect_not_moving(h, 0, 'at jog-speed 0') - h.set('joint.0.plus', 0) - h.set('joint.jog-speed', 60) - - -def jog_is_gated(h): - to_zero(h) - h.set('joint.jog-speed', 60) - - h.nml_state(L.STATE_OFF) - h.set('joint.0.plus', 1) - expect_not_moving(h, 0, 'when the machine is off') - h.set('joint.0.plus', 0) - - manual_joint_mode(h, homed=True) - h.nml_teleop(1) - h.set('joint.0.plus', 1) - expect_not_moving(h, 0, 'in teleop mode') - h.set('joint.0.plus', 0) - h.nml_teleop(0) - - # abort stops a jog; the held input does not restart it - h.set('joint.0.plus', 1) - expect_velocity(h, 0, 1.0, 'before abort') - h.pulse('abort') - expect_stopped(h, 0, 'after abort') - expect_not_moving(h, 0, 'while joint.0.plus is still held after abort') - h.set('joint.0.plus', 0) - - -def analog_jog(h): - to_zero(h) - h.set('joint.jog-speed', 60) - h.set('joint.0.analog', 0.5) - expect_velocity(h, 0, 0.5, 'at analog 0.5') - h.set('joint.0.analog', -0.8) - expect_velocity(h, 0, -0.8, 'at analog -0.8') - h.set('joint.0.analog', 0.1) - expect_stopped(h, 0, 'at analog 0.1, inside the 0.2 deadband') - h.set('joint.0.analog', 0.3) - expect_velocity(h, 0, 0.3, 'at analog 0.3') - h.set('joint.jog-speed', 120) - expect_velocity(h, 0, 0.6, 'at analog 0.3 after jog-speed changes to 120') - h.set('joint.jog-speed', 60) - h.set('joint.0.analog', 0.0) - expect_stopped(h, 0, 'at analog 0') - - h.set('joint.jog-deadband', 0.6) - h.set('joint.0.analog', 0.5) - expect_not_moving(h, 0, 'at analog 0.5 with a 0.6 deadband') - h.set('joint.0.analog', 0.7) - expect_velocity(h, 0, 0.7, 'at analog 0.7 with a 0.6 deadband') - h.set('joint.0.analog', -0.65) - expect_velocity(h, 0, -0.65, 'at analog -0.65 with a 0.6 deadband') - h.set('joint.0.analog', 0.0) - expect_stopped(h, 0, 'at analog 0') - h.set('joint.jog-deadband', 0.2) - - for j in (1, 2): - h.set('joint.%d.analog' % j, -0.4) - expect_velocity(h, j, -0.4, 'at analog -0.4') - h.set('joint.%d.analog' % j, 0.0) - expect_stopped(h, j, 'at analog 0') - - -def expect_at(h, j, pos, why): - return h.expect('joint %d ends at %+.3f %s' % (j, pos, why), - lambda: close(h.joint_pos(j), pos, 1e-4) and h.stat.inpos, - timeout=10, detail=lambda: 'position %+.4f' % h.joint_pos(j)) - - -def incremental_jog(h): - to_zero(h) - h.set('joint.jog-speed', 60) - for j in range(JOINTS): - h.set('joint.%d.increment' % j, 0.25) - h.pulse('joint.%d.increment-plus' % j) - expect_at(h, j, 0.25, 'after increment-plus') - h.pulse('joint.%d.increment-minus' % j) - expect_at(h, j, 0.0, 'after increment-minus') - - h.set('joint.0.increment-plus', 1) - expect_at(h, 0, 0.25, 'while increment-plus is held') - h.expect_steady('a held increment-plus moves only once', - lambda: close(h.joint_pos(0), 0.25, 1e-4), duration=0.6) - h.set('joint.0.increment-plus', 0) - h.settle() - h.expect_steady('releasing increment-plus moves nothing', - lambda: close(h.joint_pos(0), 0.25, 1e-4)) - - h.pulse('joint.1.select') - h.set('joint.selected.increment', 0.5) - h.pulse('joint.selected.increment-plus') - expect_at(h, 1, 0.5, 'after joint.selected.increment-plus with joint 1 selected') - h.pulse('joint.selected.increment-minus') - expect_at(h, 1, 0.0, 'after joint.selected.increment-minus') - h.check('the selected increment did not move joint 0', - close(h.joint_pos(0), 0.25, 1e-4), 'joint 0 at %+.4f' % h.joint_pos(0)) - - h.nml_state(L.STATE_OFF) - h.pulse('joint.2.increment-plus') - h.expect_steady('increment-plus does nothing when the machine is off', - lambda: close(h.joint_pos(2), 0.0, 1e-4)) - - -def selected_jog(h): - to_zero(h) - h.set('joint.jog-speed', 60) - h.pulse('joint.0.select') - - h.set('joint.selected.plus', 1) - expect_velocity(h, 0, 1.0, 'while joint.selected.plus is held') - h.pulse('joint.1.select') - expect_stopped(h, 0, 'when the selection moves to joint 1 mid-jog') - expect_velocity(h, 1, 1.0, 'after being selected mid-jog') - h.set('joint.selected.plus', 0) - expect_stopped(h, 1, 'when joint.selected.plus is released') - - h.set('joint.selected.minus', 1) - expect_velocity(h, 1, -1.0, 'while joint.selected.minus is held') - h.pulse('joint.2.select') - expect_stopped(h, 1, 'when the selection moves to joint 2') - expect_velocity(h, 2, -1.0, 'after being selected during a minus jog') - h.set('joint.selected.minus', 0) - expect_stopped(h, 2, 'on release') - - # a joint jogged on its own pin keeps going when the selection changes - to_zero(h) - h.pulse('joint.0.select') - h.set('joint.2.plus', 1) - h.set('joint.selected.plus', 1) - expect_velocity(h, 0, 1.0, 'as the selected joint') - expect_velocity(h, 2, 1.0, 'on its own pin') - h.pulse('joint.1.select') - expect_stopped(h, 0, 'after the selection moves to joint 1') - expect_velocity(h, 1, 1.0, 'as the newly selected joint') - expect_velocity(h, 2, 1.0, 'still, because its own pin is held') - h.set('joint.selected.plus', 0) - h.set('joint.2.plus', 0) - expect_stopped(h, 1, 'on release') - expect_stopped(h, 2, 'on release') - - # changing the selection when nothing is jogging moves nothing - h.pulse('joint.0.select') - for j in range(JOINTS): - expect_not_moving(h, j, 'after a selection change with no jog active') - - -run(pins_and_defaults, - select, - homing, - hard_limits_and_fault, - continuous_jog, - jog_is_gated, - analog_jog, - incremental_jog, - selected_jog, - soft_limit_pins_never_set) diff --git a/tests/halui/joints/test.sh b/tests/halui/joints/test.sh deleted file mode 100755 index fd122f82169..00000000000 --- a/tests/halui/joints/test.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/bash -exec ../_lib/launch.sh diff --git a/tests/halui/machine-state/checkresult b/tests/halui/machine-state/checkresult deleted file mode 100755 index 73e90a43dfc..00000000000 --- a/tests/halui/machine-state/checkresult +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/sh -exit 0 # test failure is indicated by test.sh exit value diff --git a/tests/halui/machine-state/halui.ini b/tests/halui/machine-state/halui.ini deleted file mode 100644 index 4d21b0429ec..00000000000 --- a/tests/halui/machine-state/halui.ini +++ /dev/null @@ -1,100 +0,0 @@ -# Test machine shared by the halui pin tests: XYZ trivkins, one spindle, -# a tool table, a home sequence (so halui.home-all exists) and two MDI -# commands (so halui.halui-mdi-is-running and halui.mdi-command-NN exist). - -[EMC] -VERSION = 1.1 -DEBUG = 0 - -[DISPLAY] -DISPLAY = ./test-ui.py -MAX_FEED_OVERRIDE = 1.5 -MIN_SPINDLE_OVERRIDE = 0.5 -MAX_SPINDLE_OVERRIDE = 1.2 - -[TASK] -TASK = milltask -CYCLE_TIME = 0.001 - -[RS274NGC] -PARAMETER_FILE = sim.var - -[EMCMOT] -EMCMOT = motmod -COMM_TIMEOUT = 4.0 -BASE_PERIOD = 0 -SERVO_PERIOD = 1000000 - -[EMCIO] -TOOL_TABLE = tool.tbl - -[HAL] -HALFILE = LIB:core_sim.hal - -[HALUI] -MDI_COMMAND = G0 X1 Y0 Z0 -MDI_COMMAND = G0 X0 Y0 Z0 - -[TRAJ] -COORDINATES = X Y Z -LINEAR_UNITS = inch -ANGULAR_UNITS = degree -DEFAULT_LINEAR_VELOCITY = 1.2 -MAX_LINEAR_VELOCITY = 4 -SPINDLES = 1 -NO_FORCE_HOMING = 1 - -[KINS] -KINEMATICS = trivkins -JOINTS = 3 - -[AXIS_X] -MIN_LIMIT = -40.0 -MAX_LIMIT = 40.0 -MAX_VELOCITY = 4 -MAX_ACCELERATION = 1000.0 - -[AXIS_Y] -MIN_LIMIT = -40.0 -MAX_LIMIT = 40.0 -MAX_VELOCITY = 4 -MAX_ACCELERATION = 1000.0 - -[AXIS_Z] -MIN_LIMIT = -4.0 -MAX_LIMIT = 4.0 -MAX_VELOCITY = 4 -MAX_ACCELERATION = 1000.0 - -[JOINT_0] -TYPE = LINEAR -HOME = 0.0 -MAX_VELOCITY = 4 -MAX_ACCELERATION = 1000.0 -MIN_LIMIT = -40.0 -MAX_LIMIT = 40.0 -FERROR = 0.050 -MIN_FERROR = 0.010 -HOME_SEQUENCE = 0 - -[JOINT_1] -TYPE = LINEAR -HOME = 0.0 -MAX_VELOCITY = 4 -MAX_ACCELERATION = 1000.0 -MIN_LIMIT = -40.0 -MAX_LIMIT = 40.0 -FERROR = 0.050 -MIN_FERROR = 0.010 -HOME_SEQUENCE = 0 - -[JOINT_2] -TYPE = LINEAR -HOME = 0.0 -MAX_VELOCITY = 4 -MAX_ACCELERATION = 1000.0 -MIN_LIMIT = -4.0 -MAX_LIMIT = 4.0 -FERROR = 0.050 -MIN_FERROR = 0.010 -HOME_SEQUENCE = 0 diff --git a/tests/halui/machine-state/test-ui.py b/tests/halui/machine-state/test-ui.py deleted file mode 100755 index e2d00e1300f..00000000000 --- a/tests/halui/machine-state/test-ui.py +++ /dev/null @@ -1,188 +0,0 @@ -#!/usr/bin/env python3 -"""halui: estop, machine power, task mode and motion mode. - -Pins: estop.activate, estop.reset, estop.is-activated, - machine.on, machine.off, machine.is-on, machine.units-per-mm, - mode.manual, mode.auto, mode.mdi, mode.teleop, mode.joint, - mode.is-manual, mode.is-auto, mode.is-mdi, mode.is-teleop, mode.is-joint -""" - -import os -import sys - -sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', '_lib')) -from halui_test import run, INCH_PER_MM # noqa: E402 - -import linuxcnc as L # noqa: E402 - -# task has no distinct OFF state: it reports ESTOP_RESET when the machine is -# neither estopped nor enabled (emctask.cc, emcTaskSetState) -POWERED_OFF = L.STATE_ESTOP_RESET - -MODE_PINS = {L.MODE_MANUAL: 'mode.is-manual', - L.MODE_AUTO: 'mode.is-auto', - L.MODE_MDI: 'mode.is-mdi'} - - -def startup_status(h): - h.expect('task starts in ESTOP', lambda: h.stat.task_state == L.STATE_ESTOP) - h.expect_pin('estop.is-activated reflects startup ESTOP', 'estop.is-activated', True) - h.expect_pin('machine.is-on is false at startup', 'machine.is-on', False) - # linear units are units per mm; this is an inch machine - h.expect_pin('machine.units-per-mm is published once task is up', - 'machine.units-per-mm', INCH_PER_MM, tol=1e-9) - - -def estop_and_power(h): - h.pulse('estop.reset') - h.expect('estop.reset -> task ESTOP_RESET', - lambda: h.stat.task_state == L.STATE_ESTOP_RESET) - h.expect_pin('estop.is-activated clears on reset', 'estop.is-activated', False) - h.expect_pin('machine.is-on stays false after reset', 'machine.is-on', False) - - h.pulse('machine.on') - h.expect('machine.on -> task ON', lambda: h.stat.task_state == L.STATE_ON) - h.expect_pin('machine.is-on sets', 'machine.is-on', True) - - h.pulse('machine.off') - h.expect('machine.off powers down (task reads back ESTOP_RESET)', - lambda: h.stat.task_state == POWERED_OFF) - h.expect_pin('machine.is-on clears on OFF', 'machine.is-on', False) - h.expect_pin('estop.is-activated stays clear on OFF', 'estop.is-activated', False) - - h.pulse('machine.on') - h.expect('machine.on from OFF -> task ON', lambda: h.stat.task_state == L.STATE_ON) - - h.pulse('estop.activate') - h.expect('estop.activate from ON -> task ESTOP', lambda: h.stat.task_state == L.STATE_ESTOP) - h.expect_pin('estop.is-activated sets', 'estop.is-activated', True) - h.expect_pin('machine.is-on clears on ESTOP', 'machine.is-on', False) - - -def power_on_refused_in_estop(h): - # task refuses ON straight from ESTOP; halui passes the request on and - # does not try to work around it - h.machine_estop() - h.pulse('machine.on') - h.expect_steady('machine.on while in ESTOP is refused by task', - lambda: h.stat.task_state == L.STATE_ESTOP) - h.expect_pin('machine.is-on stays false', 'machine.is-on', False) - - -def inputs_are_edge_triggered(h): - h.machine_estop() - h.nml_state(L.STATE_ESTOP_RESET) - h.set('machine.on', 1) - h.expect('rising edge on machine.on powers on', lambda: h.stat.task_state == L.STATE_ON) - h.nml_state(L.STATE_OFF) - h.expect_steady('a held machine.on does not power on again', - lambda: h.stat.task_state == POWERED_OFF, duration=0.6) - h.set('machine.on', 0) - h.expect_steady('the falling edge of machine.on does nothing', - lambda: h.stat.task_state == POWERED_OFF, duration=0.4) - - h.nml_state(L.STATE_ON) - h.set('estop.activate', 1) - h.expect('rising edge on estop.activate estops', lambda: h.stat.task_state == L.STATE_ESTOP) - h.nml_state(L.STATE_ESTOP_RESET) - h.expect_steady('a held estop.activate does not estop again', - lambda: h.stat.task_state == L.STATE_ESTOP_RESET, duration=0.6) - h.set('estop.activate', 0) - - -def status_follows_other_clients(h): - # output pins mirror task state no matter who changed it - h.machine_estop() - h.expect_pin('estop.is-activated follows an NML estop', 'estop.is-activated', True) - h.machine_on() - h.expect_pin('machine.is-on follows an NML power-on', 'machine.is-on', True) - h.expect_pin('estop.is-activated follows an NML reset', 'estop.is-activated', False) - - -def expect_task_mode_pins(h, want, why): - for mode, pin in MODE_PINS.items(): - h.expect_pin('%s is %s %s' % (pin, mode == want, why), pin, mode == want) - - -def task_modes(h): - h.machine_on() - h.nml_mode(L.MODE_MANUAL) - for request, mode, label in (('mode.mdi', L.MODE_MDI, 'MDI'), - ('mode.auto', L.MODE_AUTO, 'AUTO'), - ('mode.manual', L.MODE_MANUAL, 'MANUAL')): - h.pulse(request) - h.expect('%s -> task %s' % (request, label), lambda m=mode: h.stat.task_mode == m) - expect_task_mode_pins(h, mode, 'after ' + request) - - # asking for the mode task is already in sends nothing at all - for request, mode in (('mode.manual', L.MODE_MANUAL), - ('mode.auto', L.MODE_AUTO), - ('mode.mdi', L.MODE_MDI)): - h.nml_mode(mode) - h.settle(0.1) - serial = h.poll().echo_serial_number - h.pulse(request) - h.settle(0.3) - h.check('%s while already in that mode sends no command' % request, - h.poll().echo_serial_number == serial, - 'echo_serial_number %d -> %d' % (serial, h.stat.echo_serial_number)) - - # status pins follow a mode change made by another client - h.nml_mode(L.MODE_AUTO) - expect_task_mode_pins(h, L.MODE_AUTO, 'after an NML mode change') - h.nml_mode(L.MODE_MANUAL) - - -def task_mode_while_not_on(h): - for state, label in ((L.STATE_ESTOP, 'ESTOP'), (L.STATE_OFF, 'OFF')): - if state == L.STATE_ESTOP: - h.machine_estop() - else: - h.machine_on() - h.nml_state(L.STATE_OFF) - h.nml_mode(L.MODE_MANUAL) - h.pulse('mode.mdi') - h.expect('mode.mdi is accepted while in %s' % label, - lambda: h.stat.task_mode == L.MODE_MDI) - h.pulse('mode.manual') - h.expect('mode.manual is accepted while in %s' % label, - lambda: h.stat.task_mode == L.MODE_MANUAL) - - -def motion_modes(h): - h.machine_on() - h.nml_mode(L.MODE_MANUAL) - h.nml_home_all() - - h.pulse('mode.teleop') - h.expect('mode.teleop -> motion TELEOP', lambda: h.stat.motion_mode == L.TRAJ_MODE_TELEOP) - h.expect_pin('mode.is-teleop sets', 'mode.is-teleop', True) - h.expect_pin('mode.is-joint clears in teleop', 'mode.is-joint', False) - - h.pulse('mode.joint') - h.expect('mode.joint -> motion FREE', lambda: h.stat.motion_mode == L.TRAJ_MODE_FREE) - h.expect_pin('mode.is-joint sets', 'mode.is-joint', True) - h.expect_pin('mode.is-teleop clears in joint mode', 'mode.is-teleop', False) - - # in MDI, motion is in coordinated mode: neither teleop nor joint - h.nml_mode(L.MODE_MDI) - h.expect('MDI puts motion in COORD', lambda: h.stat.motion_mode == L.TRAJ_MODE_COORD) - h.expect_pin('mode.is-joint is false in COORD', 'mode.is-joint', False) - h.expect_pin('mode.is-teleop is false in COORD', 'mode.is-teleop', False) - - # status follows another client switching to teleop - h.nml_mode(L.MODE_MANUAL) - h.nml_teleop(1) - h.expect_pin('mode.is-teleop follows an NML teleop enable', 'mode.is-teleop', True) - h.nml_teleop(0) - h.expect_pin('mode.is-joint follows an NML teleop disable', 'mode.is-joint', True) - - -run(startup_status, - estop_and_power, - power_on_refused_in_estop, - inputs_are_edge_triggered, - status_follows_other_clients, - task_modes, - task_mode_while_not_on, - motion_modes) diff --git a/tests/halui/machine-state/test.sh b/tests/halui/machine-state/test.sh deleted file mode 100755 index fd122f82169..00000000000 --- a/tests/halui/machine-state/test.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/bash -exec ../_lib/launch.sh diff --git a/tests/halui/mdi-commands/checkresult b/tests/halui/mdi-commands/checkresult deleted file mode 100755 index 73e90a43dfc..00000000000 --- a/tests/halui/mdi-commands/checkresult +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/sh -exit 0 # test failure is indicated by test.sh exit value diff --git a/tests/halui/mdi-commands/halui.ini b/tests/halui/mdi-commands/halui.ini deleted file mode 100644 index b7ddfc5ab00..00000000000 --- a/tests/halui/mdi-commands/halui.ini +++ /dev/null @@ -1,102 +0,0 @@ -# Test machine shared by the halui pin tests: XYZ trivkins, one spindle, -# a tool table, a home sequence (so halui.home-all exists) and two MDI -# commands (so halui.halui-mdi-is-running and halui.mdi-command-NN exist). - -[EMC] -VERSION = 1.1 -DEBUG = 0 - -[DISPLAY] -DISPLAY = ./test-ui.py -MAX_FEED_OVERRIDE = 1.5 -MIN_SPINDLE_OVERRIDE = 0.5 -MAX_SPINDLE_OVERRIDE = 1.2 - -[TASK] -TASK = milltask -CYCLE_TIME = 0.001 - -[RS274NGC] -PARAMETER_FILE = sim.var - -[EMCMOT] -EMCMOT = motmod -COMM_TIMEOUT = 4.0 -BASE_PERIOD = 0 -SERVO_PERIOD = 1000000 - -[EMCIO] -TOOL_TABLE = tool.tbl - -[HAL] -HALFILE = LIB:core_sim.hal - -[HALUI] -MDI_COMMAND = G20 G90 G0 X1 -MDI_COMMAND = G20 G90 G0 X0 -MDI_COMMAND = G20 G90 G1 X2 F60 -MDI_COMMAND = G20 G90 G1 X0 F60 - -[TRAJ] -COORDINATES = X Y Z -LINEAR_UNITS = inch -ANGULAR_UNITS = degree -DEFAULT_LINEAR_VELOCITY = 1.2 -MAX_LINEAR_VELOCITY = 4 -SPINDLES = 1 -NO_FORCE_HOMING = 1 - -[KINS] -KINEMATICS = trivkins -JOINTS = 3 - -[AXIS_X] -MIN_LIMIT = -40.0 -MAX_LIMIT = 40.0 -MAX_VELOCITY = 4 -MAX_ACCELERATION = 1000.0 - -[AXIS_Y] -MIN_LIMIT = -40.0 -MAX_LIMIT = 40.0 -MAX_VELOCITY = 4 -MAX_ACCELERATION = 1000.0 - -[AXIS_Z] -MIN_LIMIT = -4.0 -MAX_LIMIT = 4.0 -MAX_VELOCITY = 4 -MAX_ACCELERATION = 1000.0 - -[JOINT_0] -TYPE = LINEAR -HOME = 0.0 -MAX_VELOCITY = 4 -MAX_ACCELERATION = 1000.0 -MIN_LIMIT = -40.0 -MAX_LIMIT = 40.0 -FERROR = 0.050 -MIN_FERROR = 0.010 -HOME_SEQUENCE = 0 - -[JOINT_1] -TYPE = LINEAR -HOME = 0.0 -MAX_VELOCITY = 4 -MAX_ACCELERATION = 1000.0 -MIN_LIMIT = -40.0 -MAX_LIMIT = 40.0 -FERROR = 0.050 -MIN_FERROR = 0.010 -HOME_SEQUENCE = 0 - -[JOINT_2] -TYPE = LINEAR -HOME = 0.0 -MAX_VELOCITY = 4 -MAX_ACCELERATION = 1000.0 -MIN_LIMIT = -4.0 -MAX_LIMIT = 4.0 -FERROR = 0.050 -MIN_FERROR = 0.010 -HOME_SEQUENCE = 0 diff --git a/tests/halui/mdi-commands/long.ngc b/tests/halui/mdi-commands/long.ngc deleted file mode 100644 index cac45d6b3e7..00000000000 --- a/tests/halui/mdi-commands/long.ngc +++ /dev/null @@ -1,5 +0,0 @@ -(six seconds out along X, six back: long enough to pause, resume and stop) -G20 G90 G17 -G1 X3 F30 -G1 X0 F30 -M2 diff --git a/tests/halui/mdi-commands/test-ui.py b/tests/halui/mdi-commands/test-ui.py deleted file mode 100755 index 89516f9c54b..00000000000 --- a/tests/halui/mdi-commands/test-ui.py +++ /dev/null @@ -1,182 +0,0 @@ -#!/usr/bin/env python3 -"""halui: [HALUI]MDI_COMMAND buttons. - -Pins: mdi-command-NN, halui-mdi-is-running - -halui switches task to MDI, runs the command, and switches back to the mode -it found once task reports DONE. tests/halui/mdi covers the basic round trip; -this covers the running flag, queueing, and the paths where task refuses. - -MDI_COMMAND 00: G0 X1 01: G0 X0 - 02: G1 X2 F60 03: G1 X0 F60 (two seconds each) -""" - -import os -import sys -import time - -sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', '_lib')) -from halui_test import run, close # noqa: E402 - -import linuxcnc as L # noqa: E402 - -MODES = {L.MODE_MANUAL: 'MANUAL', L.MODE_AUTO: 'AUTO', L.MODE_MDI: 'MDI'} - - -def x(h): - return h.stat.actual_position[0] - - -def expect_x(h, want, why, timeout=10): - return h.expect('X reaches %g %s' % (want, why), - lambda: close(x(h), want, 1e-4) and h.stat.inpos, timeout, - detail=lambda: 'X=%.4f' % x(h)) - - -def expect_mode(h, mode, why, timeout=5): - return h.expect('task is back in %s %s' % (MODES[mode], why), - lambda: h.stat.task_mode == mode, timeout, - detail=lambda: 'mode=%s' % MODES.get(h.stat.task_mode, h.stat.task_mode)) - - -def at_x0(h, mode): - h.machine_on() - h.nml_mdi('G20 G90 G0 X0 Y0 Z0') - h.nml_mode(mode) - - -def pins(h): - for n in range(4): - h.check('mdi-command-%02d exists' % n, h.has('mdi-command-%02d' % n)) - h.check('there is no pin beyond the configured commands', not h.has('mdi-command-04')) - h.check('halui-mdi-is-running exists because MDI commands are configured', - h.has('halui-mdi-is-running')) - h.expect_pin('halui-mdi-is-running is false at startup', 'halui-mdi-is-running', False) - - -def round_trip_from_each_mode(h): - for mode in (L.MODE_MANUAL, L.MODE_AUTO, L.MODE_MDI): - at_x0(h, mode) - h.pulse('mdi-command-00') - expect_x(h, 1, 'after mdi-command-00 from %s' % MODES[mode]) - expect_mode(h, mode, 'after the command') - h.expect_pin('halui-mdi-is-running clears after the command from %s' % MODES[mode], - 'halui-mdi-is-running', False) - - -def running_flag(h): - at_x0(h, L.MODE_MANUAL) - h.pulse('mdi-command-02') - h.expect('task switches to MDI for the command', lambda: h.stat.task_mode == L.MODE_MDI) - h.expect_pin('halui-mdi-is-running sets while the command runs', 'halui-mdi-is-running', True) - h.expect('the command is moving X', lambda: 0.2 < x(h) < 1.8) - h.check('task is still in MDI mid-command', h.stat.task_mode == L.MODE_MDI) - expect_x(h, 2, 'at the end of mdi-command-02') - expect_mode(h, L.MODE_MANUAL, 'once the command is done') - h.expect_pin('halui-mdi-is-running clears when it is done', 'halui-mdi-is-running', False) - - -def queued_commands(h): - at_x0(h, L.MODE_MANUAL) - h.pulse('mdi-command-02') - h.expect('first command under way', lambda: x(h) > 0.2) - h.pulse('mdi-command-03') - furthest = 0.0 - end = time.time() + 10 - while time.time() < end: - h.poll() - furthest = max(furthest, x(h)) - if h.stat.task_mode != L.MODE_MDI: - break - time.sleep(0.01) - h.check('both queued commands ran in order (X went to 2 and back to 0)', - furthest > 1.99 and close(x(h), 0, 1e-4), - 'furthest X=%.4f, final X=%.4f' % (furthest, x(h))) - h.check('the mode is restored only after the whole queue is done', - close(x(h), 0, 1e-4), 'mode left MDI at X=%.4f' % x(h)) - expect_mode(h, L.MODE_MANUAL, 'after the queue') - h.expect_pin('halui-mdi-is-running clears after the queue', 'halui-mdi-is-running', False) - - -def edge_only(h): - at_x0(h, L.MODE_MANUAL) - h.set('mdi-command-00', 1) - expect_x(h, 1, 'while mdi-command-00 is held') - expect_mode(h, L.MODE_MANUAL, 'while it is still held') - h.nml_mdi('G0 X0') - h.nml_mode(L.MODE_MANUAL) - h.expect_steady('a held mdi-command-00 does not run again', - lambda: close(x(h), 0, 1e-4) and h.stat.task_mode == L.MODE_MANUAL, - duration=0.8) - h.set('mdi-command-00', 0) - - -def refused_by_task(h): - # In ESTOP task accepts the switch to MDI but refuses the command itself. - at_x0(h, L.MODE_MANUAL) - h.machine_estop() - h.nml_mode(L.MODE_MANUAL) - h.drain_errors() - h.pulse('mdi-command-00') - h.settle(1.0) - s = h.poll() - h.log('mdi-command-00 in ESTOP: mode=%s status=%d X=%.4f is-running=%s errors=%r' - % (MODES.get(s.task_mode), s.state, x(h), h.get('halui-mdi-is-running'), - h.drain_errors())) - h.check('the command does not move anything in ESTOP', close(x(h), 0, 1e-4)) - h.check('task reports the refused command as an error', s.state == L.RCS_ERROR, - 'status=%d' % s.state) - # halui restores the old mode only on RCS DONE (modify_hal_pins). The - # refused command leaves task in ERROR, so nothing is restored and the - # running flag never drops. - h.known_bug('task is left in MDI after an MDI button is refused', - h.stays(lambda: h.stat.task_mode == L.MODE_MDI, 1.0), - 'halui only restores the previous mode when task status is DONE; ' - 'on ERROR it waits forever. Should be back in MANUAL') - h.known_bug('halui-mdi-is-running stays true after the refused command', - h.stays(lambda: h.get('halui-mdi-is-running'), 1.0), - 'halui_sent_mdi is cleared only on DONE; should be false') - - # The stale state resolves on the next command that finishes with DONE, - # whatever it is. Here that is powering the machine on, which therefore - # also switches task out of MDI -- long after the button press. - h.machine_on() - h.known_bug('turning the machine on later switches task back to MANUAL', - h.wait_for(lambda: h.stat.task_mode == L.MODE_MANUAL), - 'the delayed restore from the refused MDI button fires on the next DONE, ' - 'from an unrelated command') - h.expect_pin('halui-mdi-is-running clears after that', 'halui-mdi-is-running', False) - - -def while_program_runs(h): - # task refuses the switch to MDI while a program runs - at_x0(h, L.MODE_AUTO) - here = os.path.dirname(os.path.abspath(__file__)) - h.cmd.program_open(os.path.join(here, 'long.ngc')) - h.cmd.wait_complete() - h.cmd.auto(L.AUTO_RUN, 0) - h.expect('the program is running', lambda: x(h) > 0.2) - h.pulse('mdi-command-00') - h.settle(0.5) - running_flag = h.get('halui-mdi-is-running') - h.log('mdi-command-00 while a program runs: mode=%s is-running=%s' - % (MODES.get(h.poll().task_mode), running_flag)) - h.check('task stays in AUTO', h.stat.task_mode == L.MODE_AUTO) - h.known_bug('halui-mdi-is-running is true although no MDI command was sent', - running_flag, - 'sendMdiCommand() sets halui_sent_mdi before task has refused the ' - 'switch to MDI; should stay false') - h.check('the program keeps running', h.stat.interp_state != L.INTERP_IDLE) - h.nml_abort() - h.expect_pin('halui-mdi-is-running is clear once the program is gone', - 'halui-mdi-is-running', False) - h.check('task is still in AUTO afterwards', h.poll().task_mode == L.MODE_AUTO) - - -run(pins, - round_trip_from_each_mode, - running_flag, - queued_commands, - edge_only, - refused_by_task, - while_program_runs) diff --git a/tests/halui/mdi-commands/test.sh b/tests/halui/mdi-commands/test.sh deleted file mode 100755 index fd122f82169..00000000000 --- a/tests/halui/mdi-commands/test.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/bash -exec ../_lib/launch.sh diff --git a/tests/halui/overrides/checkresult b/tests/halui/overrides/checkresult deleted file mode 100755 index 73e90a43dfc..00000000000 --- a/tests/halui/overrides/checkresult +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/sh -exit 0 # test failure is indicated by test.sh exit value diff --git a/tests/halui/overrides/halui.ini b/tests/halui/overrides/halui.ini deleted file mode 100644 index 4d21b0429ec..00000000000 --- a/tests/halui/overrides/halui.ini +++ /dev/null @@ -1,100 +0,0 @@ -# Test machine shared by the halui pin tests: XYZ trivkins, one spindle, -# a tool table, a home sequence (so halui.home-all exists) and two MDI -# commands (so halui.halui-mdi-is-running and halui.mdi-command-NN exist). - -[EMC] -VERSION = 1.1 -DEBUG = 0 - -[DISPLAY] -DISPLAY = ./test-ui.py -MAX_FEED_OVERRIDE = 1.5 -MIN_SPINDLE_OVERRIDE = 0.5 -MAX_SPINDLE_OVERRIDE = 1.2 - -[TASK] -TASK = milltask -CYCLE_TIME = 0.001 - -[RS274NGC] -PARAMETER_FILE = sim.var - -[EMCMOT] -EMCMOT = motmod -COMM_TIMEOUT = 4.0 -BASE_PERIOD = 0 -SERVO_PERIOD = 1000000 - -[EMCIO] -TOOL_TABLE = tool.tbl - -[HAL] -HALFILE = LIB:core_sim.hal - -[HALUI] -MDI_COMMAND = G0 X1 Y0 Z0 -MDI_COMMAND = G0 X0 Y0 Z0 - -[TRAJ] -COORDINATES = X Y Z -LINEAR_UNITS = inch -ANGULAR_UNITS = degree -DEFAULT_LINEAR_VELOCITY = 1.2 -MAX_LINEAR_VELOCITY = 4 -SPINDLES = 1 -NO_FORCE_HOMING = 1 - -[KINS] -KINEMATICS = trivkins -JOINTS = 3 - -[AXIS_X] -MIN_LIMIT = -40.0 -MAX_LIMIT = 40.0 -MAX_VELOCITY = 4 -MAX_ACCELERATION = 1000.0 - -[AXIS_Y] -MIN_LIMIT = -40.0 -MAX_LIMIT = 40.0 -MAX_VELOCITY = 4 -MAX_ACCELERATION = 1000.0 - -[AXIS_Z] -MIN_LIMIT = -4.0 -MAX_LIMIT = 4.0 -MAX_VELOCITY = 4 -MAX_ACCELERATION = 1000.0 - -[JOINT_0] -TYPE = LINEAR -HOME = 0.0 -MAX_VELOCITY = 4 -MAX_ACCELERATION = 1000.0 -MIN_LIMIT = -40.0 -MAX_LIMIT = 40.0 -FERROR = 0.050 -MIN_FERROR = 0.010 -HOME_SEQUENCE = 0 - -[JOINT_1] -TYPE = LINEAR -HOME = 0.0 -MAX_VELOCITY = 4 -MAX_ACCELERATION = 1000.0 -MIN_LIMIT = -40.0 -MAX_LIMIT = 40.0 -FERROR = 0.050 -MIN_FERROR = 0.010 -HOME_SEQUENCE = 0 - -[JOINT_2] -TYPE = LINEAR -HOME = 0.0 -MAX_VELOCITY = 4 -MAX_ACCELERATION = 1000.0 -MIN_LIMIT = -4.0 -MAX_LIMIT = 4.0 -FERROR = 0.050 -MIN_FERROR = 0.010 -HOME_SEQUENCE = 0 diff --git a/tests/halui/overrides/test-ui.py b/tests/halui/overrides/test-ui.py deleted file mode 100755 index 25840468ee0..00000000000 --- a/tests/halui/overrides/test-ui.py +++ /dev/null @@ -1,230 +0,0 @@ -#!/usr/bin/env python3 -"""halui: feed, rapid, spindle and max-velocity overrides. - -For each override: counts (relative and direct-value), count-enable, scale, -increase, decrease, reset, value -- and the clamping halui applies. - -Limits in halui.ini: [DISPLAY]MAX_FEED_OVERRIDE = 1.5, -MIN_SPINDLE_OVERRIDE = 0.5, MAX_SPINDLE_OVERRIDE = 1.2, -[TRAJ]MAX_LINEAR_VELOCITY = 4. -""" - -import os -import sys - -sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', '_lib')) -from halui_test import run, close # noqa: E402 - -import linuxcnc as L # noqa: E402 - - -class Model: - """What halui should ask for: last value +/- steps, clamped.""" - - def __init__(self, value, lo, hi): - self.value, self.lo, self.hi, self.counts = value, lo, hi, 0 - - def clamp(self, v): - return max(self.lo, min(self.hi, v)) - - def relative(self, counts, scale): - self.value = self.clamp(self.value + (counts - self.counts) * scale) - self.counts = counts - - def direct(self, counts, scale): - self.value = self.clamp(counts * scale) - self.counts = counts - - def ignored(self, counts): - self.counts = counts - - def set(self, v): - self.value = self.clamp(v) - - -def exercise(h, label, pfx, read, lo, hi, has_reset=True): - def P(s): - return pfx + '.' + s - - m = Model(read(h.poll()), lo, hi) - - def expect(why): - # When a step leaves the value unchanged (already at a limit) the - # check below passes at once, so give halui time to sample the input - # before the next one arrives -- otherwise two steps look like one. - h.settle() - want = m.value - h.expect('%s is %.3f %s' % (label, want, why), - lambda: close(read(h.stat), want, 1e-6), - detail=lambda: 'task has %.4f' % read(h.stat)) - h.expect_pin('%s.value is %.3f %s' % (pfx, want, why), P('value'), want, tol=1e-6) - - h.check('%s.scale defaults to 0.1' % pfx, close(h.default(P('scale')), 0.1), - 'default %r' % h.default(P('scale'))) - h.check('%s.count-enable defaults to on' % pfx, h.default(P('count-enable')) is True, - 'default %r' % h.default(P('count-enable'))) - expect('at startup') - - scale = 0.1 - for c in (1, 4, 20, 19, -40, -38): - h.set(P('counts'), c) - m.relative(c, scale) - expect('after counts -> %d (relative)' % c) - - h.set(P('count-enable'), 0) - h.set(P('counts'), -30) - m.ignored(-30) - h.expect_steady('%s ignores counts while count-enable is off' % pfx, - lambda: close(read(h.stat), m.value, 1e-6)) - h.set(P('count-enable'), 1) - h.set(P('counts'), -29) - m.relative(-29, scale) - expect('after re-enabling: one count, no jump from the ignored ones') - - h.pulse(P('increase')) - m.set(m.value + scale) - expect('after increase') - h.pulse(P('decrease')) - m.set(m.value - scale) - expect('after decrease') - - h.set(P('increase'), 1) - h.settle(0.3) - m.set(m.value + scale) - expect('while increase is held (one step per edge)') - h.set(P('increase'), 0) - h.settle() - - scale = 0.25 - h.set(P('scale'), scale) - h.pulse(P('increase')) - m.set(m.value + scale) - expect('after increase with scale 0.25') - for _ in range(8): - h.pulse(P('increase')) - m.set(m.value + scale) - expect('after increasing past the upper limit') - for _ in range(12): - h.pulse(P('decrease')) - m.set(m.value - scale) - expect('after decreasing past the lower limit') - - if has_reset: - h.pulse(P('reset')) - m.set(1.0) - expect('after reset') - else: - h.check('%s has no reset pin' % pfx, not h.has(P('reset'))) - - scale = 0.1 - h.set(P('scale'), scale) - h.set(P('direct-value'), 1) - for c in (7, 30, -1, 9): - h.set(P('counts'), c) - m.direct(c, scale) - expect('after counts -> %d (direct-value)' % c) - h.set(P('direct-value'), 0) - h.set(P('counts'), 10) - m.relative(10, scale) - expect('after counts -> 10 (relative again)') - return m - - -def feed_override(h): - h.machine_on() - exercise(h, 'task feed override', 'feed-override', lambda s: s.feedrate, 0.0, 1.5) - h.cmd.feedrate(0.7) - h.expect_pin('feed-override.value follows an NML change', 'feed-override.value', 0.7) - - -def rapid_override(h): - h.machine_on() - # halui hard-codes the rapid override ceiling at 1.0 - exercise(h, 'task rapid override', 'rapid-override', lambda s: s.rapidrate, 0.0, 1.0) - h.cmd.rapidrate(0.3) - h.expect_pin('rapid-override.value follows an NML change', 'rapid-override.value', 0.3) - - -def spindle_override(h): - h.machine_on() - exercise(h, 'task spindle 0 override', 'spindle.0.override', - lambda s: s.spindle[0]['override'], 0.5, 1.2) - h.cmd.spindleoverride(0.8, 0) - h.expect_pin('spindle.0.override.value follows an NML change', - 'spindle.0.override.value', 0.8) - - -def max_velocity(h): - h.machine_on() - start = h.poll().max_velocity - h.check('task starts at [TRAJ]MAX_LINEAR_VELOCITY', close(start, 4.0), 'max_velocity=%.3f' % start) - h.expect_pin('max-velocity.value shows it', 'max-velocity.value', 4.0) - h.check('max-velocity.scale defaults to 0 (halui never initialises it)', - close(h.default('max-velocity.scale'), 0.0), 'default %r' % h.default('max-velocity.scale')) - h.check('max-velocity.count-enable defaults to on', h.default('max-velocity.count-enable') is True) - - h.set('max-velocity.scale', 0.5) - h.pulse('max-velocity.decrease') - h.known_bug('max-velocity.decrease from 4.0 lands on 1.0 instead of 3.5', - h.wait_for(lambda: close(h.stat.max_velocity, 1.0)), - 'every request is clamped to 1.0: iniLoad() no longer reads ' - '[TRAJ]MAX_LINEAR_VELOCITY into maxMaxVelocity since 2f57090adb ' - '(new ini parser); intended ceiling here is 4.0') - h.expect_pin('max-velocity.value follows the clamped value', 'max-velocity.value', 1.0) - - # inside [0, 1.0] the override behaves as intended - m = Model(1.0, 0.0, 1.0) - - def expect(why): - h.settle() - want = m.value - h.expect('task max velocity is %.3f %s' % (want, why), - lambda: close(h.stat.max_velocity, want, 1e-6), - detail=lambda: 'task has %.4f' % h.stat.max_velocity) - h.expect_pin('max-velocity.value is %.3f %s' % (want, why), 'max-velocity.value', want) - - h.pulse('max-velocity.decrease') - m.set(0.5) - expect('after decrease') - h.pulse('max-velocity.increase') - m.set(1.0) - expect('after increase') - h.pulse('max-velocity.increase') - expect('after increasing past the (buggy) 1.0 ceiling') - for c in (-1, -5, -3): - h.set('max-velocity.counts', c) - m.relative(c, 0.5) - expect('after counts -> %d (relative)' % c) - - h.set('max-velocity.count-enable', 0) - h.set('max-velocity.counts', 5) - m.ignored(5) - h.expect_steady('max-velocity ignores counts while count-enable is off', - lambda: close(h.stat.max_velocity, m.value, 1e-6)) - h.set('max-velocity.count-enable', 1) - - h.set('max-velocity.direct-value', 1) - h.set('max-velocity.counts', 1) - m.direct(1, 0.5) - expect('after counts -> 1 (direct-value)') - h.set('max-velocity.counts', 6) - h.known_bug('max-velocity direct-value 3.0 lands on 1.0', - h.wait_for(lambda: close(h.stat.max_velocity, 1.0)), - 'same maxMaxVelocity clamp; intended result is 3.0') - h.set('max-velocity.direct-value', 0) - h.check('max-velocity has no reset pin', not h.has('max-velocity.reset')) - - h.cmd.maxvel(2.5) - h.expect_pin('max-velocity.value follows an NML change', 'max-velocity.value', 2.5) - - -def not_on(h): - # overrides are immediate commands: task accepts them even when not ON - h.machine_estop() - h.cmd.feedrate(1.0) - h.cmd.wait_complete() - h.pulse('feed-override.decrease') - h.expect('feed override changes while in ESTOP', lambda: close(h.stat.feedrate, 0.9)) - - -run(feed_override, rapid_override, spindle_override, max_velocity, not_on) diff --git a/tests/halui/overrides/test.sh b/tests/halui/overrides/test.sh deleted file mode 100755 index fd122f82169..00000000000 --- a/tests/halui/overrides/test.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/bash -exec ../_lib/launch.sh diff --git a/tests/halui/program/block-delete.ngc b/tests/halui/program/block-delete.ngc deleted file mode 100644 index ccec84254ac..00000000000 --- a/tests/halui/program/block-delete.ngc +++ /dev/null @@ -1,4 +0,0 @@ -G20 G90 -G0 Z0 -/G0 Z-1 -M2 diff --git a/tests/halui/program/checkresult b/tests/halui/program/checkresult deleted file mode 100755 index 73e90a43dfc..00000000000 --- a/tests/halui/program/checkresult +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/sh -exit 0 # test failure is indicated by test.sh exit value diff --git a/tests/halui/program/halui.ini b/tests/halui/program/halui.ini deleted file mode 100644 index 4d21b0429ec..00000000000 --- a/tests/halui/program/halui.ini +++ /dev/null @@ -1,100 +0,0 @@ -# Test machine shared by the halui pin tests: XYZ trivkins, one spindle, -# a tool table, a home sequence (so halui.home-all exists) and two MDI -# commands (so halui.halui-mdi-is-running and halui.mdi-command-NN exist). - -[EMC] -VERSION = 1.1 -DEBUG = 0 - -[DISPLAY] -DISPLAY = ./test-ui.py -MAX_FEED_OVERRIDE = 1.5 -MIN_SPINDLE_OVERRIDE = 0.5 -MAX_SPINDLE_OVERRIDE = 1.2 - -[TASK] -TASK = milltask -CYCLE_TIME = 0.001 - -[RS274NGC] -PARAMETER_FILE = sim.var - -[EMCMOT] -EMCMOT = motmod -COMM_TIMEOUT = 4.0 -BASE_PERIOD = 0 -SERVO_PERIOD = 1000000 - -[EMCIO] -TOOL_TABLE = tool.tbl - -[HAL] -HALFILE = LIB:core_sim.hal - -[HALUI] -MDI_COMMAND = G0 X1 Y0 Z0 -MDI_COMMAND = G0 X0 Y0 Z0 - -[TRAJ] -COORDINATES = X Y Z -LINEAR_UNITS = inch -ANGULAR_UNITS = degree -DEFAULT_LINEAR_VELOCITY = 1.2 -MAX_LINEAR_VELOCITY = 4 -SPINDLES = 1 -NO_FORCE_HOMING = 1 - -[KINS] -KINEMATICS = trivkins -JOINTS = 3 - -[AXIS_X] -MIN_LIMIT = -40.0 -MAX_LIMIT = 40.0 -MAX_VELOCITY = 4 -MAX_ACCELERATION = 1000.0 - -[AXIS_Y] -MIN_LIMIT = -40.0 -MAX_LIMIT = 40.0 -MAX_VELOCITY = 4 -MAX_ACCELERATION = 1000.0 - -[AXIS_Z] -MIN_LIMIT = -4.0 -MAX_LIMIT = 4.0 -MAX_VELOCITY = 4 -MAX_ACCELERATION = 1000.0 - -[JOINT_0] -TYPE = LINEAR -HOME = 0.0 -MAX_VELOCITY = 4 -MAX_ACCELERATION = 1000.0 -MIN_LIMIT = -40.0 -MAX_LIMIT = 40.0 -FERROR = 0.050 -MIN_FERROR = 0.010 -HOME_SEQUENCE = 0 - -[JOINT_1] -TYPE = LINEAR -HOME = 0.0 -MAX_VELOCITY = 4 -MAX_ACCELERATION = 1000.0 -MIN_LIMIT = -40.0 -MAX_LIMIT = 40.0 -FERROR = 0.050 -MIN_FERROR = 0.010 -HOME_SEQUENCE = 0 - -[JOINT_2] -TYPE = LINEAR -HOME = 0.0 -MAX_VELOCITY = 4 -MAX_ACCELERATION = 1000.0 -MIN_LIMIT = -4.0 -MAX_LIMIT = 4.0 -FERROR = 0.050 -MIN_FERROR = 0.010 -HOME_SEQUENCE = 0 diff --git a/tests/halui/program/long.ngc b/tests/halui/program/long.ngc deleted file mode 100644 index cac45d6b3e7..00000000000 --- a/tests/halui/program/long.ngc +++ /dev/null @@ -1,5 +0,0 @@ -(six seconds out along X, six back: long enough to pause, resume and stop) -G20 G90 G17 -G1 X3 F30 -G1 X0 F30 -M2 diff --git a/tests/halui/program/optional-stop.ngc b/tests/halui/program/optional-stop.ngc deleted file mode 100644 index 563612d0428..00000000000 --- a/tests/halui/program/optional-stop.ngc +++ /dev/null @@ -1,5 +0,0 @@ -G20 G90 -G0 X0 -M1 -G0 X0.5 -M2 diff --git a/tests/halui/program/step.ngc b/tests/halui/program/step.ngc deleted file mode 100644 index 111479bd529..00000000000 --- a/tests/halui/program/step.ngc +++ /dev/null @@ -1,5 +0,0 @@ -(every line moves, so each step is visible as a change in X) -G20 G90 G0 X0.1 -G0 X0.2 -G0 X0.3 -M2 diff --git a/tests/halui/program/test-ui.py b/tests/halui/program/test-ui.py deleted file mode 100755 index dc5fe39abb6..00000000000 --- a/tests/halui/program/test-ui.py +++ /dev/null @@ -1,295 +0,0 @@ -#!/usr/bin/env python3 -"""halui: program control and program status. - -Pins: program.run, program.pause, program.resume, program.step, program.stop, - program.optional-stop.on, program.optional-stop.off, - program.optional-stop.is-on, - program.block-delete.on, program.block-delete.off, - program.block-delete.is-on, - program.is-idle, program.is-running, program.is-paused, abort - -halui cannot open a program, so opening one is done over NML as setup. -""" - -import os -import sys -import time - -HERE = os.path.dirname(os.path.abspath(__file__)) -sys.path.insert(0, os.path.join(HERE, '..', '_lib')) -from halui_test import run, close # noqa: E402 - -import linuxcnc as L # noqa: E402 - - -def running(h): - return h.stat.interp_state in (L.INTERP_READING, L.INTERP_WAITING) - - -def paused(h): - return h.stat.interp_state == L.INTERP_PAUSED - - -def idle(h): - return h.stat.interp_state == L.INTERP_IDLE - - -def x(h): - return h.poll().actual_position[0] - - -def expect_program_pins(h, is_idle, is_running, is_paused, why): - h.expect_pin('program.is-idle is %s %s' % (is_idle, why), 'program.is-idle', is_idle) - h.expect_pin('program.is-running is %s %s' % (is_running, why), 'program.is-running', is_running) - h.expect_pin('program.is-paused is %s %s' % (is_paused, why), 'program.is-paused', is_paused) - - -def to_origin(h): - h.machine_on() - h.nml_mdi('G20 G90 G0 X0 Y0 Z0') - - -def open_program(h, name): - h.nml_mode(L.MODE_AUTO) - h.cmd.program_open(os.path.join(HERE, name)) - h.cmd.wait_complete() - if not h.wait_for(lambda: h.stat.file.endswith(name)): - raise RuntimeError('setup: could not open ' + name) - - -def nml_run(h): - # wait_complete() on a run only returns once the program has finished, - # so for a short program just wait for task to take the command - h.cmd.auto(L.AUTO_RUN, 0) - if not h.wait_for(lambda: h.stat.echo_serial_number >= h.cmd.serial): - raise RuntimeError('setup: task did not take the run command') - - -def expect_still(h, name): - h.settle(0.3) - a = x(h) - h.settle(0.4) - b = x(h) - return h.check(name, close(a, b, 1e-6), 'X %.5f -> %.5f' % (a, b)) - - -def run_without_a_program(h): - h.machine_on() - h.nml_mode(L.MODE_MANUAL) - h.check('no program is open at startup', h.poll().file == '', 'file=%r' % h.stat.file) - expect_program_pins(h, True, False, False, 'at startup') - serial = h.poll().echo_serial_number - h.pulse('program.run') - h.settle(0.3) - h.check('program.run with no program open sends nothing', - h.poll().echo_serial_number == serial, - 'echo_serial_number %d -> %d' % (serial, h.stat.echo_serial_number)) - h.check('program.run with no program open leaves task in MANUAL', - h.stat.task_mode == L.MODE_MANUAL, 'mode=%d' % h.stat.task_mode) - - -def run_pause_resume_stop(h): - to_origin(h) - open_program(h, 'long.ngc') - h.nml_mode(L.MODE_MANUAL) - - h.pulse('program.run') - h.expect('program.run switches task to AUTO by itself', - lambda: h.stat.task_mode == L.MODE_AUTO) - h.expect('program.run starts the program', lambda: running(h)) - h.expect('the program moves X', lambda: h.stat.actual_position[0] > 0.2) - expect_program_pins(h, False, True, False, 'while running') - - h.pulse('program.pause') - h.expect('program.pause pauses the program', lambda: paused(h)) - expect_program_pins(h, False, False, True, 'while paused') - expect_still(h, 'motion stops while paused') - - h.pulse('program.pause') - h.expect_steady('program.pause while paused keeps it paused', lambda: paused(h), duration=0.4) - - here = x(h) - h.pulse('program.resume') - h.expect('program.resume resumes the program', lambda: running(h)) - h.expect('motion continues after resume', lambda: h.stat.actual_position[0] > here + 0.05) - expect_program_pins(h, False, True, False, 'after resume') - - h.pulse('program.resume') - h.expect_steady('program.resume while running keeps it running', lambda: running(h), duration=0.4) - - h.pulse('program.stop') - h.expect('program.stop ends the program', lambda: idle(h)) - expect_program_pins(h, True, False, False, 'after program.stop') - expect_still(h, 'motion stops after program.stop') - - -def run_while_already_in_auto(h): - to_origin(h) - open_program(h, 'long.ngc') - h.pulse('program.run') - h.expect('program.run from AUTO starts the program', lambda: running(h)) - h.pulse('program.stop') - h.expect('program.stop ends it', lambda: idle(h)) - - -def pause_when_idle(h): - # task accepts a pause with a program open but not running, and reports - # the interpreter as PAUSED. That is task behaviour, not halui's; halui - # passes the request on and its status pins report what task says. - to_origin(h) - open_program(h, 'long.ngc') - h.pulse('program.pause') - h.expect('program.pause with nothing running puts task in PAUSED', lambda: paused(h)) - expect_program_pins(h, False, False, True, 'after a pause while idle') - h.pulse('program.stop') - h.expect('program.stop leaves that paused state', lambda: idle(h)) - expect_program_pins(h, True, False, False, 'after stopping it') - - -def abort_pin(h): - to_origin(h) - open_program(h, 'long.ngc') - nml_run(h) - h.expect('the program runs (started over NML)', lambda: h.stat.actual_position[0] > 0.2) - expect_program_pins(h, False, True, False, 'while a program started over NML runs') - h.pulse('abort') - h.expect('abort ends a running program', lambda: idle(h)) - expect_program_pins(h, True, False, False, 'after abort') - expect_still(h, 'motion stops after abort') - - # abort also stops a paused program - to_origin(h) - open_program(h, 'long.ngc') - nml_run(h) - h.cmd.auto(L.AUTO_PAUSE) - h.cmd.wait_complete() - h.wait_for(lambda: paused(h)) - h.pulse('abort') - h.expect('abort ends a paused program', lambda: idle(h)) - expect_program_pins(h, True, False, False, 'after aborting a paused program') - - # and an MDI move - to_origin(h) - h.nml_mode(L.MODE_MDI) - h.cmd.mdi('G1 X3 F30') - h.expect('an MDI move is under way', lambda: h.stat.actual_position[0] > 0.1) - h.pulse('abort') - h.expect('abort ends an MDI move', lambda: idle(h)) - expect_still(h, 'motion stops after aborting MDI') - - -def step_trace(h, do_step, steps=8): - """Step through step.ngc, recording (X, interpreter state) after each step.""" - to_origin(h) - open_program(h, 'step.ngc') - trace = [] - for _ in range(steps): - do_step() - h.settle(0.6) - s = h.poll() - trace.append((round(s.actual_position[0], 4), s.interp_state)) - return trace - - -def step(h): - # How far one step gets is task's business (it lags the presses while the - # program starts up). halui's job is to turn each rising edge into exactly - # one step, so compare it with stepping over NML. - def nml_step(): - h.cmd.auto(L.AUTO_STEP) - h.cmd.wait_complete() - - reference = step_trace(h, nml_step) - h.nml_abort() - via_pin = step_trace(h, lambda: h.pulse('program.step')) - h.check('program.step steps exactly like an NML step, press for press', - via_pin == reference, 'NML %s / pin %s' % (reference, via_pin)) - - xs = [x for x, _ in via_pin] - h.check('stepping walks through the whole program', 0.3 in xs, 'X after each step: %s' % xs) - h.check('no step moves more than one line', - all(b - a <= 0.1 + 1e-6 for a, b in zip([0.0] + xs, xs)), 'X after each step: %s' % xs) - - h.pulse('program.stop') - h.expect('program.stop ends a stepped program', lambda: idle(h)) - - -def optional_stop(h): - h.machine_on() - h.pulse('program.optional-stop.on') - h.expect('optional-stop.on turns optional stop on in task', lambda: h.stat.optional_stop) - h.expect_pin('optional-stop.is-on sets', 'program.optional-stop.is-on', True) - - to_origin(h) - h.nml_mdi('G0 X0') - open_program(h, 'optional-stop.ngc') - nml_run(h) - h.expect('with optional stop on, M1 pauses the program', lambda: paused(h)) - h.check('the move after M1 has not happened', close(x(h), 0.0, 1e-4), 'X=%.4f' % x(h)) - h.pulse('program.resume') - h.expect('program.resume continues past M1', - lambda: idle(h) and close(h.stat.actual_position[0], 0.5, 1e-4)) - - h.pulse('program.optional-stop.off') - h.expect('optional-stop.off turns optional stop off in task', lambda: not h.stat.optional_stop) - h.expect_pin('optional-stop.is-on clears', 'program.optional-stop.is-on', False) - - to_origin(h) - open_program(h, 'optional-stop.ngc') - saw_pause = False - nml_run(h) - end = time.time() + 10 - while time.time() < end: - h.poll() - saw_pause = saw_pause or paused(h) - if idle(h): - break - time.sleep(0.01) - h.check('with optional stop off, M1 is skipped', not saw_pause and idle(h) - and close(h.stat.actual_position[0], 0.5, 1e-4), - 'paused=%s X=%.4f' % (saw_pause, h.stat.actual_position[0])) - - h.cmd.set_optional_stop(1) - h.expect_pin('optional-stop.is-on follows an NML change', 'program.optional-stop.is-on', True) - h.cmd.set_optional_stop(0) - h.expect_pin('optional-stop.is-on follows it back', 'program.optional-stop.is-on', False) - - -def block_delete(h): - h.machine_on() - h.pulse('program.block-delete.on') - h.expect('block-delete.on turns block delete on in task', lambda: h.stat.block_delete) - h.expect_pin('block-delete.is-on sets', 'program.block-delete.is-on', True) - - to_origin(h) - open_program(h, 'block-delete.ngc') - nml_run(h) - h.wait_idle() - h.check('with block delete on, the "/" line is skipped', - close(h.poll().actual_position[2], 0.0, 1e-4), 'Z=%.4f' % h.stat.actual_position[2]) - - h.pulse('program.block-delete.off') - h.expect('block-delete.off turns block delete off in task', lambda: not h.stat.block_delete) - h.expect_pin('block-delete.is-on clears', 'program.block-delete.is-on', False) - - to_origin(h) - open_program(h, 'block-delete.ngc') - nml_run(h) - h.wait_idle() - h.check('with block delete off, the "/" line runs', - close(h.poll().actual_position[2], -1.0, 1e-4), 'Z=%.4f' % h.stat.actual_position[2]) - - h.cmd.set_block_delete(1) - h.expect_pin('block-delete.is-on follows an NML change', 'program.block-delete.is-on', True) - h.cmd.set_block_delete(0) - h.expect_pin('block-delete.is-on follows it back', 'program.block-delete.is-on', False) - - -run(run_without_a_program, - run_pause_resume_stop, - run_while_already_in_auto, - pause_when_idle, - abort_pin, - step, - optional_stop, - block_delete) diff --git a/tests/halui/program/test.sh b/tests/halui/program/test.sh deleted file mode 100755 index fd122f82169..00000000000 --- a/tests/halui/program/test.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/bash -exec ../_lib/launch.sh diff --git a/tests/halui/spindle-coolant/checkresult b/tests/halui/spindle-coolant/checkresult deleted file mode 100755 index 73e90a43dfc..00000000000 --- a/tests/halui/spindle-coolant/checkresult +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/sh -exit 0 # test failure is indicated by test.sh exit value diff --git a/tests/halui/spindle-coolant/halui.ini b/tests/halui/spindle-coolant/halui.ini deleted file mode 100644 index 4d21b0429ec..00000000000 --- a/tests/halui/spindle-coolant/halui.ini +++ /dev/null @@ -1,100 +0,0 @@ -# Test machine shared by the halui pin tests: XYZ trivkins, one spindle, -# a tool table, a home sequence (so halui.home-all exists) and two MDI -# commands (so halui.halui-mdi-is-running and halui.mdi-command-NN exist). - -[EMC] -VERSION = 1.1 -DEBUG = 0 - -[DISPLAY] -DISPLAY = ./test-ui.py -MAX_FEED_OVERRIDE = 1.5 -MIN_SPINDLE_OVERRIDE = 0.5 -MAX_SPINDLE_OVERRIDE = 1.2 - -[TASK] -TASK = milltask -CYCLE_TIME = 0.001 - -[RS274NGC] -PARAMETER_FILE = sim.var - -[EMCMOT] -EMCMOT = motmod -COMM_TIMEOUT = 4.0 -BASE_PERIOD = 0 -SERVO_PERIOD = 1000000 - -[EMCIO] -TOOL_TABLE = tool.tbl - -[HAL] -HALFILE = LIB:core_sim.hal - -[HALUI] -MDI_COMMAND = G0 X1 Y0 Z0 -MDI_COMMAND = G0 X0 Y0 Z0 - -[TRAJ] -COORDINATES = X Y Z -LINEAR_UNITS = inch -ANGULAR_UNITS = degree -DEFAULT_LINEAR_VELOCITY = 1.2 -MAX_LINEAR_VELOCITY = 4 -SPINDLES = 1 -NO_FORCE_HOMING = 1 - -[KINS] -KINEMATICS = trivkins -JOINTS = 3 - -[AXIS_X] -MIN_LIMIT = -40.0 -MAX_LIMIT = 40.0 -MAX_VELOCITY = 4 -MAX_ACCELERATION = 1000.0 - -[AXIS_Y] -MIN_LIMIT = -40.0 -MAX_LIMIT = 40.0 -MAX_VELOCITY = 4 -MAX_ACCELERATION = 1000.0 - -[AXIS_Z] -MIN_LIMIT = -4.0 -MAX_LIMIT = 4.0 -MAX_VELOCITY = 4 -MAX_ACCELERATION = 1000.0 - -[JOINT_0] -TYPE = LINEAR -HOME = 0.0 -MAX_VELOCITY = 4 -MAX_ACCELERATION = 1000.0 -MIN_LIMIT = -40.0 -MAX_LIMIT = 40.0 -FERROR = 0.050 -MIN_FERROR = 0.010 -HOME_SEQUENCE = 0 - -[JOINT_1] -TYPE = LINEAR -HOME = 0.0 -MAX_VELOCITY = 4 -MAX_ACCELERATION = 1000.0 -MIN_LIMIT = -40.0 -MAX_LIMIT = 40.0 -FERROR = 0.050 -MIN_FERROR = 0.010 -HOME_SEQUENCE = 0 - -[JOINT_2] -TYPE = LINEAR -HOME = 0.0 -MAX_VELOCITY = 4 -MAX_ACCELERATION = 1000.0 -MIN_LIMIT = -4.0 -MAX_LIMIT = 4.0 -FERROR = 0.050 -MIN_FERROR = 0.010 -HOME_SEQUENCE = 0 diff --git a/tests/halui/spindle-coolant/test-ui.py b/tests/halui/spindle-coolant/test-ui.py deleted file mode 100755 index f1daa19269b..00000000000 --- a/tests/halui/spindle-coolant/test-ui.py +++ /dev/null @@ -1,171 +0,0 @@ -#!/usr/bin/env python3 -"""halui: spindle control, spindle brake, mist and flood. - -Pins: spindle.0.start, stop, forward, reverse, increase, decrease, - brake-on, brake-off, is-on, runs-forward, runs-backward, brake-is-on, - mist.on, mist.off, mist.is-on, flood.on, flood.off, flood.is-on -""" - -import os -import sys - -sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', '_lib')) -from halui_test import run # noqa: E402 - -import linuxcnc as L # noqa: E402 - -SP = 'spindle.0.' - - -def sp(h): - return h.stat.spindle[0] - - -def expect_spindle(h, speed, why): - direction = (speed > 0) - (speed < 0) - h.expect('spindle 0 runs at %g %s' % (speed, why), - lambda: sp(h)['speed'] == speed and sp(h)['direction'] == direction - and bool(sp(h)['enabled']) == (speed != 0), - detail=lambda: 'speed=%g direction=%d enabled=%d' - % (sp(h)['speed'], sp(h)['direction'], sp(h)['enabled'])) - h.expect_pin(SP + 'is-on is %s %s' % (speed != 0, why), SP + 'is-on', speed != 0) - h.expect_pin(SP + 'runs-forward is %s %s' % (speed > 0, why), SP + 'runs-forward', speed > 0) - h.expect_pin(SP + 'runs-backward is %s %s' % (speed < 0, why), SP + 'runs-backward', speed < 0) - - -def expect_speed_steady(h, speed, why): - h.expect_steady('spindle 0 stays at %g %s' % (speed, why), - lambda: sp(h)['speed'] == speed, - detail=lambda: 'speed=%g' % sp(h)['speed']) - - -def without_s_word(h): - h.machine_on() - h.nml_mode(L.MODE_MANUAL) - expect_spindle(h, 0, 'at startup') - # with no S word active, halui asks for speed +/-1 - h.pulse(SP + 'start') - expect_spindle(h, 1, 'after start with no S word') - h.pulse(SP + 'stop') - expect_spindle(h, 0, 'after stop') - h.pulse(SP + 'reverse') - expect_spindle(h, -1, 'after reverse with no S word') - h.pulse(SP + 'forward') - expect_spindle(h, 1, 'after forward with no S word') - h.pulse(SP + 'stop') - expect_spindle(h, 0, 'after stop') - - -def with_s_word(h): - h.machine_on() - h.nml_mdi('S500') - h.nml_mode(L.MODE_MANUAL) - h.pulse(SP + 'forward') - expect_spindle(h, 500, 'after forward with S500') - h.pulse(SP + 'reverse') - expect_spindle(h, -500, 'after reverse with S500') - h.pulse(SP + 'start') - expect_spindle(h, 500, 'after start with S500 (start is forward)') - - # each rising edge steps by [SPINDLE_0]INCREMENT (default 100); - # the falling edge sends SPINDLE_CONSTANT, which keeps the speed - h.set(SP + 'increase', 1) - expect_spindle(h, 600, 'on the rising edge of increase') - expect_speed_steady(h, 600, 'while increase is held') - h.set(SP + 'increase', 0) - expect_speed_steady(h, 600, 'after increase is released') - - h.set(SP + 'decrease', 1) - expect_spindle(h, 500, 'on the rising edge of decrease') - h.set(SP + 'decrease', 0) - expect_speed_steady(h, 500, 'after decrease is released') - - h.pulse(SP + 'reverse') - expect_spindle(h, -500, 'after reverse') - h.pulse(SP + 'increase') - expect_spindle(h, -600, 'after increase while in reverse (magnitude grows)') - h.pulse(SP + 'decrease') - expect_spindle(h, -500, 'after decrease while in reverse') - - h.pulse(SP + 'stop') - expect_spindle(h, 0, 'after stop') - h.pulse(SP + 'increase') - expect_spindle(h, 0, 'after increase while stopped (does nothing)') - h.pulse(SP + 'decrease') - expect_spindle(h, 0, 'after decrease while stopped (does nothing)') - - -def brake(h): - h.machine_on() - h.nml_mode(L.MODE_MANUAL) - h.pulse(SP + 'brake-on') - h.expect('brake-on engages the brake', lambda: sp(h)['brake'] == 1) - h.expect_pin(SP + 'brake-is-on sets', SP + 'brake-is-on', True) - h.pulse(SP + 'brake-off') - h.expect('brake-off releases the brake', lambda: sp(h)['brake'] == 0) - h.expect_pin(SP + 'brake-is-on clears', SP + 'brake-is-on', False) - - h.cmd.brake(L.BRAKE_ENGAGE, 0) - h.expect_pin(SP + 'brake-is-on follows an NML brake engage', SP + 'brake-is-on', True) - h.cmd.brake(L.BRAKE_RELEASE, 0) - h.expect_pin(SP + 'brake-is-on follows an NML brake release', SP + 'brake-is-on', False) - - -def status_follows_other_clients(h): - h.machine_on() - h.nml_mode(L.MODE_MANUAL) - h.cmd.spindle(L.SPINDLE_FORWARD, 300, 0) - expect_spindle(h, 300, 'after an NML spindle forward') - h.cmd.spindle(L.SPINDLE_REVERSE, 300, 0) - expect_spindle(h, -300, 'after an NML spindle reverse') - h.cmd.spindle(L.SPINDLE_OFF, 0) - expect_spindle(h, 0, 'after an NML spindle off') - - -def spindle_when_not_on(h): - h.machine_estop() - h.pulse(SP + 'start') - expect_speed_steady(h, 0, 'when start is pressed in ESTOP') - h.expect_pin(SP + 'is-on stays false in ESTOP', SP + 'is-on', False) - - -def coolant(h): - h.machine_on() - h.nml_mode(L.MODE_MANUAL) - for kind in ('mist', 'flood'): - read = (lambda s: s.mist) if kind == 'mist' else (lambda s: s.flood) - h.pulse(kind + '.on') - h.expect('%s.on turns %s on' % (kind, kind), lambda r=read: r(h.stat)) - h.expect_pin('%s.is-on sets' % kind, kind + '.is-on', True) - h.pulse(kind + '.off') - h.expect('%s.off turns %s off' % (kind, kind), lambda r=read: not r(h.stat)) - h.expect_pin('%s.is-on clears' % kind, kind + '.is-on', False) - - h.cmd.mist(L.MIST_ON) - h.expect_pin('mist.is-on follows an NML mist on', 'mist.is-on', True) - h.cmd.flood(L.FLOOD_ON) - h.expect_pin('flood.is-on follows an NML flood on', 'flood.is-on', True) - h.cmd.mist(L.MIST_OFF) - h.cmd.flood(L.FLOOD_OFF) - h.expect_pin('mist.is-on follows an NML mist off', 'mist.is-on', False) - h.expect_pin('flood.is-on follows an NML flood off', 'flood.is-on', False) - - -def machine_off_stops_flood(h): - # task turns flood off whenever the machine is turned on or off - # (emcTaskSetState); flood.is-on has to follow that - h.machine_on() - h.pulse('flood.on') - h.expect_pin('flood is on', 'flood.is-on', True) - h.pulse('machine.off') - h.expect('machine.off turns flood off in task', lambda: not h.stat.flood) - h.expect_pin('flood.is-on follows task turning flood off', 'flood.is-on', False) - - -run(without_s_word, - with_s_word, - brake, - status_follows_other_clients, - spindle_when_not_on, - coolant, - machine_off_stops_flood) diff --git a/tests/halui/spindle-coolant/test.sh b/tests/halui/spindle-coolant/test.sh deleted file mode 100755 index fd122f82169..00000000000 --- a/tests/halui/spindle-coolant/test.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/bash -exec ../_lib/launch.sh diff --git a/tests/halui/startup-halfile/checkresult b/tests/halui/startup-halfile/checkresult deleted file mode 100755 index 73e90a43dfc..00000000000 --- a/tests/halui/startup-halfile/checkresult +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/sh -exit 0 # test failure is indicated by test.sh exit value diff --git a/tests/halui/startup-halfile/halui-nets.hal b/tests/halui/startup-halfile/halui-nets.hal deleted file mode 100644 index bf0bcf2c075..00000000000 --- a/tests/halui/startup-halfile/halui-nets.hal +++ /dev/null @@ -1,7 +0,0 @@ -# halui pins wired from a regular HALFILE. The startup script runs HAL files -# only after halui is ready, and configs rely on that: this must keep loading -# if halui ever moves into task. -net machine-is-on-led halui.machine.is-on -net remote-estop halui.estop.activate -net remote-estop-reset halui.estop.reset -net remote-mode-mdi halui.mode.mdi diff --git a/tests/halui/startup-halfile/halui.ini b/tests/halui/startup-halfile/halui.ini deleted file mode 100644 index 901508b390c..00000000000 --- a/tests/halui/startup-halfile/halui.ini +++ /dev/null @@ -1,102 +0,0 @@ -# Test machine shared by the halui pin tests: XYZ trivkins, one spindle, -# a tool table, a home sequence (so halui.home-all exists) and two MDI -# commands (so halui.halui-mdi-is-running and halui.mdi-command-NN exist). - -[EMC] -VERSION = 1.1 -DEBUG = 0 - -[DISPLAY] -DISPLAY = ./test-ui.py -MAX_FEED_OVERRIDE = 1.5 -MIN_SPINDLE_OVERRIDE = 0.5 -MAX_SPINDLE_OVERRIDE = 1.2 - -[TASK] -TASK = milltask -CYCLE_TIME = 0.001 - -[RS274NGC] -PARAMETER_FILE = sim.var - -[EMCMOT] -EMCMOT = motmod -COMM_TIMEOUT = 4.0 -BASE_PERIOD = 0 -SERVO_PERIOD = 1000000 - -[EMCIO] -TOOL_TABLE = tool.tbl - -[HAL] -HALFILE = LIB:core_sim.hal -# halui pins wired in a regular HALFILE, not POSTGUI_HALFILE -HALFILE = halui-nets.hal - -[HALUI] -MDI_COMMAND = G0 X1 Y0 Z0 -MDI_COMMAND = G0 X0 Y0 Z0 - -[TRAJ] -COORDINATES = X Y Z -LINEAR_UNITS = inch -ANGULAR_UNITS = degree -DEFAULT_LINEAR_VELOCITY = 1.2 -MAX_LINEAR_VELOCITY = 4 -SPINDLES = 1 -NO_FORCE_HOMING = 1 - -[KINS] -KINEMATICS = trivkins -JOINTS = 3 - -[AXIS_X] -MIN_LIMIT = -40.0 -MAX_LIMIT = 40.0 -MAX_VELOCITY = 4 -MAX_ACCELERATION = 1000.0 - -[AXIS_Y] -MIN_LIMIT = -40.0 -MAX_LIMIT = 40.0 -MAX_VELOCITY = 4 -MAX_ACCELERATION = 1000.0 - -[AXIS_Z] -MIN_LIMIT = -4.0 -MAX_LIMIT = 4.0 -MAX_VELOCITY = 4 -MAX_ACCELERATION = 1000.0 - -[JOINT_0] -TYPE = LINEAR -HOME = 0.0 -MAX_VELOCITY = 4 -MAX_ACCELERATION = 1000.0 -MIN_LIMIT = -40.0 -MAX_LIMIT = 40.0 -FERROR = 0.050 -MIN_FERROR = 0.010 -HOME_SEQUENCE = 0 - -[JOINT_1] -TYPE = LINEAR -HOME = 0.0 -MAX_VELOCITY = 4 -MAX_ACCELERATION = 1000.0 -MIN_LIMIT = -40.0 -MAX_LIMIT = 40.0 -FERROR = 0.050 -MIN_FERROR = 0.010 -HOME_SEQUENCE = 0 - -[JOINT_2] -TYPE = LINEAR -HOME = 0.0 -MAX_VELOCITY = 4 -MAX_ACCELERATION = 1000.0 -MIN_LIMIT = -4.0 -MAX_LIMIT = 4.0 -FERROR = 0.050 -MIN_FERROR = 0.010 -HOME_SEQUENCE = 0 diff --git a/tests/halui/startup-halfile/test-ui.py b/tests/halui/startup-halfile/test-ui.py deleted file mode 100755 index c07b51daac6..00000000000 --- a/tests/halui/startup-halfile/test-ui.py +++ /dev/null @@ -1,67 +0,0 @@ -#!/usr/bin/env python3 -"""halui pins wired from a regular HALFILE. - -The startup script runs HAL files only after halui is ready, and configs -rely on that ordering. This config nets halui pins in a HALFILE (see -halui-nets.hal); if halui's pins did not exist yet, linuxcnc would not get -as far as running this script. -""" - -import os -import sys -import time - -sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', '_lib')) -from halui_test import run, HOLD # noqa: E402 - -import hal # noqa: E402 -import linuxcnc as L # noqa: E402 - -NETTED = {'machine.is-on', 'estop.activate', 'estop.reset', 'mode.mdi'} - - -def pulse_signal(h, sig, pin): - h.touched.add(pin) - hal.set_s(sig, True) - time.sleep(HOLD) - hal.set_s(sig, False) - time.sleep(HOLD) - - -def wiring(h): - h.check('linuxcnc started with halui pins netted from a HALFILE', True) - h.check('exactly the netted pins are wired outside the harness', - h.external == NETTED, 'external: %s' % sorted(h.external)) - - -def netted_pins_work(h): - h.expect('the machine-is-on-led signal is false in ESTOP', - lambda: not hal.get_value('machine-is-on-led')) - - pulse_signal(h, 'remote-estop-reset', 'estop.reset') - h.expect('a pulse on the netted estop.reset resets estop', - lambda: h.stat.task_state == L.STATE_ESTOP_RESET) - - h.machine_on() - h.expect('the machine-is-on-led signal follows the machine turning on', - lambda: hal.get_value('machine-is-on-led')) - - h.nml_mode(L.MODE_MANUAL) - pulse_signal(h, 'remote-mode-mdi', 'mode.mdi') - h.expect('a pulse on the netted mode.mdi switches task to MDI', - lambda: h.stat.task_mode == L.MODE_MDI) - - pulse_signal(h, 'remote-estop', 'estop.activate') - h.expect('a pulse on the netted estop.activate estops the machine', - lambda: h.stat.task_state == L.STATE_ESTOP) - h.expect('the machine-is-on-led signal drops with it', - lambda: not hal.get_value('machine-is-on-led')) - - try: - h.set('estop.activate', 1) - h.check('the harness refuses to drive a pin the config wired', False) - except KeyError: - h.check('the harness refuses to drive a pin the config wired', True) - - -run(wiring, netted_pins_work) diff --git a/tests/halui/startup-halfile/test.sh b/tests/halui/startup-halfile/test.sh deleted file mode 100755 index fd122f82169..00000000000 --- a/tests/halui/startup-halfile/test.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/bash -exec ../_lib/launch.sh diff --git a/tests/halui/tool/checkresult b/tests/halui/tool/checkresult deleted file mode 100755 index 73e90a43dfc..00000000000 --- a/tests/halui/tool/checkresult +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/sh -exit 0 # test failure is indicated by test.sh exit value diff --git a/tests/halui/tool/halui.ini b/tests/halui/tool/halui.ini deleted file mode 100644 index 4d21b0429ec..00000000000 --- a/tests/halui/tool/halui.ini +++ /dev/null @@ -1,100 +0,0 @@ -# Test machine shared by the halui pin tests: XYZ trivkins, one spindle, -# a tool table, a home sequence (so halui.home-all exists) and two MDI -# commands (so halui.halui-mdi-is-running and halui.mdi-command-NN exist). - -[EMC] -VERSION = 1.1 -DEBUG = 0 - -[DISPLAY] -DISPLAY = ./test-ui.py -MAX_FEED_OVERRIDE = 1.5 -MIN_SPINDLE_OVERRIDE = 0.5 -MAX_SPINDLE_OVERRIDE = 1.2 - -[TASK] -TASK = milltask -CYCLE_TIME = 0.001 - -[RS274NGC] -PARAMETER_FILE = sim.var - -[EMCMOT] -EMCMOT = motmod -COMM_TIMEOUT = 4.0 -BASE_PERIOD = 0 -SERVO_PERIOD = 1000000 - -[EMCIO] -TOOL_TABLE = tool.tbl - -[HAL] -HALFILE = LIB:core_sim.hal - -[HALUI] -MDI_COMMAND = G0 X1 Y0 Z0 -MDI_COMMAND = G0 X0 Y0 Z0 - -[TRAJ] -COORDINATES = X Y Z -LINEAR_UNITS = inch -ANGULAR_UNITS = degree -DEFAULT_LINEAR_VELOCITY = 1.2 -MAX_LINEAR_VELOCITY = 4 -SPINDLES = 1 -NO_FORCE_HOMING = 1 - -[KINS] -KINEMATICS = trivkins -JOINTS = 3 - -[AXIS_X] -MIN_LIMIT = -40.0 -MAX_LIMIT = 40.0 -MAX_VELOCITY = 4 -MAX_ACCELERATION = 1000.0 - -[AXIS_Y] -MIN_LIMIT = -40.0 -MAX_LIMIT = 40.0 -MAX_VELOCITY = 4 -MAX_ACCELERATION = 1000.0 - -[AXIS_Z] -MIN_LIMIT = -4.0 -MAX_LIMIT = 4.0 -MAX_VELOCITY = 4 -MAX_ACCELERATION = 1000.0 - -[JOINT_0] -TYPE = LINEAR -HOME = 0.0 -MAX_VELOCITY = 4 -MAX_ACCELERATION = 1000.0 -MIN_LIMIT = -40.0 -MAX_LIMIT = 40.0 -FERROR = 0.050 -MIN_FERROR = 0.010 -HOME_SEQUENCE = 0 - -[JOINT_1] -TYPE = LINEAR -HOME = 0.0 -MAX_VELOCITY = 4 -MAX_ACCELERATION = 1000.0 -MIN_LIMIT = -40.0 -MAX_LIMIT = 40.0 -FERROR = 0.050 -MIN_FERROR = 0.010 -HOME_SEQUENCE = 0 - -[JOINT_2] -TYPE = LINEAR -HOME = 0.0 -MAX_VELOCITY = 4 -MAX_ACCELERATION = 1000.0 -MIN_LIMIT = -4.0 -MAX_LIMIT = 4.0 -FERROR = 0.050 -MIN_FERROR = 0.010 -HOME_SEQUENCE = 0 diff --git a/tests/halui/tool/test-ui.py b/tests/halui/tool/test-ui.py deleted file mode 100755 index 5c0f4d9d6c0..00000000000 --- a/tests/halui/tool/test-ui.py +++ /dev/null @@ -1,112 +0,0 @@ -#!/usr/bin/env python3 -"""halui: tool status. - -Pins: tool.number, tool.diameter, - tool.length_offset.x/y/z/a/b/c/u/v/w - -tool.tbl: T1 Z0.5 D0.25, T2 Z1.0 D0.5, T3 Z0 D0.125. test.sh copies it -fresh from ../_lib before every run, because G10 L1 rewrites it. -""" - -import os -import sys - -HERE = os.path.dirname(os.path.abspath(__file__)) -sys.path.insert(0, os.path.join(HERE, '..', '_lib')) -from halui_test import run # noqa: E402 - -import linuxcnc as L # noqa: E402 - -OFFSET_LETTERS = 'xyzabcuvw' - - -def mdi(h, *codes): - h.machine_on() - for c in codes: - h.nml_mdi(c) - - -def expect_tool(h, number, diameter, why): - h.expect('task has tool %d in the spindle %s' % (number, why), - lambda: h.stat.tool_in_spindle == number, - detail=lambda: 'tool_in_spindle=%d' % h.stat.tool_in_spindle) - h.expect_pin('tool.number is %d %s' % (number, why), 'tool.number', number) - h.expect_pin('tool.diameter is %g %s' % (diameter, why), 'tool.diameter', diameter, tol=1e-6) - - -def expect_offsets(h, offsets, why): - for i, a in enumerate(OFFSET_LETTERS): - want = offsets.get(a, 0.0) - h.expect('task tool offset %s is %g %s' % (a, want, why), - lambda i=i, w=want: abs(h.stat.tool_offset[i] - w) < 1e-6, - detail=lambda i=i: 'tool_offset[%d]=%g' % (i, h.stat.tool_offset[i])) - h.expect_pin('tool.length_offset.%s is %g %s' % (a, want, why), - 'tool.length_offset.' + a, want, tol=1e-6) - - -def startup(h): - expect_tool(h, 0, 0.0, 'at startup') - expect_offsets(h, {}, 'at startup') - - -def tool_changes(h): - mdi(h, 'G20 G90 G49', 'M61 Q2') - expect_tool(h, 2, 0.5, 'after M61 Q2') - expect_offsets(h, {}, 'before G43') - - mdi(h, 'G43') - expect_offsets(h, {'z': 1.0}, 'after G43 with tool 2') - - mdi(h, 'M61 Q1', 'G43') - expect_tool(h, 1, 0.25, 'after M61 Q1') - expect_offsets(h, {'z': 0.5}, 'after G43 with tool 1') - - mdi(h, 'T3 M6') - expect_tool(h, 3, 0.125, 'after T3 M6') - mdi(h, 'G43') - expect_offsets(h, {'z': 0.0}, 'after G43 with tool 3') - - mdi(h, 'G43.1 X0.1 Y0.2 Z0.3') - expect_offsets(h, {'x': 0.1, 'y': 0.2, 'z': 0.3}, 'after G43.1 X0.1 Y0.2 Z0.3') - - mdi(h, 'G49') - expect_offsets(h, {}, 'after G49') - - mdi(h, 'M61 Q0') - expect_tool(h, 0, 0.0, 'after M61 Q0 (empty spindle)') - - -def status_follows_table_edits(h): - mdi(h, 'G20 G90 M61 Q2') - expect_tool(h, 2, 0.5, 'before the table edit') - mdi(h, 'G10 L1 P2 R0.4') - expect_tool(h, 2, 0.8, 'after G10 L1 P2 R0.4 (radius 0.4)') - mdi(h, 'G10 L1 P2 Z1.25', 'G43') - expect_offsets(h, {'z': 1.25}, 'after G10 L1 P2 Z1.25 and G43') - mdi(h, 'G49', 'M61 Q0') - - -def unknown_tool(h): - # modify_hal_pins() has a latent bug: its "tool not found" test compares - # the loop index with CANON_POCKETS_MAX, but the loop stops after the last - # used index, so a tool missing from the table would leave the previous - # diameter on the pin. It cannot be reached this way: task refuses M61 for - # a tool that is not in the table, and on a non-random changer index 0 - # always mirrors the loaded tool. - mdi(h, 'G20 G90 M61 Q3') - expect_tool(h, 3, 0.125, 'before asking for an unknown tool') - h.drain_errors() - h.nml_mode(L.MODE_MDI) - h.cmd.mdi('M61 Q99') - h.cmd.wait_complete() - h.wait_idle() - h.settle(0.3) - errors = h.drain_errors() - h.check('task refuses M61 for a tool that is not in the table', - h.poll().tool_in_spindle == 3 and any('99' in e for e in errors), - 'tool_in_spindle=%d errors=%r' % (h.stat.tool_in_spindle, errors)) - expect_tool(h, 3, 0.125, 'after the refused M61 Q99') - mdi(h, 'M61 Q0') - - -run(startup, tool_changes, status_follows_table_edits, unknown_tool) diff --git a/tests/halui/tool/test.sh b/tests/halui/tool/test.sh deleted file mode 100755 index fd122f82169..00000000000 --- a/tests/halui/tool/test.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/bash -exec ../_lib/launch.sh From fea0822fab96bf3fa2a383667868b44568dac83d Mon Sep 17 00:00:00 2001 From: Rene Hopf Date: Sat, 17 Oct 2026 12:15:48 +0200 Subject: [PATCH 11/21] halui: read the max-velocity limit from the INI file again The conversion to the new INI parser kept the condition but dropped the read, so maxMaxVelocity stayed 1 and halui.max-velocity.* could never set more than 1 unit/s. Read [TRAJ]MAX_LINEAR_VELOCITY, falling back to [AXIS_X]MAX_VELOCITY and then 1.0, as before. --- src/emc/task/halui.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/emc/task/halui.cc b/src/emc/task/halui.cc index cfbf16166ee..c3c0697784a 100644 --- a/src/emc/task/halui.cc +++ b/src/emc/task/halui.cc @@ -1089,8 +1089,8 @@ static int haluiIniLoad(const char *filename) } } - if(!inifile.isSet("MAX_LINEAR_VELOCITY", "TRAJ") && !inifile.isSet("MAX_VELOCITY", "AXIS_X")) - maxMaxVelocity = 1.0; + maxMaxVelocity = inifile.findRealV("MAX_LINEAR_VELOCITY", "TRAJ", + inifile.findRealV("MAX_VELOCITY", "AXIS_X", 1.0)); if (auto inival = inifile.findReal("MIN_SPINDLE_OVERRIDE", "DISPLAY")) { if (*inival > 0.0) { From 00590940ad44e1f93bc51a358ceab1410c63d1a4 Mon Sep 17 00:00:00 2001 From: Rene Hopf Date: Sat, 17 Oct 2026 12:15:48 +0200 Subject: [PATCH 12/21] task: keep halui command errors out of the NML client status A halui command does not consume a serial number, so the echo still points at the last NML command while it runs. Clearing the error flags for it hid the error of a failed NML command, and a halui command that the planner refused set ERROR on a client command that had succeeded. Leave the flags to NML commands; the planner still reports a refused halui command on the error channel. tests/halui/client-status checks both, and the max-velocity limit. --- src/emc/task/emctaskmain.cc | 13 ++-- tests/halui/client-status/checkresult | 2 + tests/halui/client-status/halui.ini | 96 ++++++++++++++++++++++++++ tests/halui/client-status/test-ui.py | 99 +++++++++++++++++++++++++++ tests/halui/client-status/test.sh | 4 ++ 5 files changed, 209 insertions(+), 5 deletions(-) create mode 100755 tests/halui/client-status/checkresult create mode 100644 tests/halui/client-status/halui.ini create mode 100755 tests/halui/client-status/test-ui.py create mode 100755 tests/halui/client-status/test.sh diff --git a/src/emc/task/emctaskmain.cc b/src/emc/task/emctaskmain.cc index bbe9a8b2cc7..655b70a81de 100644 --- a/src/emc/task/emctaskmain.cc +++ b/src/emc/task/emctaskmain.cc @@ -3575,6 +3575,7 @@ int main(int argc, char *argv[]) check_ini_hal_items(emcStatus->motion.traj.joints); // read command + bool internalDispatch = false; if (0 != emcCommandBuffer->read()) { // got a new command, so clear out errors emcCommand = emcCommandBuffer->get_address(); @@ -3585,14 +3586,16 @@ int main(int argc, char *argv[]) taskcmd::next(emcStatus->echo_serial_number)) { // A command came from inside task (halui). Point emcCommand at // it and the rest of the loop treats it exactly like one read - // from NML. + // from NML, except for the error flags: they belong to the last + // NML command, the one whose serial a client waits on. emcCommand = queued; emcCommandInternal = true; - taskPlanError = 0; - taskExecuteError = 0; + internalDispatch = true; } - // run control cycle - if (0 != emcTaskPlan()) { + // run control cycle. A command from inside task that fails is + // reported on the error channel by the planner; it must not turn + // the status of an NML client's command into ERROR. + if (0 != emcTaskPlan() && !internalDispatch) { taskPlanError = 1; } if (0 != emcTaskExecute()) { diff --git a/tests/halui/client-status/checkresult b/tests/halui/client-status/checkresult new file mode 100755 index 00000000000..73e90a43dfc --- /dev/null +++ b/tests/halui/client-status/checkresult @@ -0,0 +1,2 @@ +#!/bin/sh +exit 0 # test failure is indicated by test.sh exit value diff --git a/tests/halui/client-status/halui.ini b/tests/halui/client-status/halui.ini new file mode 100644 index 00000000000..26f32e13f82 --- /dev/null +++ b/tests/halui/client-status/halui.ini @@ -0,0 +1,96 @@ +[EMC] +VERSION = 1.1 +DEBUG = 0x7fffffff +RCS_DEBUG = 0x05400f01 + +[DISPLAY] +DISPLAY = ./test-ui.py + +[RS274NGC] +PARAMETER_FILE = sim.var +USER_M_PATH = ./subs + +[EMCMOT] +EMCMOT = motmod +COMM_TIMEOUT = 4.0 +BASE_PERIOD = 0 +SERVO_PERIOD = 1000000 + +[TASK] +TASK = milltask +CYCLE_TIME = 0.001 +MDI_QUEUED_COMMANDS=10000 + +[HAL] +HALFILE = LIB: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_VELOCITY = 4 + +[KINS] +KINEMATICS = trivkins +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 = -4.0 +MAX_LIMIT = 4.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 = -4.0 +MAX_LIMIT = 4.0 +FERROR = 0.050 +MIN_FERROR = 0.010 diff --git a/tests/halui/client-status/test-ui.py b/tests/halui/client-status/test-ui.py new file mode 100755 index 00000000000..fdecbf8cae2 --- /dev/null +++ b/tests/halui/client-status/test-ui.py @@ -0,0 +1,99 @@ +#!/usr/bin/env python3 +# halui inside task and an NML client side by side: +# - halui.max-velocity is limited by [TRAJ]MAX_LINEAR_VELOCITY, not 1; +# - a halui command that task refuses does not turn the status of the +# client's own command into ERROR, and a halui command does not clear +# the ERROR of a client command that failed. + +import os +import sys +import time + +import hal +import linuxcnc + +c = linuxcnc.command() +s = linuxcnc.stat() +e = linuxcnc.error_channel() +h = hal.component("test-ui") +h.newpin("home", hal.Type.BOOL, hal.Dir.OUT) +h.newpin("mv-counts", hal.Type.SINT, hal.Dir.OUT) +h.ready() +os.system("halcmd net home test-ui.home halui.joint.0.home") +os.system("halcmd net mv-counts test-ui.mv-counts halui.max-velocity.counts") +os.system("halcmd setp halui.max-velocity.count-enable 1") +os.system("halcmd setp halui.max-velocity.scale 0.01") +os.system("halcmd setp halui.max-velocity.direct-value 1") + +fails = 0 + + +def check(name, ok, detail=''): + global fails + print('%s: %s %s' % ('ok' if ok else 'FAIL', name, detail), flush=True) + if not ok: + fails += 1 + + +def wait(fn, timeout=5.0): + end = time.time() + timeout + while time.time() < end: + s.poll() + if fn(): + return True + time.sleep(0.01) + s.poll() + return fn() + + +def errors(): + msgs = [] + while True: + m = e.poll() + if not m: + return msgs + msgs.append(m[1]) + + +def settle(): + # give task a few cycles to dispatch a halui command + time.sleep(0.2) + + +wait(lambda: s.task_state != 0, 10) +c.state(linuxcnc.STATE_ESTOP_RESET) +c.state(linuxcnc.STATE_ON) +check('machine on', c.wait_complete() == linuxcnc.RCS_DONE) + +# --- max velocity above 1 unit/s through the counts pins +h['mv-counts'] = 250 +check('max-velocity counts 250 gives 2.5', wait(lambda: abs(s.max_velocity - 2.5) < 1e-9), s.max_velocity) +h['mv-counts'] = 1000 +check('max-velocity capped at MAX_LINEAR_VELOCITY', wait(lambda: abs(s.max_velocity - 4) < 1e-9), s.max_velocity) +errors() + +# --- a refused halui command leaves the client's DONE alone +c.state(linuxcnc.STATE_OFF) +check('machine off', c.wait_complete() == linuxcnc.RCS_DONE) +h['home'] = 1 +settle() +h['home'] = 0 +msgs = errors() +check('halui home refused while off', msgs != [], msgs) +check('client command still DONE after the refused halui command', + c.wait_complete() == linuxcnc.RCS_DONE) +s.poll() +check('status not ERROR', s.state != linuxcnc.RCS_ERROR, s.state) + +# --- a halui command leaves the client's ERROR alone +c.home(0) +check('client home refused while off', c.wait_complete() == linuxcnc.RCS_ERROR) +errors() +h['mv-counts'] = 150 +check('halui max-velocity applied', wait(lambda: abs(s.max_velocity - 1.5) < 1e-9), s.max_velocity) +check('client command still ERROR after a halui command', + c.wait_complete() == linuxcnc.RCS_ERROR) + +errors() +print('%d failures' % fails, flush=True) +os._exit(1 if fails else 0) diff --git a/tests/halui/client-status/test.sh b/tests/halui/client-status/test.sh new file mode 100755 index 00000000000..2d0bb0375f1 --- /dev/null +++ b/tests/halui/client-status/test.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +exec linuxcnc -r halui.ini + From 5f1eff621f27c15152204e1e0530cd0f18e67453 Mon Sep 17 00:00:00 2001 From: Rene Hopf Date: Fri, 16 Oct 2026 19:02:06 +0200 Subject: [PATCH 13/21] task: the task mode follows what runs and cannot be set Manual, MDI and Auto are no longer modes a user interface switches between. Task tracks what it runs (idle, a program, MDI) and reports the mode from that: Auto while a program runs or is paused, MDI while MDI commands run, Manual otherwise. - While idle task accepts jogs, homing, MDI commands and program runs. Starting a run checks homing, an open program and that no jog (including a wheel jog) is active, switches motion to coordinated mode and re-syncs the interpreter; nothing leaves interp_list until motion is in coordinated mode. When the run ends motion goes back to the joint or world mode it had before, so wheel jogs work whenever nothing runs. - The planner chooses its command table by what runs: idle (the old Manual and Auto-idle tables merged), program (unchanged), MDI running (jogs and joint/world switching refused). - EMC_TASK_SET_MODE is accepted in any state and does nothing. - halui: halui.mode.manual, .mdi and .auto do nothing, the is-* pins show the derived mode, MDI commands go straight to task. User interfaces that switch pages on the mode keep working through a per-UI view mode: Python mode(), Tcl emc_mode and linuxcncrsh set mode (per connection) record the page asked for, and task_mode / get mode report it while task is idle. AXIS loses its "coordinated while Manual, force teleop" kick and the dead tab-raise code. Behaviour changes, documented in updating-linuxcnc: switching to Manual no longer aborts a running MDI command; a run started from Manual runs the program; a run with no program open is refused; the parameter file is saved at the start of every MDI command from idle. Tests: new tests/task-modeless; halui/mdi rewritten for the new semantics; g28.2/invalid-pword waits for motion to leave coordinated mode; motion-logger, M99, interp_initcode and linuxcncrsh expectations updated for the mode switches that moved (COORD at run start, FREE or TELEOP at run end, no abort from a mode change). --- docs/src/config/python-interface.adoc | 16 +- .../getting-started/updating-linuxcnc.adoc | 35 ++ docs/src/gui/halui.adoc | 19 +- docs/src/man/man1/halui.1.adoc | 12 +- docs/src/man/man1/linuxcncrsh.1.adoc | 10 +- src/emc/task/emctask.cc | 83 +-- src/emc/task/emctaskmain.cc | 484 ++++++++---------- src/emc/task/halui.cc | 147 +----- src/emc/task/task.hh | 10 +- src/emc/usr_intf/axis/extensions/emcmodule.cc | 28 +- src/emc/usr_intf/axis/scripts/axis.py | 21 - src/emc/usr_intf/emcrsh.cc | 28 +- src/emc/usr_intf/emcsh.cc | 16 +- tests/halui/mdi/test-ui.py | 73 +-- tests/interp/g28.2/invalid-pword/test-ui.py | 7 +- .../expected.motion-logger | 18 +- tests/interp_initcode/expected | 6 +- tests/linuxcncrsh/expected-telnet-output | 12 +- tests/linuxcncrsh/test.sh | 12 +- .../basic/expected.builtin-startup.in | 23 +- tests/motion-logger/basic/expected.g0 | 2 + tests/motion-logger/basic/expected.g1 | 2 + tests/motion-logger/basic/expected.reset | 2 + tests/motion-logger/basic/expected.s | 2 + .../mountaindew/expected.motion-logger | 18 +- tests/task-modeless/.gitignore | 2 + tests/task-modeless/checkresult | 2 + tests/task-modeless/program.ngc | 4 + tests/task-modeless/sim.hal | 16 + tests/task-modeless/test-ui.py | 240 +++++++++ tests/task-modeless/test.ini | 85 +++ tests/task-modeless/test.sh | 3 + tests/task-modeless/tool.tbl | 1 + 33 files changed, 775 insertions(+), 664 deletions(-) create mode 100644 tests/task-modeless/.gitignore create mode 100755 tests/task-modeless/checkresult create mode 100644 tests/task-modeless/program.ngc create mode 100644 tests/task-modeless/sim.hal create mode 100755 tests/task-modeless/test-ui.py create mode 100644 tests/task-modeless/test.ini create mode 100755 tests/task-modeless/test.sh create mode 100644 tests/task-modeless/tool.tbl diff --git a/docs/src/config/python-interface.adoc b/docs/src/config/python-interface.adoc index 0fce1c760ac..4fc52957d7f 100644 --- a/docs/src/config/python-interface.adoc +++ b/docs/src/config/python-interface.adoc @@ -350,6 +350,11 @@ see <> for an example. *task_mode*:: '(returns integer)' - current task mode. One of `MODE_MDI`, `MODE_AUTO`, `MODE_MANUAL`. + `MODE_AUTO` while a program runs (including paused) and `MODE_MDI` + while MDI commands run. While task is idle it is the mode this process + last asked for with `mode()`, `MODE_MANUAL` until then: task's own mode + reports what runs and cannot be set, so each user interface keeps its + own page. *task_paused*:: '(returns integer)' - task paused flag. @@ -579,8 +584,6 @@ def ok_for_mdi(): return not s.estop and s.enabled and (s.homed.count(1) == s.joints) and (s.interp_state == linuxcnc.INTERP_IDLE) if ok_for_mdi(): - c.mode(linuxcnc.MODE_MDI) - c.wait_complete() # wait until mode switch executed (or default timeout of 5s occurs!) c.mdi("G0 X10 Y20 Z30") ---- @@ -627,10 +630,6 @@ c.mdi("G0 X10 Y20 Z30") c.mist(linuxcnc.MIST_ON) c.mist(linuxcnc.MIST_OFF) -c.mode(linuxcnc.MODE_MDI) -c.mode(linuxcnc.MODE_AUTO) -c.mode(linuxcnc.MODE_MANUAL) - c.override_limits() c.program_open("foo.ngc") @@ -719,7 +718,10 @@ c.tool_offset(toolno, z_offset, x_offset, diameter, frontangle, backangle, orie MIST_OFF `mode(int)`:: - set mode (MODE_MDI, MODE_MANUAL, MODE_AUTO). + set the mode this process shows (MODE_MDI, MODE_MANUAL, MODE_AUTO), see + `task_mode`. Nothing is sent to task: it starts an MDI run on `mdi()` + and a program run on `auto(AUTO_RUN)` or `auto(AUTO_STEP)` when it is + idle, and jogs and homes whenever it is idle, whatever mode was set. `override_limits()`:: set the override axis limits flag. diff --git a/docs/src/getting-started/updating-linuxcnc.adoc b/docs/src/getting-started/updating-linuxcnc.adoc index 2f9e5960909..793ac8e2288 100644 --- a/docs/src/getting-started/updating-linuxcnc.adoc +++ b/docs/src/getting-started/updating-linuxcnc.adoc @@ -247,6 +247,41 @@ there is nothing to start. Remove these from existing configurations: The pins, `[HALUI]MDI_COMMAND` and the `[DISPLAY]` override limits work as before, see link:../gui/halui.html[HAL User Interface]. +=== The task mode cannot be set + +Manual, MDI and Auto are no longer modes a user interface switches +between. Task accepts what fits what it is doing: + +* while idle: jogs, homing, an MDI command (which starts MDI) and a + program run or step (which starts the program); +* while MDI runs: more MDI commands, which queue, pause and abort; +* while a program runs: pause, step and abort, as before. + +Immediate commands such as overrides, spindle and coolant are accepted +as before. Several user interfaces can therefore show different pages at +the same time without taking the machine away from each other. + +* Task's mode, and `halui.mode.is-manual`, `.is-mdi`, `.is-auto`, report + what runs: Auto while a program runs or is paused, MDI while MDI + commands run, Manual otherwise. They change on their own when a run + starts and ends. +* The Python `mode()` command, Tcl `emc_mode` and linuxcncrsh `set mode` + no longer reach task. They set the mode that user interface (Python or + Tcl process, linuxcncrsh connection) shows, which `task_mode`, + `emc_mode` and `get mode` report while task is idle. User interfaces + that switch pages on the mode keep working, each with its own page. +* The `halui.mode.manual`, `.mdi` and `.auto` pins do nothing. +* Switching to Manual used to abort a running MDI command. It no longer + does: use abort. +* Task puts motion into coordinated mode when a run starts and back into + joint or world mode when it ends, so wheel (MPG) jogs work whenever + nothing runs. A jog in progress, including a wheel jog, holds off MDI + and program starts, which are refused with an error. +* A run started in Manual mode used to be ignored. It now runs the + program. A run or step with no program open is refused. +* While MDI runs, jogs and switching between joint and world mode are + refused; they used to be passed to motion. + == Preview renderer now requires OpenGL 3.3 core diff --git a/docs/src/gui/halui.adoc b/docs/src/gui/halui.adoc index 18d287ac60b..f725bf4236d 100644 --- a/docs/src/gui/halui.adoc +++ b/docs/src/gui/halui.adoc @@ -70,8 +70,8 @@ Owner Type Dir Value Name When a halui MDI pin is set (pulsed) true, halui will send the MDI command defined in the INI. -This will not always succeed depending on the current operating -mode (e.g., while in AUTO halui can't successfully send MDI commands). +This will not always succeed depending on what LinuxCNC is doing +(e.g., while a program runs or a jog is active task refuses MDI commands). == Example Configuration @@ -151,11 +151,10 @@ that is set in the [TRAJ] section of the INI file. * 'halui.mdi-command-__' (bool, in) - halui will try to send the MDI command defined in the INI. __ is a two digit number starting at 00. + - If the command succeeds then it will place LinuxCNC in the MDI mode and then back to Manual mode. + If no [HALUI]MDI_COMMAND variables are set in the ini file, no halui.mdi-command- pins will be exported by halui. * 'halui.halui-mdi-is-running' (bool, out) - execution status of MDI commands sent by halui. The status is active - even during mode switching. + from the press until the command finishes. If no [HALUI]MDI_COMMAND variables are set in the ini file, this pins will not be exported by halui. === Joint @@ -234,15 +233,15 @@ _L_ = axis letter (xyzabcuvw) === Mode -* 'halui.mode.auto' (bool, in) - pin for requesting auto mode -* 'halui.mode.is-auto' (bool, out) - indicates auto mode is on +* 'halui.mode.auto' (bool, in) - does nothing, the task mode follows what task runs and cannot be set +* 'halui.mode.is-auto' (bool, out) - indicates a program runs, or is paused * 'halui.mode.is-joint' (bool, out) - indicates joint by joint jog mode is on -* 'halui.mode.is-manual' (bool, out) - indicates manual mode is on -* 'halui.mode.is-mdi' (bool, out) - indicates MDI mode is on +* 'halui.mode.is-manual' (bool, out) - indicates task is idle: neither a program nor MDI runs +* 'halui.mode.is-mdi' (bool, out) - indicates MDI commands run * 'halui.mode.is-teleop' (bool, out) - indicates coordinated jog mode is on * 'halui.mode.joint' (bool, in) - pin for requesting joint by joint jog mode -* 'halui.mode.manual' (bool, in) - pin for requesting manual mode -* 'halui.mode.mdi' (bool, in) - pin for requesting MDI mode +* 'halui.mode.manual' (bool, in) - does nothing, see 'halui.mode.auto' +* 'halui.mode.mdi' (bool, in) - does nothing, see 'halui.mode.auto' * 'halui.mode.teleop' (bool, in) - pin for requesting coordinated jog mode === Program diff --git a/docs/src/man/man1/halui.1.adoc b/docs/src/man/man1/halui.1.adoc index 8f3fdc853c6..e493e8ff122 100644 --- a/docs/src/man/man1/halui.1.adoc +++ b/docs/src/man/man1/halui.1.adoc @@ -152,23 +152,23 @@ contact) connect the physical button to a HAL debounce filter first. === Mode *halui.mode.auto* bool in:: - pin for requesting auto mode + does nothing. The task mode follows what task runs and cannot be set. *halui.mode.is-auto* bool out:: - pin for auto mode is on + a program runs, or is paused *halui.mode.is-joint* bool out:: pin showing joint by joint jog mode is on *halui.mode.is-manual* bool out:: - pin for manual mode is on + task is idle: neither a program nor MDI runs *halui.mode.is-mdi* bool out:: - pin for MDI mode is on + MDI commands run *halui.mode.is-teleop* bool out:: pin showing coordinated jog mode is on *halui.mode.joint* bool in:: pin for requesting joint by joint jog mode *halui.mode.manual* bool in:: - pin for requesting manual mode + does nothing, see *halui.mode.auto* *halui.mode.mdi* bool in:: - pin for requesting MDI mode + does nothing, see *halui.mode.auto* *halui.mode.teleop* bool in:: pin for requesting coordinated jog mode diff --git a/docs/src/man/man1/linuxcncrsh.1.adoc b/docs/src/man/man1/linuxcncrsh.1.adoc index 1278e8d9923..b39c15e3a78 100644 --- a/docs/src/man/man1/linuxcncrsh.1.adoc +++ b/docs/src/man/man1/linuxcncrsh.1.adoc @@ -432,8 +432,12 @@ Subcommands for 'GET' and 'SET' are: *get mode*:: *set mode* {manual|auto|mdi}:: - With get, returns the current machine mode. - With set, sets the machine mode as specified. + With get, returns AUTO while a program runs, MDI while MDI commands + run and, while the machine is idle, the mode this connection last set + (MANUAL until then). + With set, sets the mode this connection shows. It is not sent to the + machine: task's mode reports what runs and cannot be set, and task + accepts jogs, MDI commands and program runs whatever mode is set. *get open* *set open* __:: @@ -491,7 +495,7 @@ Subcommands for 'GET' and 'SET' are: Additionally, many sanity and boundary condition checks are performed that are hard to duplicate outside of the canon interface. + - The 'SET PROBE' command can only be run in MDI mode (use 'SET MODE MDI'). + 'SET PROBE' is sent as an MDI command, so it is refused while a program runs. Additionally, 'SET PROBE' never returns a 'SET PROBE NAK' if the probe fails to make contact. However, an error is produced (use 'GET ERROR') and the 'GET PROBE_TRIPPED' returns 'NO' in that case. diff --git a/src/emc/task/emctask.cc b/src/emc/task/emctask.cc index 6e88b359372..b831ff8e154 100644 --- a/src/emc/task/emctask.cc +++ b/src/emc/task/emctask.cc @@ -52,8 +52,7 @@ static_assert(EMC_MAX_CALL_STACK >= INTERP_SUB_ROUTINE_LEVELS, #define MAX_M_DIRS (USER_DEFINED_FUNCTION_MAX_DIRS+1) //note:the +1 is for the PROGRAM_PREFIX or default directory==nc_files -/* flag for how we want to interpret traj coord mode, as mdi or auto */ -static EMC_TASK_MODE mdiOrAuto = EMC_TASK_MODE::AUTO; +TaskRun taskRun = TaskRun::NONE; InterpBase *pinterp=NULL; #define interp (*pinterp) @@ -225,7 +224,7 @@ int emcTaskStateRestore() { int res = 0; // Do NOT restore on MDI command - if (emcStatus->task.mode == EMC_TASK_MODE::AUTO) { + if (taskRun == TaskRun::PROGRAM) { // Validity of state tag checked within restore function res = pinterp->restore_from_tag(emcStatus->motion.traj.tag); } @@ -276,50 +275,6 @@ int emcTaskAbort() return 0; } -int emcTaskSetMode(EMC_TASK_MODE mode) -{ - int retval = 0; - - if (jogging_is_active()) { - log_info("Ignoring task mode change while jogging"); - return 0; - } - - switch (mode) { - case EMC_TASK_MODE::MANUAL: - // go to manual mode - if (all_homed()) { - emcTrajSetMode(EMC_TRAJ_MODE::TELEOP); - } else { - emcTrajSetMode(EMC_TRAJ_MODE::FREE); - } - mdiOrAuto = EMC_TASK_MODE::AUTO; // we'll default back to here - break; - - case EMC_TASK_MODE::MDI: - // go to mdi mode - emcTrajSetMode(EMC_TRAJ_MODE::COORD); - emcTaskAbort(); - emcTaskPlanSynch(); - mdiOrAuto = EMC_TASK_MODE::MDI; - break; - - case EMC_TASK_MODE::AUTO: - // go to auto mode - emcTrajSetMode(EMC_TRAJ_MODE::COORD); - emcTaskAbort(); - emcTaskPlanSynch(); - mdiOrAuto = EMC_TASK_MODE::AUTO; - break; - - default: - retval = -1; - break; - } - - return retval; -} - int emcTaskSetState(EMC_TASK_STATE state) { int t; @@ -384,27 +339,25 @@ int emcTaskSetState(EMC_TASK_STATE state) /* determineMode() - Looks at mode of subsystems, and returns associated mode + The task mode is not set by anyone, it reports what task is running: - Depends on traj mode, and mdiOrAuto flag - - traj mode mdiOrAuto task mode - --------- --------- --------- - FREE XXX MANUAL - TELEOP XXX MANUAL - COORD MDI MDI - COORD AUTO AUTO + taskRun task mode + ------- --------- + NONE MANUAL + PROGRAM AUTO + MDI MDI */ EMC_TASK_MODE determineMode() { - if (emcStatus->motion.traj.mode == EMC_TRAJ_MODE::FREE) { - return EMC_TASK_MODE::MANUAL; - } - if (emcStatus->motion.traj.mode == EMC_TRAJ_MODE::TELEOP) { - return EMC_TASK_MODE::MANUAL; - } - // for EMC_TRAJ_MODE::COORD - return mdiOrAuto; + switch (taskRun) { + case TaskRun::PROGRAM: + return EMC_TASK_MODE::AUTO; + case TaskRun::MDI: + return EMC_TASK_MODE::MDI; + case TaskRun::NONE: + break; + } + return EMC_TASK_MODE::MANUAL; } /* @@ -756,7 +709,7 @@ int emcTaskUpdate(EMC_TASK_STAT * stat) } // If we get an error from trying to unpack from the motion state, always // use interp's internal state, so the active state is never out of date - if (emcStatus->task.mode != EMC_TASK_MODE::AUTO || + if (taskRun != TaskRun::PROGRAM || res_state == INTERP_ERROR) { interp.active_g_codes(&stat->activeGCodes[0]); interp.active_m_codes(&stat->activeMCodes[0]); diff --git a/src/emc/task/emctaskmain.cc b/src/emc/task/emctaskmain.cc index 655b70a81de..8cdb22d43a8 100644 --- a/src/emc/task/emctaskmain.cc +++ b/src/emc/task/emctaskmain.cc @@ -416,7 +416,7 @@ static EMC_TRAJ_SET_SPINDLESYNC *emcTrajSetSpindlesyncMsg; // MDI while running in TELEOP/COORD would otherwise silently stall. We dip // motion into FREE for the duration and restore whatever mode it was in // before, invisibly to the task-level MDI/AUTO/MANUAL state -// (mdiOrAuto is untouched) -- same principle as multichannel-DESIGN.txt's +// (taskRun is untouched) -- same principle as multichannel-DESIGN.txt's // "channel sessions do NOT flip the global teleop mode" for the analogous // per-channel-homing problem. static int homingWaitJoint = -1; // joint (-1 = all) we're waiting on @@ -457,7 +457,6 @@ 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; @@ -787,23 +786,106 @@ void readahead_waiting(void) } } -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; +// Runs. Task is idle (taskRun NONE) until an MDI command or a program +// starts a run, and idle again once the run is over. Nobody sets a task +// mode; the one reported is derived from taskRun (determineMode()). +// +// Motion follows: while idle it is in free or teleop mode, so jogs, wheel +// jogs and homing work; a run puts it in coordinated mode. Motion only +// makes that switch once in position, so a run waits for it before the +// first command leaves interp_list (see coordWaiting in emcTaskExecute()). + +// Set by taskRunStart(), cleared once motion is in coordinated mode. +static bool coordWaiting = false; +static double coordWaitStart = 0.0; +static const double COORD_WAIT_TIMEOUT = 5.0; + +// The motion mode and homing at the start of a run, to go back to, and +// the mode the last run went back to. +static EMC_TRAJ_MODE runPriorMode = EMC_TRAJ_MODE::FREE; +static bool runPriorHomed = false; +static EMC_TRAJ_MODE idleMode = EMC_TRAJ_MODE::FREE; + +// Leave idle for a run. Returns -1, with an operator error, if the run may +// not start. +static int taskRunStart(TaskRun run) +{ + const bool mdi = run == TaskRun::MDI; + + if (!all_homed() && !no_force_homing) { //!no_force_homing = force homing before MDI and Auto + emcOperatorError(mdi ? _("Can't issue MDI command when not homed") + : _("Can't run a program when not homed")); + return -1; + } + if (!mdi && emcStatus->task.file[0] == 0) { + // a step would pause on nothing and never finish + emcOperatorError(_("Can't run a program: no program is open")); + return -1; + } + if (jogging_is_active()) { + emcOperatorError(mdi ? _("Can't issue MDI command while jogging") + : _("Can't run a program while jogging")); + return -1; + } + + // Right after a run the status can still show coordinated mode while + // motion is on its way back to idleMode, so send the switch anyway. + runPriorMode = emcStatus->motion.traj.mode; + if (runPriorMode == EMC_TRAJ_MODE::COORD) { + runPriorMode = idleMode; + } + runPriorHomed = all_homed(); + if (emcTrajSetMode(EMC_TRAJ_MODE::COORD) != 0) { + emcOperatorError(_("Can't switch motion to coordinated mode")); + return -1; + } + coordWaiting = true; + coordWaitStart = etime(); + + if (mdi && taskplanopen) { + // what a switch to MDI mode did: MDI does not run with the + // program open; PLAN_RUN opens it again + emcTaskPlanClose(); } + // the machine may have moved since the interpreter last looked + emcTaskPlanSynch(); + + taskRun = run; return 0; } +// Back to idle: the motion mode the run started from, or, if homing +// changed in between, world mode when homed and joint mode otherwise. +static void taskRunEnd() +{ + taskRun = TaskRun::NONE; + coordWaiting = false; + + EMC_TRAJ_MODE mode = all_homed() ? EMC_TRAJ_MODE::TELEOP : EMC_TRAJ_MODE::FREE; + if (runPriorHomed == (bool)all_homed()) { + mode = runPriorMode; + } + idleMode = mode; + emcTrajSetMode(mode); +} + +// End the run once the interpreter is idle: a program that ran to its end, +// an MDI command that finished with nothing queued behind it, or anything +// aborted. What an abort leaves on interp_list (the interpreter synch) runs +// while idle. +static void taskRunCheckDone() +{ + if (taskRun == TaskRun::NONE + || emcStatus->task.interpState != EMC_TASK_INTERP::IDLE) { + return; + } + if (taskRun == TaskRun::MDI + && (mdi_execute_queue.len() != 0 || mdi_execute_wait || mdi_execute_next)) { + return; + } + taskRunEnd(); +} + /* emcTaskPlan() @@ -823,27 +905,25 @@ static int emcTaskPlan(void) type = 0; } - // Always display messages + // Always display messages. A mode change is accepted in any state and + // does nothing, see EMC_TASK_SET_MODE_TYPE in emcTaskIssueCommand(). switch (type) { case EMC_OPERATOR_ERROR_TYPE: case EMC_OPERATOR_TEXT_TYPE: case EMC_OPERATOR_DISPLAY_TYPE: + case EMC_TASK_SET_MODE_TYPE: retval = emcTaskIssueCommand(emcCommand); return retval; } + taskRunCheckDone(); + // 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: @@ -867,7 +947,6 @@ static int emcTaskPlan(void) case EMC_TRAJ_SET_SO_ENABLE_TYPE: case EMC_TRAJ_SET_VELOCITY_TYPE: case EMC_TRAJ_SET_ACCELERATION_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: @@ -888,10 +967,10 @@ static int emcTaskPlan(void) retval = emcTaskIssueCommand(emcCommand); break; - // one case where we need to be in manual mode + // one case where nothing may be running case EMC_JOINT_OVERRIDE_LIMITS_TYPE: retval = 0; - if (emcStatus->task.mode == EMC_TASK_MODE::MANUAL) { + if (taskRun == TaskRun::NONE) { retval = emcTaskIssueCommand(emcCommand); } break; @@ -932,19 +1011,13 @@ static int emcTaskPlan(void) } // 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 on what task is running */ + switch (taskRun) { + case TaskRun::NONE: // ON, idle switch (type) { case 0: case EMC_NULL_TYPE: @@ -975,6 +1048,8 @@ static int emcTaskPlan(void) 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: @@ -986,16 +1061,15 @@ static int emcTaskPlan(void) case EMC_COOLANT_MIST_OFF_TYPE: case EMC_COOLANT_FLOOD_ON_TYPE: case EMC_COOLANT_FLOOD_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_PAUSE_TYPE: - case EMC_TASK_PLAN_REVERSE_TYPE: - case EMC_TASK_PLAN_FORWARD_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: @@ -1008,20 +1082,55 @@ static int emcTaskPlan(void) case EMC_MOTION_ADAPTIVE_TYPE: case EMC_TRAJ_RIGID_TAP_TYPE: case EMC_TRAJ_SET_TELEOP_ENABLE_TYPE: - case EMC_SET_DEBUG_TYPE: + case EMC_SET_DEBUG_TYPE: retval = emcTaskIssueCommand(emcCommand); break; - // queued commands + // commands that start a run case EMC_TASK_PLAN_EXECUTE_TYPE: - // resynch the interpreter, since we may have moved - // externally - emcTaskQueueTaskPlanSynchCmd(); - // and now call for interpreter execute - retval = emcTaskIssueCommand(emcCommand); + retval = taskRunStart(TaskRun::MDI); + if (retval == 0) { + retval = emcTaskIssueCommand(emcCommand); + if (retval != 0) { + taskRunEnd(); + } + } + break; + + case EMC_TASK_PLAN_RUN_TYPE: + retval = taskRunStart(TaskRun::PROGRAM); + if (retval == 0) { + retval = emcTaskIssueCommand(emcCommand); + if (retval != 0) { + taskRunEnd(); + } + } break; + case EMC_TASK_PLAN_STEP_TYPE: + // handles case where first action is to step the program + retval = taskRunStart(TaskRun::PROGRAM); + if (retval != 0) break; + 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) { + taskRunEnd(); + 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; + + // queued commands + case EMC_TOOL_LOAD_TOOL_TABLE_TYPE: { // send to IO emcTaskQueueCommand(std::make_unique(*static_cast(emcCommand))); @@ -1051,134 +1160,19 @@ static int emcTaskPlan(void) 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(_("can't do that (%s:%d) in manual mode"), emc_symbol_lookup(type),(int) type); + emcOperatorError(_("can't do that (%s:%d) while idle"), emc_symbol_lookup(type),(int) type); retval = -1; break; - } // switch (type) in ON, MANUAL + } // switch (type) in ON, idle - break; // case EMC_TASK_MODE::MANUAL + break; // case TaskRun::NONE - case EMC_TASK_MODE::AUTO: // ON, AUTO + case TaskRun::PROGRAM: // ON, program running 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_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_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: { - // send to IO - emcTaskQueueCommand(std::make_unique(*static_cast(emcCommand))); - // signify no more reading - emcTaskPlanSetWait(); - // then resynch interpreter - emcTaskQueueTaskPlanSynchCmd(); - break; - } - case EMC_TOOL_SET_OFFSET_TYPE: { - // send to IO - emcTaskQueueCommand(std::make_unique(*static_cast(emcCommand))); - // signify no more reading - emcTaskPlanSetWait(); - // then resynch interpreter - emcTaskQueueTaskPlanSynchCmd(); - 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(_("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 + case EMC_TASK_INTERP::READING: // ON, program, READING switch (type) { case 0: case EMC_NULL_TYPE: @@ -1209,7 +1203,6 @@ static int emcTaskPlan(void) 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: @@ -1233,18 +1226,18 @@ static int emcTaskPlan(void) // otherwise we can't handle it default: - emcOperatorError(_("can't do that (%s) in auto mode with the interpreter reading"), emc_symbol_lookup(type)); + emcOperatorError(_("can't do that (%s) while a program runs, with the interpreter reading"), emc_symbol_lookup(type)); retval = -1; break; - } // switch (type) in ON, AUTO, READING + } // switch (type) in ON, program, READING // handle interp readahead logic readahead_reading(); break; // EMC_TASK_INTERP::READING - case EMC_TASK_INTERP::PAUSED: // ON, AUTO, PAUSED + case EMC_TASK_INTERP::PAUSED: // ON, program, PAUSED switch (type) { case 0: case EMC_NULL_TYPE: @@ -1279,10 +1272,8 @@ static int emcTaskPlan(void) case EMC_COOLANT_MIST_OFF_TYPE: case EMC_COOLANT_FLOOD_ON_TYPE: case EMC_COOLANT_FLOOD_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: @@ -1314,11 +1305,11 @@ static int emcTaskPlan(void) // otherwise we can't handle it default: - emcOperatorError(_("can't do that (%s) in auto mode with the interpreter paused"), emc_symbol_lookup(type)); + emcOperatorError(_("can't do that (%s) while a program runs, with the interpreter paused"), emc_symbol_lookup(type)); retval = -1; break; - } // switch (type) in ON, AUTO, PAUSED + } // switch (type) in ON, program, PAUSED break; // EMC_TASK_INTERP::PAUSED @@ -1348,7 +1339,6 @@ static int emcTaskPlan(void) 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: @@ -1356,7 +1346,6 @@ static int emcTaskPlan(void) 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: @@ -1379,28 +1368,27 @@ static int emcTaskPlan(void) // otherwise we can't handle it default: - emcOperatorError(_("can't do that (%s) in auto mode with the interpreter waiting"), emc_symbol_lookup(type)); + emcOperatorError(_("can't do that (%s) while a program runs, with the interpreter waiting"), emc_symbol_lookup(type)); retval = -1; break; - } // switch (type) in ON, AUTO, WAITING + } // switch (type) in ON, program, WAITING // handle interp readahead logic readahead_waiting(); break; // end of case EMC_TASK_INTERP::WAITING - default: - // coding error - log_error("invalid mode({})", (int)emcStatus->task.mode); - retval = -1; + case EMC_TASK_INTERP::IDLE: + // aborted in this cycle, taskRunCheckDone() ends the run in + // the next one break; - } // switch (mode) in ON, AUTO + } // switch (interpState) in ON, program - break; // case EMC_TASK_MODE::AUTO + break; // case TaskRun::PROGRAM - case EMC_TASK_MODE::MDI: // ON, MDI + case TaskRun::MDI: // ON, MDI running switch (type) { case 0: case EMC_NULL_TYPE: @@ -1435,7 +1423,6 @@ static int emcTaskPlan(void) case EMC_COOLANT_MIST_OFF_TYPE: case EMC_COOLANT_FLOOD_ON_TYPE: case EMC_COOLANT_FLOOD_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: @@ -1503,25 +1490,17 @@ static int emcTaskPlan(void) // 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(_("can't do that (%s:%d) in MDI mode"), emc_symbol_lookup(type),(int) type); + emcOperatorError(_("can't do that (%s) while MDI is running"), emc_symbol_lookup(type)); retval = -1; break; - } // switch (type) in ON, MDI + } // switch (type) in ON, MDI running mdi_execute_hook(); - break; // case EMC_TASK_MODE::MDI - - default: - break; + break; // case TaskRun::MDI - } // switch (mode) + } // switch (taskRun) break; // case EMC_TASK_STATE::ON @@ -1756,9 +1735,8 @@ static int emcTaskIssueCommand(NMLmsg * cmd) // invalid joint number) -- homing will never start, so the // WAITING_FOR_HOMING poll below would never run to undo the // FREE-mode dip either. Undo it here instead, or traj.mode - // (and therefore task.mode, which determineMode() derives - // from it) stays stuck at FREE/MANUAL until the operator - // manually cycles mode again. + // stays stuck at FREE and the rest of the program or MDI + // command cannot move. homingWaiting = false; if (homingPriorMode != EMC_TRAJ_MODE::FREE) { emcTrajSetMode(homingPriorMode); @@ -2209,52 +2187,9 @@ static int emcTaskIssueCommand(NMLmsg * cmd) // mode and state commands case EMC_TASK_SET_MODE_TYPE: - mode_msg = reinterpret_cast(cmd); - if (emcStatus->task.mode == EMC_TASK_MODE::AUTO && - emcStatus->task.interpState != EMC_TASK_INTERP::IDLE && - mode_msg->mode != EMC_TASK_MODE::AUTO) { - emcOperatorError(_("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) { - log_info("emcTaskPlanClose() called at {}:{}\n", - __FILE__, __LINE__); - } - } - - // clear out the pending command - emcTaskCommand = NULL; - 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; - emcStatus->motion.traj.single_stepping = 0; - stepping = 0; - steppingWait = 0; - - // now queue up command to resynch interpreter - emcTaskQueueTaskPlanSynchCmd(); - } - retval = emcTaskSetMode(mode_msg->mode); - } + // The task mode reports what task is running (determineMode()) and + // cannot be set. Accept the request so existing clients keep working. + retval = 0; break; case EMC_TASK_SET_STATE_TYPE: @@ -2345,16 +2280,7 @@ static int emcTaskIssueCommand(NMLmsg * cmd) stepping = 0; steppingWait = 0; execute_msg = reinterpret_cast(cmd); - if (!all_homed() && !no_force_homing) { //!no_force_homing = force homing before MDI - emcOperatorError(_("Can't issue MDI command when not homed")); - retval = -1; - break; - } - if (emcStatus->task.mode != EMC_TASK_MODE::MDI) { - emcOperatorError(_("Must be in MDI mode to issue MDI command")); - retval = -1; - break; - } + // taskRunStart() has checked homing // track interpState also during MDI - it might be an oword sub call emcStatus->task.interpState = EMC_TASK_INTERP::READING; @@ -2369,26 +2295,22 @@ static int emcTaskIssueCommand(NMLmsg * cmd) } int level = emcTaskPlanLevel(); - if (emcStatus->task.mode == EMC_TASK_MODE::MDI) { - if (mdi_execute_level < 0) - mdi_execute_level = level; - } + 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 didn't encounter an error - if (execRetval == INTERP_ERROR) { - mdi_execute_next = 0; - } else { - mdi_execute_next = 1; - } + 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 didn't encounter an error + if (execRetval == INTERP_ERROR) { + mdi_execute_next = 0; + } else { + mdi_execute_next = 1; } } switch (execRetval) { @@ -2432,11 +2354,7 @@ static int emcTaskIssueCommand(NMLmsg * cmd) break; case EMC_TASK_PLAN_RUN_TYPE: - if (!all_homed() && !no_force_homing) { //!no_force_homing = force homing before Auto - emcOperatorError(_("Can't run a program when not homed")); - retval = -1; - break; - } + // taskRunStart() has checked homing emcStatus->motion.traj.single_stepping = 0; stepping = 0; steppingWait = 0; @@ -2743,6 +2661,20 @@ static int emcTaskExecute(void) case EMC_TASK_EXEC::DONE: STEPPING_CHECK(); + if (coordWaiting) { + // a run has just started; see taskRunStart() + if (emcStatus->motion.traj.mode == EMC_TRAJ_MODE::COORD) { + coordWaiting = false; + } else { + if (etime() - coordWaitStart > COORD_WAIT_TIMEOUT) { + coordWaiting = false; + emcOperatorError(_("Motion did not switch to coordinated mode")); + emcStatus->task.execState = EMC_TASK_EXEC::ERROR; + retval = -1; + } + break; + } + } if (!emcStatus->motion.traj.queueFull && emcStatus->task.interpState != EMC_TASK_INTERP::PAUSED) { if (NULL == emcTaskCommand) { diff --git a/src/emc/task/halui.cc b/src/emc/task/halui.cc index c3c0697784a..af1847372a9 100644 --- a/src/emc/task/halui.cc +++ b/src/emc/task/halui.cc @@ -15,7 +15,7 @@ * Nothing waits for an echo: inside task, waiting for task to answer * is a deadlock, since it is this thread that would have to answer. * -* - MDI commands become a state machine, see sendMdiCommand() below. +* - MDI commands go straight to task, see sendMdiCommand() below. * * - Status is read straight out of the live EMC_STAT. halui sees it after * task has finished the cycle's status update, which is the same @@ -43,7 +43,6 @@ #include #include -#include #include /* access to HAL functions/definitions */ #include /* rtapi_print_msg */ @@ -81,12 +80,12 @@ static int axis_mask = 0; FIELD(bool,estop_reset) /* pin for resetting ESTOP */ \ FIELD(bool,estop_is_activated) /* pin for status ESTOP is activated */ \ \ - FIELD(bool,mode_manual) /* pin for requesting manual mode */ \ - FIELD(bool,mode_is_manual) /* pin for manual mode is on */ \ - FIELD(bool,mode_auto) /* pin for requesting auto mode */ \ - FIELD(bool,mode_is_auto) /* pin for auto mode is on */ \ - FIELD(bool,mode_mdi) /* pin for requesting mdi mode */ \ - FIELD(bool,mode_is_mdi) /* pin for mdi mode is on */ \ + FIELD(bool,mode_manual) /* pin for requesting manual mode, does nothing */ \ + FIELD(bool,mode_is_manual) /* pin for manual mode is on: task is idle */ \ + FIELD(bool,mode_auto) /* pin for requesting auto mode, does nothing */ \ + FIELD(bool,mode_is_auto) /* pin for auto mode is on: a program runs */ \ + FIELD(bool,mode_mdi) /* pin for requesting mdi mode, does nothing */ \ + FIELD(bool,mode_is_mdi) /* pin for mdi mode is on: MDI runs */ \ FIELD(bool,mode_teleop) /* pin for requesting teleop mode */ \ FIELD(bool,mode_is_teleop) /* pin for teleop mode is on */ \ FIELD(bool,mode_joint) /* pin for requesting joint mode */ \ @@ -267,7 +266,6 @@ static double maxFeedOverride=1; static double maxMaxVelocity=1; static double minSpindleOverride=0.0; static double maxSpindleOverride=1.0; -static EMC_TASK_MODE halui_old_mode = EMC_TASK_MODE::MANUAL; static int halui_sent_mdi = 0; @@ -276,9 +274,7 @@ static const double HALUI_PERIOD = 0.020; static double last_pass = 0.0; -// MDI state machine, see sendMdiCommand() -static std::deque mdi_pending; -static taskcmd::Ticket mdi_mode_ticket = 0; +// the last MDI command halui queued, see sendMdiCommand() static taskcmd::Ticket mdi_exec_ticket = 0; // Queue a command for task to execute on one of the next cycles. This is @@ -634,48 +630,9 @@ static int sendEstopReset() return emcCommandSend(state_msg); } -static int sendManual() -{ - EMC_TASK_SET_MODE mode_msg; - - if (emcStatus->task.mode == EMC_TASK_MODE::MANUAL) { - return 0; - } - - mode_msg.mode = EMC_TASK_MODE::MANUAL; - return emcCommandSend(mode_msg); -} - -static int sendAuto() -{ - EMC_TASK_SET_MODE mode_msg; - - if (emcStatus->task.mode == EMC_TASK_MODE::AUTO) { - return 0; - } - - mode_msg.mode = EMC_TASK_MODE::AUTO; - return emcCommandSend(mode_msg); -} - -static int sendMdi() -{ - EMC_TASK_SET_MODE mode_msg; - - if (emcStatus->task.mode == EMC_TASK_MODE::MDI) { - return 0; - } - - mode_msg.mode = EMC_TASK_MODE::MDI; - return emcCommandSend(mode_msg); -} - -// Start an [HALUI]MDI_COMMAND. The standalone halui could block here: it -// sent the switch to MDI, waited for task to echo it, checked the mode and -// only then sent the command itself. Inside task nothing may block, so the -// sequence becomes a state machine, driven by service_mdi() below: -// -// press -> queue SET_MODE(MDI) -> task reaches MDI -> queue EXECUTE +// Start an [HALUI]MDI_COMMAND. Task needs no mode for it: an MDI command +// starts an MDI run when task is idle, and queues behind the running one +// during MDI. Task refuses it while a program runs or a jog is active. // // What the pins do is unchanged, including the two known quirks the tests // pin down: halui-mdi-is-running goes true at the press, before task has @@ -683,60 +640,15 @@ static int sendMdi() // next command finishes DONE. static void sendMdiCommand(int n) { - if (!halui_sent_mdi) { - // There is currently no MDI command from halui executing, we're - // currently starting the first one. Record what the Task mode is, - // so we can restore it when all the MDI commands finish. - halui_old_mode = emcStatus->task.mode; - } - halui_sent_mdi = 1; if (num_mdi_commands > 0) { hal_set_bool(halui_data->halui_mdi_is_running, halui_sent_mdi); } - mdi_pending.push_back(n); - - // switch to MDI mode if needed - if (emcStatus->task.mode != EMC_TASK_MODE::MDI && mdi_mode_ticket == 0) { - EMC_TASK_SET_MODE mode_msg; - mode_msg.mode = EMC_TASK_MODE::MDI; - mdi_mode_ticket = taskcmd::push(mode_msg); - } -} - -// Issue the MDI commands waiting for task to be in MDI mode, or give up on -// them if task did not go there. Runs every task cycle. -static void service_mdi() -{ - if (mdi_pending.empty()) { - return; - } - - if (emcStatus->task.mode == EMC_TASK_MODE::MDI) { - mdi_mode_ticket = 0; - while (!mdi_pending.empty()) { - EMC_TASK_PLAN_EXECUTE emc_task_plan_execute_msg; - rtapi_strxcpy(emc_task_plan_execute_msg.command, - mdi_commands[mdi_pending.front()]); - mdi_exec_ticket = taskcmd::push(emc_task_plan_execute_msg); - mdi_pending.pop_front(); - } - return; - } - - if (!taskcmd::pending(mdi_mode_ticket)) { - // Task has been through the mode change and is not in MDI, so it - // refused it -- while a program runs, for instance. Drop the - // commands, exactly as the standalone halui did when its mode - // check failed. halui_sent_mdi deliberately stays set: the pins - // recover on the next command that ends DONE. - rtapi_print("halui: %s: could not switch task to mdi, dropping %d command(s)\n", - __func__, (int)mdi_pending.size()); - mdi_pending.clear(); - mdi_mode_ticket = 0; - } + EMC_TASK_PLAN_EXECUTE emc_task_plan_execute_msg; + rtapi_strxcpy(emc_task_plan_execute_msg.command, mdi_commands[n]); + mdi_exec_ticket = taskcmd::push(emc_task_plan_execute_msg); } // True once the MDI command halui started has actually been issued by task @@ -745,8 +657,6 @@ static void service_mdi() static bool mdi_settled() { return halui_sent_mdi - && mdi_pending.empty() - && !taskcmd::pending(mdi_mode_ticket) && !taskcmd::pending(mdi_exec_ticket); } @@ -812,7 +722,6 @@ static int sendProgramRun(int line) programStartLine = line; emc_task_plan_run_msg.line = line; - sendAuto(); return emcCommandSend(emc_task_plan_run_msg); } @@ -1325,14 +1234,8 @@ static void check_hal_changes() if (check_bit_changed(new_halui_data.estop_reset, old_halui_data.estop_reset) != 0) sendEstopReset(); - if (check_bit_changed(new_halui_data.mode_manual, old_halui_data.mode_manual) != 0) - sendManual(); - - if (check_bit_changed(new_halui_data.mode_auto, old_halui_data.mode_auto) != 0) - sendAuto(); - - if (check_bit_changed(new_halui_data.mode_mdi, old_halui_data.mode_mdi) != 0) - sendMdi(); + // halui.mode.manual, .auto and .mdi do nothing: the task mode follows + // what task runs if (check_bit_changed(new_halui_data.mode_teleop, old_halui_data.mode_teleop) != 0) sendTeleop(); @@ -1778,21 +1681,9 @@ static void modify_hal_pins() hal_set_bool(halui_data->machine_is_on, emcStatus->task.state == EMC_TASK_STATE::ON); hal_set_bool(halui_data->estop_is_activated, emcStatus->task.state == EMC_TASK_STATE::ESTOP); - // Decide once whether an ongoing halui MDI command has finished: the mode - // restore below may refresh emcStatus, and Task may echo it while still EXEC. + // whether an ongoing halui MDI command has finished bool mdi_finished = mdi_settled() && emcStatus->status == RCS_STATUS::DONE; - if (mdi_settled()) { // we have an ongoing MDI command - if (mdi_finished) { //which seems to have finished - switch (halui_old_mode) { - case EMC_TASK_MODE::MANUAL: sendManual();break; - case EMC_TASK_MODE::MDI: break; - case EMC_TASK_MODE::AUTO: sendAuto();break; - default: sendManual();break; - } - } - } - hal_set_bool(halui_data->mode_is_manual, emcStatus->task.mode == EMC_TASK_MODE::MANUAL); hal_set_bool(halui_data->mode_is_auto, emcStatus->task.mode == EMC_TASK_MODE::AUTO); @@ -2021,10 +1912,6 @@ void haluiUpdate(void) check_hal_changes(); //if anything changed send commands } - // every cycle, and after check_hal_changes() so that a button pressed - // in this pass is acted on in it - service_mdi(); - if (due) { modify_hal_pins(); //if status changed modify HAL too } diff --git a/src/emc/task/task.hh b/src/emc/task/task.hh index d8c619cdb50..3e258beae5e 100644 --- a/src/emc/task/task.hh +++ b/src/emc/task/task.hh @@ -29,11 +29,19 @@ extern int emcTaskOnce(const char *inifile, EMC_IO_STAT &emcioStatus); int all_homed(void); bool jogging_is_active(void); +// What task is running. The task mode reported in the status is derived +// from it (determineMode()); nothing sets the mode directly. +enum class TaskRun { + NONE, // idle: jogs, homing, MDI and program starts are accepted + PROGRAM, // a program run, from PLAN_RUN or PLAN_STEP + MDI, // MDI commands, from PLAN_EXECUTE +}; +extern TaskRun taskRun; + int emcTaskInit(); int emcTaskHalt(); int emcTaskStateRestore(); int emcTaskAbort(); -int emcTaskSetMode(EMC_TASK_MODE mode); int emcTaskSetState(EMC_TASK_STATE state); int emcTaskPlanInit(); int emcTaskPlanSetWait(); diff --git a/src/emc/usr_intf/axis/extensions/emcmodule.cc b/src/emc/usr_intf/axis/extensions/emcmodule.cc index 635726e7cd7..bdf297c286e 100644 --- a/src/emc/usr_intf/axis/extensions/emcmodule.cc +++ b/src/emc/usr_intf/axis/extensions/emcmodule.cc @@ -1134,7 +1134,6 @@ static PyMemberDef Stat_members[] = { { "state", T_INT, O(status), READONLY, NULL}, // task - { "task_mode", T_INT, O(task.mode), READONLY, NULL}, { "task_state", T_INT, O(task.state), READONLY, "Current Task state. Possible values:\n" " STATE_ESTOP: E-Stop is active.\n" @@ -1369,6 +1368,21 @@ static PyObject *Stat_homed(pyStatChannel *s, void *) { return res; } +// The page a user interface shows. Task's mode cannot be set: it reports +// MDI or Auto while one runs and Manual while idle. mode() records the +// page this process asked for instead, and task_mode returns it while task +// is idle, so each user interface keeps its own page and the ones that +// follow task_mode to switch pages keep working. +static EMC_TASK_MODE view_mode = EMC_TASK_MODE::MANUAL; + +static PyObject *Stat_task_mode(pyStatChannel *s, void *) { + EMC_TASK_MODE mode = s->status.task.mode; + if (mode == EMC_TASK_MODE::MANUAL) { + mode = view_mode; + } + return PyLong_FromLong((long)mode); +} + static PyObject *Stat_ain(pyStatChannel *s, void *) { return double_array(s->status.motion.analog_input, EMCMOT_MAX_AIO); } @@ -1580,6 +1594,7 @@ static PyObject *Stat_taskbeat(pyStatChannel *s, void *) { static PyGetSetDef Stat_getsetlist[] = { {(char*)"actual_position", (getter)Stat_actual, NULL, NULL, NULL}, {(char*)"ain", (getter)Stat_ain, NULL, NULL, NULL}, + {(char*)"task_mode", (getter)Stat_task_mode, NULL, NULL, NULL}, {(char*)"aout", (getter)Stat_aout, NULL, NULL, NULL}, {(char*)"joint", (getter)Stat_joint, NULL, NULL, NULL}, {(char*)"axis", (getter)Stat_axis, NULL, NULL, NULL}, @@ -1749,10 +1764,11 @@ static PyObject *optional_stop(pyCommandChannel *s, PyObject *o) { return Py_None; } -static PyObject *mode(pyCommandChannel *s, PyObject *o) { - EMC_TASK_SET_MODE m; - if(!PyArg_ParseTuple(o, "i", &m.mode)) return NULL; - switch(m.mode) { +// Nothing goes to task, see view_mode. +static PyObject *mode(pyCommandChannel * /*s*/, PyObject *o) { + EMC_TASK_MODE m; + if(!PyArg_ParseTuple(o, "i", &m)) return NULL; + switch(m) { case EMC_TASK_MODE::MDI: case EMC_TASK_MODE::MANUAL: case EMC_TASK_MODE::AUTO: @@ -1761,7 +1777,7 @@ static PyObject *mode(pyCommandChannel *s, PyObject *o) { PyErr_Format(PyExc_ValueError,"Mode should be MODE_MDI, MODE_MANUAL, or MODE_AUTO"); return NULL; } - emcSendCommand(s, m); + view_mode = m; Py_INCREF(Py_None); return Py_None; } diff --git a/src/emc/usr_intf/axis/scripts/axis.py b/src/emc/usr_intf/axis/scripts/axis.py index 9477cca0332..ad767fa0fec 100755 --- a/src/emc/usr_intf/axis/scripts/axis.py +++ b/src/emc/usr_intf/axis/scripts/axis.py @@ -746,7 +746,6 @@ def start(self): self.stat = linuxcnc.stat() except linuxcnc.error: return False - self.last_task_mode = self.stat.task_mode self.last_motion_mode = self.stat.motion_mode def C(s): a = o.colors[s + "_alpha"] @@ -844,30 +843,10 @@ def update(self): continuous_jog_in_progress = 0 cjogindices = [] - if ( (self.stat.motion_mode == linuxcnc.TRAJ_MODE_COORD) - and (self.stat.task_mode == linuxcnc.MODE_MANUAL) - ): - set_motion_teleop(1) if ( (self.stat.motion_mode == linuxcnc.TRAJ_MODE_TELEOP) and not vars.teleop_mode.get() ): vars.teleop_mode.set(1) - # With joints_axes support and jogging while mdi - # (ref: emctaskmain.cc:allow_while_idle_type()) - # behavior is better without changing tabs upon detecting - # a task_mode change. - # Restore behavior with this local var: enable_tab_change - enable_tab_change = False - if ( enable_tab_change - and (self.stat.task_mode != self.last_task_mode)): - if (self.stat.task_mode == linuxcnc.MODE_MANUAL): - root_window.tk.eval(pane_top + ".tabs raise manual") - if (self.stat.task_mode == linuxcnc.MODE_MDI): - root_window.tk.eval(pane_top + ".tabs raise mdi") - if (self.stat.task_mode == linuxcnc.MODE_AUTO): - # not sure if anything needs to be done for this - pass - self.last_task_mode = self.stat.task_mode self.after = self.win.after(update_ms, self.update) diff --git a/src/emc/usr_intf/emcrsh.cc b/src/emc/usr_intf/emcrsh.cc index 88550e56177..500a05f986c 100644 --- a/src/emc/usr_intf/emcrsh.cc +++ b/src/emc/usr_intf/emcrsh.cc @@ -172,6 +172,7 @@ typedef struct { std::string version; // Client's version std::string progname; // Filename of (g-code) program EMC_WAIT_TYPE waitmode; // Local to the connection to allow others to intervene + EMC_TASK_MODE viewmode; // The mode this connection asked for, see getMode() double cmdtimeout; // Command timeout (infinite when <= 0.0) double usrtimeout; // Timeout as set by SET TIMEOUT int serial; // The serial number of the last command sent @@ -1161,20 +1162,13 @@ static cmdResponseType setUpdateStatus(connectionRecType &) static cmdResponseType setMode(connectionRecType &ctx) { // SET MODE + // Nothing goes to task: its mode cannot be set. The connection keeps + // the mode it asked for, see getMode(). switch (checkManualAutoMDI(ctx.toks[2])) { default: errornl(ctx, fmt::format("Invalid argument '{}', must be {{manual,auto,mdi}}", ctx.toks[2])); return rtError; - case kwManual: - if (sendManual()) - return rtError; - break; - case kwAuto: - if (sendAuto()) - return rtError; - break; - case kwMDI: - if (sendMdi()) - return rtError; - break; + case kwManual: ctx.viewmode = EMC_TASK_MODE::MANUAL; break; + case kwAuto: ctx.viewmode = EMC_TASK_MODE::AUTO; break; + case kwMDI: ctx.viewmode = EMC_TASK_MODE::MDI; break; } return rtOk; } @@ -2015,12 +2009,17 @@ static cmdResponseType getMachine(connectionRecType &ctx) static cmdResponseType getMode(connectionRecType &ctx) { // GET MODE - switch (emcStatus->task.mode) { + // Task's mode reports what runs and cannot be set. While task is + // idle, report the mode this connection asked for with SET MODE. + EMC_TASK_MODE mode = emcStatus->task.mode; + if (mode == EMC_TASK_MODE::MANUAL) + mode = ctx.viewmode; + switch (mode) { case EMC_TASK_MODE::MANUAL: replynl(ctx, "MODE MANUAL"); break; case EMC_TASK_MODE::AUTO: replynl(ctx, "MODE AUTO"); break; case EMC_TASK_MODE::MDI: replynl(ctx, "MODE MDI"); break; default: - errornl(ctx, fmt::format("internal: GET MODE: unrecognised EMC_TASK_MODE value '{}'", (int)emcStatus->task.mode)); + errornl(ctx, fmt::format("internal: GET MODE: unrecognised EMC_TASK_MODE value '{}'", (int)mode)); replynl(ctx, "MODE ?"); } return rtOk; @@ -3590,6 +3589,7 @@ static int sockMain(int svrfd) cr.version = "1.1"; cr.echo = true; cr.waitmode = EMC_WAIT_DONE; + cr.viewmode = EMC_TASK_MODE::MANUAL; //cr.timestamp= true; clients.push_back(cr); if(isipv4) { diff --git a/src/emc/usr_intf/emcsh.cc b/src/emc/usr_intf/emcsh.cc index e7e20296f37..87de1946b26 100644 --- a/src/emc/usr_intf/emcsh.cc +++ b/src/emc/usr_intf/emcsh.cc @@ -1008,6 +1008,10 @@ static int emc_machine(ClientData /*clientdata*/, return TCL_ERROR; } +// The mode this process asked for with emc_mode. Task's mode reports what +// runs and cannot be set; while task is idle emc_mode reports this one. +static EMC_TASK_MODE viewMode = EMC_TASK_MODE::MANUAL; + static int emc_mode(ClientData /*clientdata*/, Tcl_Interp * interp, int objc, Tcl_Obj * CONST objv[]) { @@ -1019,7 +1023,11 @@ static int emc_mode(ClientData /*clientdata*/, if (emcUpdateType == EMC_UPDATE_AUTO) { updateStatus(); } - switch (emcStatus->task.mode) { + EMC_TASK_MODE mode = emcStatus->task.mode; + if (mode == EMC_TASK_MODE::MANUAL) { + mode = viewMode; + } + switch (mode) { case EMC_TASK_MODE::MANUAL: setresult(interp,"manual"); break; @@ -1039,15 +1047,15 @@ static int emc_mode(ClientData /*clientdata*/, if (objc == 2) { objstr = Tcl_GetStringFromObj(objv[1], NULL); if (!strcmp(objstr, "manual")) { - sendManual(); + viewMode = EMC_TASK_MODE::MANUAL; return TCL_OK; } if (!strcmp(objstr, "auto")) { - sendAuto(); + viewMode = EMC_TASK_MODE::AUTO; return TCL_OK; } if (!strcmp(objstr, "mdi")) { - sendMdi(); + viewMode = EMC_TASK_MODE::MDI; return TCL_OK; } } diff --git a/tests/halui/mdi/test-ui.py b/tests/halui/mdi/test-ui.py index 296db4b1d62..a096dd71c2f 100755 --- a/tests/halui/mdi/test-ui.py +++ b/tests/halui/mdi/test-ui.py @@ -115,61 +115,40 @@ def wait_for_halui_mode(pin_name): # wrong. # -log("setting mode to Manual") +# The task mode cannot be set: halui's MDI commands run from whatever mode +# a UI asked for, and task is back in Manual (idle) when they finish. +# c.mode() only sets this process's view (what s.task_mode reports while +# task is idle), so task's own mode is read from the halui pins. + +def mdi_then_manual(n, x, y, z): + log("running MDI command %d" % n) + h['mdi-%d' % n] = 1 + wait_for_joint_to_stop_at(0, x); + wait_for_joint_to_stop_at(1, y); + wait_for_joint_to_stop_at(2, z); + h['mdi-%d' % n] = 0 + wait_for_halui_mode('is-manual') + +log("asking for Manual mode") c.mode(linuxcnc.MODE_MANUAL) wait_for_halui_mode('is-manual') -log("running MDI command 0") -h['mdi-0'] = 1 -wait_for_joint_to_stop_at(0, -1); -wait_for_joint_to_stop_at(1, 0); -wait_for_joint_to_stop_at(2, 0); -h['mdi-0'] = 0 -wait_for_task_mode(linuxcnc.MODE_MANUAL) -wait_for_halui_mode('is-manual') +mdi_then_manual(0, -1, 0, 0) -log("setting mode to Auto") +log("asking for Auto mode, which only sets this process's view") c.mode(linuxcnc.MODE_AUTO) -wait_for_halui_mode('is-auto') -log("running MDI command 1") -h['mdi-1'] = 1 -wait_for_joint_to_stop_at(0, 1); -wait_for_joint_to_stop_at(1, 0); -wait_for_joint_to_stop_at(2, 0); -h['mdi-1'] = 0 +c.wait_complete() wait_for_task_mode(linuxcnc.MODE_AUTO) -wait_for_halui_mode('is-auto') +wait_for_halui_mode('is-manual') +mdi_then_manual(1, 1, 0, 0) -log("setting mode to MDI") +log("asking for MDI mode, which only sets this process's view") c.mode(linuxcnc.MODE_MDI) -wait_for_halui_mode('is-mdi') -log("running MDI command 2") -h['mdi-2'] = 1 -wait_for_joint_to_stop_at(0, 1); -wait_for_joint_to_stop_at(1, 2); -wait_for_joint_to_stop_at(2, 0); -h['mdi-2'] = 0 -s.poll() -wait_for_task_mode(linuxcnc.MODE_MDI) -wait_for_halui_mode('is-mdi') - -log("running MDI command 3") -h['mdi-3'] = 1 -wait_for_joint_to_stop_at(0, 1); -wait_for_joint_to_stop_at(1, 2); -wait_for_joint_to_stop_at(2, 3); -h['mdi-3'] = 0 -wait_for_task_mode(linuxcnc.MODE_MDI) -wait_for_halui_mode('is-mdi') - -log("running MDI command 0") -h['mdi-0'] = 1 -wait_for_joint_to_stop_at(0, -1); -wait_for_joint_to_stop_at(1, 0); -wait_for_joint_to_stop_at(2, 0); -h['mdi-0'] = 0 +c.wait_complete() wait_for_task_mode(linuxcnc.MODE_MDI) -wait_for_halui_mode('is-mdi') +wait_for_halui_mode('is-manual') +mdi_then_manual(2, 1, 2, 0) +mdi_then_manual(3, 1, 2, 3) +mdi_then_manual(0, -1, 0, 0) sys.exit(0) - diff --git a/tests/interp/g28.2/invalid-pword/test-ui.py b/tests/interp/g28.2/invalid-pword/test-ui.py index 4237a215b8c..de646780e44 100755 --- a/tests/interp/g28.2/invalid-pword/test-ui.py +++ b/tests/interp/g28.2/invalid-pword/test-ui.py @@ -59,10 +59,13 @@ def near(a, b, tol=0.001): def wait_idle(timeout=10.0): + # Task is idle once the interpreter is and motion has left the + # coordinated mode of the run for the joint or world mode it had before. t0 = time.time() while time.time() - t0 < timeout: poll() - if s.interp_state == linuxcnc.INTERP_IDLE: + if (s.interp_state == linuxcnc.INTERP_IDLE + and s.motion_mode != linuxcnc.TRAJ_MODE_COORD): return True time.sleep(0.01) return False @@ -101,7 +104,7 @@ def mode_name(m): if not wait_homed([1, 1, 1]): fail("initial home-all did not home all joints: {}".format(list(s.homed[:3]))) -# Establish a coordinated mode worth preserving. +# Establish a mode worth preserving: the one motion goes back to after a run. c.mode(linuxcnc.MODE_MDI) c.mdi("G0 X1") if not wait_idle(): diff --git a/tests/interp/m98m99/12-M99-endless-main-program/expected.motion-logger b/tests/interp/m98m99/12-M99-endless-main-program/expected.motion-logger index aebc5e1e183..6a98f7318c1 100644 --- a/tests/interp/m98m99/12-M99-endless-main-program/expected.motion-logger +++ b/tests/interp/m98m99/12-M99-endless-main-program/expected.motion-logger @@ -197,23 +197,6 @@ SPINDLE_OFF SS_ENABLE ENABLE COORD -JOG_ABORT joint=0 -JOG_ABORT joint=1 -JOG_ABORT joint=2 -JOG_ABORT joint=3 -JOG_ABORT joint=4 -JOG_ABORT joint=5 -JOG_ABORT joint=6 -JOG_ABORT joint=7 -JOG_ABORT joint=8 -JOG_ABORT joint=9 -JOG_ABORT joint=10 -JOG_ABORT joint=11 -JOG_ABORT joint=12 -JOG_ABORT joint=13 -JOG_ABORT joint=14 -JOG_ABORT joint=15 -ABORT SET_LINE x=1, y=0, z=0, a=0, b=0, c=0, u=0, v=0, w=0, id=19, motion_type=2, vel=0.666667, ini_maxvel=4, acc=1000, turn=-1 SET_LINE x=1, y=-4, z=0, a=0, b=0, c=0, u=0, v=0, w=0, id=26, motion_type=2, vel=0.666667, ini_maxvel=4, acc=1000, turn=-1 SET_LINE x=5, y=-4, z=0, a=0, b=0, c=0, u=0, v=0, w=0, id=21, motion_type=2, vel=0.666667, ini_maxvel=4, acc=1000, turn=-1 @@ -225,4 +208,5 @@ SET_LINE x=1, y=-4, z=0, a=0, b=0, c=0, u=0, v=0, w=0, id=26, motion_type=2, vel SET_LINE x=5, y=-4, z=0, a=0, b=0, c=0, u=0, v=0, w=0, id=21, motion_type=2, vel=0.666667, ini_maxvel=4, acc=1000, turn=-1 SET_SPINDLESYNC sync=0.000000, flags=0x00000000 SPINDLE_OFF +FREE DISABLE diff --git a/tests/interp_initcode/expected b/tests/interp_initcode/expected index c93f6946634..86cd5cf0511 100644 --- a/tests/interp_initcode/expected +++ b/tests/interp_initcode/expected @@ -1,5 +1,5 @@ startup gcodes (0, 800, -1, 170, 400, 200, 900, 940, 540, 430, 990, 640, -1, 970, 911, 80, -1) -set_g5x_offset (1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) +set_g5x_offset (2, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) set_g92_offset (0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) set_xy_rotation (0.0,) # interpreter: feed mode set to units per minute @@ -7,9 +7,7 @@ set feed rate 0.0 set plane 1 # interpreter: cutter radius compensation off tool_offset (0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) -set_g5x_offset (2, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) -set_g92_offset (0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) -set_xy_rotation (0.0,) +# interpreter: continuing to use same coordinate system # interpreter: retract mode set to r_plane straight_traverse (1.23, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) set feed rate 100.0 diff --git a/tests/linuxcncrsh/expected-telnet-output b/tests/linuxcncrsh/expected-telnet-output index 935b42dc147..f2ab9f7f09b 100644 --- a/tests/linuxcncrsh/expected-telnet-output +++ b/tests/linuxcncrsh/expected-telnet-output @@ -55,7 +55,7 @@ PROBE_VALUE 0 SET PROBE_CLEAR ACK ERROR OK SET PROBE NAK -ERROR Must be in MDI mode to issue MDI command +ERROR Cannot probe with zero feed rate SET PROBE_CLEAR ACK ERROR OK MODE MANUAL @@ -445,7 +445,7 @@ PROGRAM_UNITS INCH REL_ACT_POS 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 REL_CMD_POS 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 WAIT_MODE DONE -TELEOP_ENABLE OFF +TELEOP_ENABLE ON TIMEOUT 0.000000 TOOL 0 TOOL_OFFSET 0.000000 @@ -485,14 +485,14 @@ SET OPTIONAL_STOP ACK OPTIONAL_STOP ON ERROR OK OVERRIDE_LIMITS OFF -SET OVERRIDE_LIMITS NAK +SET OVERRIDE_LIMITS ACK OVERRIDE_LIMITS OFF -ERROR can't do that (EMC_JOINT_OVERRIDE_LIMITS:129) in MDI mode +ERROR OK SET STEP NAK -ERROR can't do that (EMC_TASK_PLAN_STEP:511) in MDI mode +ERROR Can't run a program: no program is open SET TASK_PLAN_INIT ACK ERROR OK -TELEOP_ENABLE OFF +TELEOP_ENABLE ON SET TELEOP_ENABLE ACK TELEOP_ENABLE OFF ERROR OK diff --git a/tests/linuxcncrsh/test.sh b/tests/linuxcncrsh/test.sh index bd4cc09c083..9a18fa57dea 100755 --- a/tests/linuxcncrsh/test.sh +++ b/tests/linuxcncrsh/test.sh @@ -91,7 +91,7 @@ function testSetOnly() { testSet estop off testSet machine on - # test if probing in manual mode fails + # probing with the manual view still runs it (as MDI); zero feed fails testSet mode manual echo get pos_offset echo get probe_tripped @@ -244,9 +244,9 @@ function testSetOnly() { testSet angular_unit_conversion deg # testSet feed_override 100 # testSet flood on # - testSetOnly jog 0 1 # - testSetOnly jog_incr 0 1 1 # - testSetOnly jog_stop 0 # + testSetOnly jog x 1 # ; world mode after MDI + testSetOnly jog_incr x 1 1 # + testSetOnly jog_stop x # testSet linear_unit_conversion mm # testSet mist on # testSet optional_stop 1 # @@ -256,12 +256,10 @@ function testSetOnly() { #testSet Open #testSet run - # Testing set override_limits results in command line message: - # can't do that (EMC_JOINT_OVERRIDE_LIMITS:129) in MDI mode testSet override_limits off # # Testing step results in a command line message: - # can't do that (EMC_TASK_PLAN_STEP:511) in MDI mode + # Can't run a program: no program is open testSetOnly step testSetOnly task_plan_init diff --git a/tests/motion-logger/basic/expected.builtin-startup.in b/tests/motion-logger/basic/expected.builtin-startup.in index 2296018b31c..0a36ebc4e40 100644 --- a/tests/motion-logger/basic/expected.builtin-startup.in +++ b/tests/motion-logger/basic/expected.builtin-startup.in @@ -204,25 +204,6 @@ SS_ENABLE ENABLE # -# The test UI finally switches mode to Auto, which switches Motion to Coord -# and aborts. +# The test UI then asks for Auto mode. That sets only the test UI's own +# view; nothing goes to Task or Motion. # - -COORD -JOG_ABORT joint=0 -JOG_ABORT joint=1 -JOG_ABORT joint=2 -JOG_ABORT joint=3 -JOG_ABORT joint=4 -JOG_ABORT joint=5 -JOG_ABORT joint=6 -JOG_ABORT joint=7 -JOG_ABORT joint=8 -JOG_ABORT joint=9 -JOG_ABORT joint=10 -JOG_ABORT joint=11 -JOG_ABORT joint=12 -JOG_ABORT joint=13 -JOG_ABORT joint=14 -JOG_ABORT joint=15 -ABORT diff --git a/tests/motion-logger/basic/expected.g0 b/tests/motion-logger/basic/expected.g0 index aad80163311..cc271eebade 100644 --- a/tests/motion-logger/basic/expected.g0 +++ b/tests/motion-logger/basic/expected.g0 @@ -1,4 +1,6 @@ +COORD SET_LINE x=1, y=2, z=3, a=4, b=5, c=6, u=7, v=8, w=9, id=2, motion_type=1, vel=1.66296, ini_maxvel=1.66296, acc=415.74, turn=-1 SET_LINE x=0.1, y=0.2, z=0.3, a=0.4, b=0.5, c=0.6, u=0.7, v=0.8, w=0.9, id=4, motion_type=1, vel=1.66296, ini_maxvel=1.66296, acc=415.74, turn=-1 SET_SPINDLESYNC sync=0.000000, flags=0x00000000 SPINDLE_OFF +FREE diff --git a/tests/motion-logger/basic/expected.g1 b/tests/motion-logger/basic/expected.g1 index d2c3bffbad6..bd250d5d9b5 100644 --- a/tests/motion-logger/basic/expected.g1 +++ b/tests/motion-logger/basic/expected.g1 @@ -1,5 +1,7 @@ +COORD SET_LINE x=1, y=2, z=3, a=4, b=5, c=6, u=7, v=8, w=9, id=2, motion_type=2, vel=0.0166667, ini_maxvel=1.66296, acc=415.74, turn=-1 SET_LINE x=0.1, y=2, z=0.3, a=0.4, b=5, c=0.6, u=0.7, v=8, w=0.9, id=3, motion_type=2, vel=0.0333333, ini_maxvel=1.40546, acc=351.364, turn=-1 SET_LINE x=10, y=2, z=0.3, a=10, b=5, c=0.6, u=10, v=8, w=0.9, id=5, motion_type=2, vel=0.00166667, ini_maxvel=4, acc=1000, turn=-1 SET_SPINDLESYNC sync=0.000000, flags=0x00000000 SPINDLE_OFF +FREE diff --git a/tests/motion-logger/basic/expected.reset b/tests/motion-logger/basic/expected.reset index 2a358b4b4f8..70687f3e8d3 100644 --- a/tests/motion-logger/basic/expected.reset +++ b/tests/motion-logger/basic/expected.reset @@ -1,3 +1,5 @@ +COORD SET_OFFSET x=0, y=0, z=0, a=0, b=0, c=0 u=0, v=0, w=0 SET_SPINDLESYNC sync=0.000000, flags=0x00000000 SPINDLE_OFF +FREE diff --git a/tests/motion-logger/basic/expected.s b/tests/motion-logger/basic/expected.s index c4216ad2293..fd0fd722768 100644 --- a/tests/motion-logger/basic/expected.s +++ b/tests/motion-logger/basic/expected.s @@ -1,3 +1,4 @@ +COORD SET_LINE x=1, y=0, z=0, a=0, b=0, c=0, u=0, v=0, w=0, id=2, motion_type=1, vel=4, ini_maxvel=4, acc=1000, turn=-1 SPINDLE_ON speed=0.000000, css_factor=0.000000, xoffset=0.000000 SET_LINE x=1.5, y=0, z=0, a=0, b=0, c=0, u=0, v=0, w=0, id=6, motion_type=1, vel=4, ini_maxvel=4, acc=1000, turn=-1 @@ -13,3 +14,4 @@ SPINDLE_ON speed=0.000000, css_factor=0.000000, xoffset=0.000000 SET_LINE x=5, y=0, z=0, a=0, b=0, c=0, u=0, v=0, w=0, id=26, motion_type=1, vel=4, ini_maxvel=4, acc=1000, turn=-1 SET_SPINDLESYNC sync=0.000000, flags=0x00000000 SPINDLE_OFF +FREE diff --git a/tests/motion-logger/mountaindew/expected.motion-logger b/tests/motion-logger/mountaindew/expected.motion-logger index c52ea9598ed..132f381701b 100644 --- a/tests/motion-logger/mountaindew/expected.motion-logger +++ b/tests/motion-logger/mountaindew/expected.motion-logger @@ -101,23 +101,6 @@ SPINDLE_OFF SS_ENABLE ENABLE COORD -JOG_ABORT joint=0 -JOG_ABORT joint=1 -JOG_ABORT joint=2 -JOG_ABORT joint=3 -JOG_ABORT joint=4 -JOG_ABORT joint=5 -JOG_ABORT joint=6 -JOG_ABORT joint=7 -JOG_ABORT joint=8 -JOG_ABORT joint=9 -JOG_ABORT joint=10 -JOG_ABORT joint=11 -JOG_ABORT joint=12 -JOG_ABORT joint=13 -JOG_ABORT joint=14 -JOG_ABORT joint=15 -ABORT SET_LINE x=2, y=0, z=0, a=0, b=0, c=0, u=0, v=0, w=0, id=4, motion_type=2, vel=0.666667, ini_maxvel=400, acc=1000, turn=-1 SET_LINE x=3, y=0, z=0, a=0, b=0, c=0, u=0, v=0, w=0, id=5, motion_type=2, vel=0.666667, ini_maxvel=400, acc=1000, turn=-1 SET_LINE x=3, y=4, z=0, a=0, b=0, c=0, u=0, v=0, w=0, id=6, motion_type=2, vel=0.666667, ini_maxvel=400, acc=1000, turn=-1 @@ -130,4 +113,5 @@ SET_LINE x=0, y=1, z=0.5, a=0, b=0, c=0, u=0, v=0, w=0, id=5, motion_type=1, vel SET_LINE x=0, y=0, z=0.5, a=0, b=0, c=0, u=0, v=0, w=0, id=6, motion_type=1, vel=400, ini_maxvel=400, acc=1000, turn=-1 SET_SPINDLESYNC sync=0.000000, flags=0x00000000 SPINDLE_OFF +FREE DISABLE diff --git a/tests/task-modeless/.gitignore b/tests/task-modeless/.gitignore new file mode 100644 index 00000000000..57585c75340 --- /dev/null +++ b/tests/task-modeless/.gitignore @@ -0,0 +1,2 @@ +sim.var +sim.var.bak diff --git a/tests/task-modeless/checkresult b/tests/task-modeless/checkresult new file mode 100755 index 00000000000..24dc9aa53e3 --- /dev/null +++ b/tests/task-modeless/checkresult @@ -0,0 +1,2 @@ +#!/bin/sh +exit 0 # test failure is indicated by test.sh exit value diff --git a/tests/task-modeless/program.ngc b/tests/task-modeless/program.ngc new file mode 100644 index 00000000000..cd7c1b0f097 --- /dev/null +++ b/tests/task-modeless/program.ngc @@ -0,0 +1,4 @@ +G0 X2 +G4 P1.5 +G0 X4 +M2 diff --git a/tests/task-modeless/sim.hal b/tests/task-modeless/sim.hal new file mode 100644 index 00000000000..d5d3ef1538b --- /dev/null +++ b/tests/task-modeless/sim.hal @@ -0,0 +1,16 @@ +loadrt [KINS]KINEMATICS +loadrt [EMCMOT]EMCMOT 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 + +# a wheel on X: one count is 0.01 +setp axis.x.jog-scale 0.01 +setp axis.x.jog-vel-mode 0 diff --git a/tests/task-modeless/test-ui.py b/tests/task-modeless/test-ui.py new file mode 100755 index 00000000000..ccda010040c --- /dev/null +++ b/tests/task-modeless/test-ui.py @@ -0,0 +1,240 @@ +#!/usr/bin/env python3 +# The task mode cannot be set: it reports what task runs, and task accepts +# jogs, MDI and program runs by what it is doing. Nothing here calls +# c.mode() except to check what it does: it sets this process's view, which +# stat.task_mode reports while task is idle. halui's mode pins show task's +# own mode. + +import os +import sys +import time + +import hal +import linuxcnc + +c = linuxcnc.command() +s = linuxcnc.stat() +e = linuxcnc.error_channel() +h = hal.component("test-ui") +h.ready() + +fails = 0 + + +def check(name, ok, detail=''): + global fails + print('%s: %s %s' % ('ok' if ok else 'FAIL', name, detail), flush=True) + if not ok: + fails += 1 + + +def wait(fn, timeout=5.0): + end = time.time() + timeout + while time.time() < end: + s.poll() + if fn(): + return True + time.sleep(0.01) + s.poll() + return fn() + + +def errors(): + msgs = [] + while True: + m = e.poll() + if not m: + return msgs + msgs.append(m[1]) + + +def idle(): + return (s.interp_state == linuxcnc.INTERP_IDLE and s.queue == 0 + and hal.get_value('halui.mode.is-manual')) + + +def x(): + return s.actual_position[0] + + +MODE = {linuxcnc.MODE_MANUAL: 'MANUAL', linuxcnc.MODE_MDI: 'MDI', linuxcnc.MODE_AUTO: 'AUTO'} +TRAJ = {linuxcnc.TRAJ_MODE_FREE: 'FREE', linuxcnc.TRAJ_MODE_TELEOP: 'TELEOP', + linuxcnc.TRAJ_MODE_COORD: 'COORD'} + + +def modes(): + return '%s/%s' % (MODE.get(s.task_mode), TRAJ.get(s.motion_mode)) + + +wait(lambda: s.task_mode in MODE and s.motion_mode in TRAJ, 10.0) +check('starts idle', s.task_mode == linuxcnc.MODE_MANUAL and s.motion_mode == linuxcnc.TRAJ_MODE_FREE, modes()) + +c.state(linuxcnc.STATE_ESTOP_RESET) +c.state(linuxcnc.STATE_ON) +c.wait_complete() + +# --- before homing: MDI is refused, joint jogs work +errors() +c.mdi('G0 X1') +c.wait_complete() +time.sleep(0.1) +msgs = errors() +check('MDI refused before homing', any('not homed' in m for m in msgs), msgs) +check('still idle in joint mode', wait(lambda: idle() and s.motion_mode == linuxcnc.TRAJ_MODE_FREE), modes()) + +c.jog(linuxcnc.JOG_INCREMENT, True, 1, 10, 0.5) +check('joint jog without a mode change', wait(lambda: abs(s.joint_actual_position[1] - 0.5) < 1e-6), s.joint_actual_position[1]) + +c.home(-1) +c.wait_complete() +check('homed', wait(lambda: all(s.homed[:3])), s.homed[:3]) +c.teleop_enable(1) +c.wait_complete() +check('world mode', wait(lambda: s.motion_mode == linuxcnc.TRAJ_MODE_TELEOP), modes()) + +# --- no program open: run and step are refused +errors() +c.auto(linuxcnc.AUTO_STEP) +c.wait_complete() +time.sleep(0.1) +msgs = errors() +check('step refused with no program', any('no program is open' in m for m in msgs), msgs) +check('still idle after the refused step', wait(idle), modes()) + +# --- MDI from idle, no mode change +c.mdi('G0 X1') +check('MDI shows as MDI mode', wait(lambda: s.task_mode == linuxcnc.MODE_MDI, 1.0), modes()) +check('MDI runs in coordinated mode', wait(lambda: s.motion_mode == linuxcnc.TRAJ_MODE_COORD, 1.0), modes()) +check('MDI moved X', wait(lambda: abs(x() - 1) < 1e-6), x()) +check('idle again after MDI', wait(idle), modes()) +check('back in world mode', wait(lambda: s.motion_mode == linuxcnc.TRAJ_MODE_TELEOP), modes()) +check('halui sees manual', wait(lambda: hal.get_value('halui.mode.is-manual'))) +check('no errors from MDI', not errors()) + +# --- wheel jog while idle after MDI +hal.set_p('axis.x.jog-enable', '1') +hal.set_p('axis.x.jog-counts', '100') +check('wheel jog after MDI', wait(lambda: abs(x() - 2) < 1e-6), x()) + +# --- a world jog right after MDI, with no mode change +c.jog(linuxcnc.JOG_INCREMENT, False, 0, 10, 0.5) +check('world jog after MDI', wait(lambda: abs(x() - 2.5) < 1e-6), x()) + +# --- mode() sets this process's view only +c.mode(linuxcnc.MODE_AUTO) +c.wait_complete() +time.sleep(0.1) +s.poll() +check('mode(AUTO) shows as the view', s.task_mode == linuxcnc.MODE_AUTO, modes()) +check('mode(AUTO) leaves task idle', hal.get_value('halui.mode.is-manual') and s.motion_mode == linuxcnc.TRAJ_MODE_TELEOP, modes()) +c.mode(linuxcnc.MODE_MDI) +c.wait_complete() +time.sleep(0.1) +s.poll() +check('mode(MDI) shows as the view', s.task_mode == linuxcnc.MODE_MDI, modes()) +check('mode(MDI) leaves task idle', hal.get_value('halui.mode.is-manual') and s.motion_mode == linuxcnc.TRAJ_MODE_TELEOP, modes()) +c.jog(linuxcnc.JOG_INCREMENT, False, 0, 10, 0.5) +check('world jog with the MDI view', wait(lambda: abs(x() - 3) < 1e-6), x()) +c.mode(linuxcnc.MODE_MANUAL) +s.poll() +check('mode(MANUAL) view', s.task_mode == linuxcnc.MODE_MANUAL, modes()) +check('no errors from mode()', not errors()) + +# --- queued MDI; jogs are refused while it runs +c.mdi('G4 P1') +c.mdi('G0 X3.5') +check('MDI queue runs', wait(lambda: s.task_mode == linuxcnc.MODE_MDI, 1.0), modes()) +check('halui sees MDI', wait(lambda: hal.get_value('halui.mode.is-mdi'), 1.0)) +y = s.actual_position[1] +c.jog(linuxcnc.JOG_INCREMENT, False, 1, 10, 0.5) +c.wait_complete() +time.sleep(0.1) +msgs = errors() +check('jog refused while MDI runs', any('while MDI is running' in m for m in msgs), msgs) +c.mode(linuxcnc.MODE_MANUAL) +c.wait_complete() +check('mode(MANUAL) does not stop MDI: queued MDI finished', wait(lambda: abs(x() - 3.5) < 1e-6, 4.0), x()) +check('idle after the MDI queue', wait(idle), modes()) +check('Y did not move', abs(s.actual_position[1] - y) < 1e-6, (s.actual_position[1], y)) + +# --- a jog in progress holds off MDI +c.jog(linuxcnc.JOG_CONTINUOUS, False, 1, 1) +wait(lambda: s.current_vel > 0.5, 1.0) +c.mdi('G0 X0') +c.wait_complete() +time.sleep(0.1) +msgs = errors() +check('MDI refused while jogging', any('while jogging' in m for m in msgs), msgs) +c.jog(linuxcnc.JOG_STOP, False, 1) +check('jog stopped, idle', wait(lambda: idle() and s.current_vel == 0), modes()) + +# --- a program run from idle, no mode change +c.program_open(os.path.abspath('program.ngc')) +c.wait_complete() +c.auto(linuxcnc.AUTO_RUN, 0) +check('program shows as AUTO mode', wait(lambda: s.task_mode == linuxcnc.MODE_AUTO, 1.0), modes()) +check('halui sees auto', wait(lambda: hal.get_value('halui.mode.is-auto'), 1.0)) +check('program reached the dwell', wait(lambda: abs(x() - 2) < 1e-6), x()) +c.mode(linuxcnc.MODE_MANUAL) +c.mdi('G0 X0') +c.jog(linuxcnc.JOG_INCREMENT, False, 1, 10, 0.5) +c.wait_complete() +time.sleep(0.1) +msgs = errors() +s.poll() +check('mode(MANUAL) leaves the program running', s.task_mode == linuxcnc.MODE_AUTO and hal.get_value('halui.mode.is-auto'), modes()) +check('MDI refused while the program runs', any('EMC_TASK_PLAN_EXECUTE' in m for m in msgs), msgs) +check('jog refused while the program runs', any('EMC_JOG_INCR' in m for m in msgs), msgs) +check('program finished', wait(lambda: abs(x() - 4) < 1e-6, 5.0), x()) +check('idle after the program', wait(idle), modes()) +check('world mode after the program', wait(lambda: s.motion_mode == linuxcnc.TRAJ_MODE_TELEOP), modes()) + +# --- abort a paused program +c.auto(linuxcnc.AUTO_RUN, 0) +wait(lambda: abs(x() - 2) < 1e-6) +c.auto(linuxcnc.AUTO_PAUSE) +check('paused program is AUTO', wait(lambda: s.paused and s.task_mode == linuxcnc.MODE_AUTO), modes()) +c.abort() +c.wait_complete() +check('abort ends the run', wait(idle), modes()) +errors() + +# --- joint mode is kept across a run +c.teleop_enable(0) +c.wait_complete() +wait(lambda: s.motion_mode == linuxcnc.TRAJ_MODE_FREE) +c.mdi('G0 X1') +check('MDI from joint mode', wait(lambda: abs(x() - 1) < 1e-6), x()) +check('back in joint mode', wait(lambda: idle() and s.motion_mode == linuxcnc.TRAJ_MODE_FREE), modes()) +c.teleop_enable(1) +c.wait_complete() + +# --- halui MDI command +hal.set_p('halui.mdi-command-00', '1') +check('halui MDI runs', wait(lambda: abs(x()) < 1e-6), x()) +check('idle after halui MDI', wait(idle), modes()) +check('halui-mdi-is-running cleared', wait(lambda: not hal.get_value('halui.halui-mdi-is-running'))) +hal.set_p('halui.mdi-command-00', '0') + +# --- the view comes back once a run ends +c.mode(linuxcnc.MODE_MDI) +c.mdi('G0 X0.5') +check('MDI from the MDI view', wait(lambda: abs(x() - 0.5) < 1e-6), x()) +check('idle again, MDI view kept', wait(lambda: hal.get_value('halui.mode.is-manual') and s.interp_state == linuxcnc.INTERP_IDLE) + and s.task_mode == linuxcnc.MODE_MDI, modes()) +c.mode(linuxcnc.MODE_MANUAL) + +# --- step from idle starts the program paused +c.auto(linuxcnc.AUTO_STEP) +check('step starts the program', wait(lambda: s.task_mode == linuxcnc.MODE_AUTO and s.paused), modes()) +c.abort() +c.wait_complete() +check('abort after step', wait(idle), modes()) + +msgs = errors() +check('no unexpected errors', not msgs, msgs) + +c.state(linuxcnc.STATE_OFF) +c.wait_complete() +print('%d failures' % fails, flush=True) +sys.exit(1 if fails else 0) diff --git a/tests/task-modeless/test.ini b/tests/task-modeless/test.ini new file mode 100644 index 00000000000..dcf9e92b986 --- /dev/null +++ b/tests/task-modeless/test.ini @@ -0,0 +1,85 @@ +[EMC] +VERSION = 1.1 +DEBUG = 0 + +[DISPLAY] +DISPLAY = ./test-ui.py + +[RS274NGC] +PARAMETER_FILE = sim.var + +[EMCMOT] +EMCMOT = motmod +COMM_TIMEOUT = 4.0 +SERVO_PERIOD = 1000000 + +[TASK] +TASK = milltask +CYCLE_TIME = 0.001 + +[HAL] +HALFILE = sim.hal + +[HALUI] +MDI_COMMAND = G0 X0 + +[TRAJ] +COORDINATES = X Y Z +LINEAR_UNITS = mm +ANGULAR_UNITS = degree +MAX_LINEAR_VELOCITY = 40 + +[EMCIO] +TOOL_TABLE = tool.tbl + +[KINS] +KINEMATICS = trivkins +JOINTS = 3 + +[AXIS_X] +MIN_LIMIT = -100.0 +MAX_LIMIT = 100.0 +MAX_VELOCITY = 40 +MAX_ACCELERATION = 1000.0 + +[JOINT_0] +TYPE = LINEAR +HOME_SEQUENCE = 0 +MAX_VELOCITY = 40 +MAX_ACCELERATION = 1000.0 +MIN_LIMIT = -100.0 +MAX_LIMIT = 100.0 +FERROR = 1 +MIN_FERROR = 1 + +[AXIS_Y] +MIN_LIMIT = -100.0 +MAX_LIMIT = 100.0 +MAX_VELOCITY = 40 +MAX_ACCELERATION = 1000.0 + +[JOINT_1] +TYPE = LINEAR +HOME_SEQUENCE = 0 +MAX_VELOCITY = 40 +MAX_ACCELERATION = 1000.0 +MIN_LIMIT = -100.0 +MAX_LIMIT = 100.0 +FERROR = 1 +MIN_FERROR = 1 + +[AXIS_Z] +MIN_LIMIT = -100.0 +MAX_LIMIT = 100.0 +MAX_VELOCITY = 40 +MAX_ACCELERATION = 1000.0 + +[JOINT_2] +TYPE = LINEAR +HOME_SEQUENCE = 0 +MAX_VELOCITY = 40 +MAX_ACCELERATION = 1000.0 +MIN_LIMIT = -100.0 +MAX_LIMIT = 100.0 +FERROR = 1 +MIN_FERROR = 1 diff --git a/tests/task-modeless/test.sh b/tests/task-modeless/test.sh new file mode 100755 index 00000000000..972cf4ffcb8 --- /dev/null +++ b/tests/task-modeless/test.sh @@ -0,0 +1,3 @@ +#!/bin/bash +rm -f sim.var +linuxcnc -r test.ini diff --git a/tests/task-modeless/tool.tbl b/tests/task-modeless/tool.tbl new file mode 100644 index 00000000000..aee1343f663 --- /dev/null +++ b/tests/task-modeless/tool.tbl @@ -0,0 +1 @@ +T1 P1 Z0.5 ;tool 1 From eddbbb3d37866e0150348ed8bd31063485bb9c2f Mon Sep 17 00:00:00 2001 From: Rene Hopf Date: Fri, 16 Oct 2026 19:32:11 +0200 Subject: [PATCH 14/21] task: one list of immediate commands for the planner tables The planner's tables repeated the commands every state passes straight to emcTaskIssueCommand(): 21 accepted in any state, 12 more once the machine is on, the spindle group unless a program moves, the plan and I/O group unless a program runs. isImmediate() now says this once, by what task is doing, and each table keeps only what is special to it. READING and WAITING share a table, the queued tool commands a helper. No change in behaviour: every state accepts the same commands as before. --- src/emc/task/emctaskmain.cc | 636 +++++++++++------------------------- 1 file changed, 196 insertions(+), 440 deletions(-) diff --git a/src/emc/task/emctaskmain.cc b/src/emc/task/emctaskmain.cc index 8cdb22d43a8..7bf1c851aff 100644 --- a/src/emc/task/emctaskmain.cc +++ b/src/emc/task/emctaskmain.cc @@ -886,10 +886,129 @@ static void taskRunCheckDone() taskRunEnd(); } +/* + isImmediate() + + The commands emcTaskPlan() passes straight to emcTaskIssueCommand(), by + what task is doing. Everything else is handled, or refused, by the table + for the state task is in. + */ +static bool isImmediate(NMLTYPE type) +{ + const bool on = emcStatus->task.state == EMC_TASK_STATE::ON; + const bool program = on && taskRun == TaskRun::PROGRAM; + + switch (type) { + // in any state + 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_TASK_SET_STATE_TYPE: + case EMC_TASK_ABORT_TYPE: + case EMC_TASK_PLAN_SET_OPTIONAL_STOP_TYPE: + case EMC_TASK_PLAN_SET_BLOCK_DELETE_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: + return true; + + // only while the machine is off or in E-stop + case EMC_JOINT_LOAD_COMP_TYPE: + case EMC_TRAJ_SET_VELOCITY_TYPE: + case EMC_TRAJ_SET_ACCELERATION_TYPE: + return !on; + + // once the machine is on, whatever runs + 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_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_OPTIONAL_STOP_TYPE: + return on; + + // once the machine is on, unless a program runs and is not paused + 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: + return on && (!program || emcStatus->task.interpState == EMC_TASK_INTERP::PAUSED); + + // unless a program runs + case EMC_TASK_PLAN_INIT_TYPE: + case EMC_TASK_PLAN_OPEN_TYPE: + case EMC_TASK_PLAN_CLOSE_TYPE: + case EMC_TASK_PLAN_SYNCH_TYPE: + case EMC_MOTION_SET_DOUT_TYPE: + case EMC_MOTION_SET_AOUT_TYPE: + case EMC_MOTION_ADAPTIVE_TYPE: + return !program; + + // unless a program or MDI runs + case EMC_TRAJ_SET_TELEOP_ENABLE_TYPE: + return !on || taskRun == TaskRun::NONE; + } + return false; +} + +// The tool commands go through interp_list: no more reading until they +// are done, then the interpreter synchs. +static void queueToolCommand(NMLmsg *cmd) +{ + switch (cmd->_type) { + case EMC_TOOL_LOAD_TOOL_TABLE_TYPE: + emcTaskQueueCommand(std::make_unique(*static_cast(cmd))); + break; + case EMC_TOOL_SET_OFFSET_TYPE: + emcTaskQueueCommand(std::make_unique(*static_cast(cmd))); + break; + case EMC_TOOL_SET_NUMBER_TYPE: + emcTaskQueueCommand(std::make_unique(*static_cast(cmd))); + break; + } + // signify no more reading + emcTaskPlanSetWait(); + // then resynch interpreter + emcTaskQueueTaskPlanSynchCmd(); +} + +// Start a run from idle with cmd, see taskRunStart(). +static int taskRunIssue(TaskRun run, NMLmsg *cmd) +{ + int retval = taskRunStart(run); + if (retval == 0) { + retval = emcTaskIssueCommand(cmd); + if (retval != 0) { + taskRunEnd(); + } + } + return retval; +} + /* emcTaskPlan() - Planner for NC code or manual mode operations + Planner for NC code or manual operations */ static int emcTaskPlan(void) { @@ -918,304 +1037,113 @@ static int emcTaskPlan(void) taskRunCheckDone(); - // handle any new command + // handle any new command: no command, the immediate ones (isImmediate()), + // then what is special to the state task is in switch (emcStatus->task.state) { case EMC_TASK_STATE::OFF: case EMC_TASK_STATE::ESTOP: case EMC_TASK_STATE::ESTOP_RESET: + switch (type) { + case 0: + case EMC_NULL_TYPE: + break; - // 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_SET_FERROR_TYPE: - case EMC_JOINT_SET_MIN_FERROR_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_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: + // one case where nothing may be running + case EMC_JOINT_OVERRIDE_LIMITS_TYPE: + retval = 0; + if (taskRun == TaskRun::NONE) { retval = emcTaskIssueCommand(emcCommand); - break; - - // one case where nothing may be running - case EMC_JOINT_OVERRIDE_LIMITS_TYPE: - retval = 0; - if (taskRun == TaskRun::NONE) { - retval = emcTaskIssueCommand(emcCommand); - } - break; - - case EMC_TOOL_LOAD_TOOL_TABLE_TYPE: { - // send to IO - emcTaskQueueCommand(std::make_unique(*static_cast(emcCommand))); - // signify no more reading - emcTaskPlanSetWait(); - // then resynch interpreter - emcTaskQueueTaskPlanSynchCmd(); - break; - } - case EMC_TOOL_SET_OFFSET_TYPE: { - // send to IO - emcTaskQueueCommand(std::make_unique(*static_cast(emcCommand))); - // signify no more reading - emcTaskPlanSetWait(); - // then resynch interpreter - emcTaskQueueTaskPlanSynchCmd(); - break; } + break; - case EMC_TOOL_SET_NUMBER_TYPE: { - // send to IO - emcTaskQueueCommand(std::make_unique(*static_cast(emcCommand))); - // signify no more reading - emcTaskPlanSetWait(); - // then resynch interpreter - emcTaskQueueTaskPlanSynchCmd(); - break; - } + case EMC_TOOL_LOAD_TOOL_TABLE_TYPE: + case EMC_TOOL_SET_OFFSET_TYPE: + case EMC_TOOL_SET_NUMBER_TYPE: + queueToolCommand(emcCommand); + break; - default: - emcOperatorError(_("command (%s) cannot be executed until the machine is out of E-stop and turned on"), emc_symbol_lookup(type)); - retval = -1; + default: + if (isImmediate(type)) { + retval = emcTaskIssueCommand(emcCommand); break; - - } // switch (type) - + } + emcOperatorError(_("command (%s) cannot be executed until the machine is out of E-stop and turned on"), emc_symbol_lookup(type)); + retval = -1; + break; + } 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 what task is running */ switch (taskRun) { case TaskRun::NONE: // ON, 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: + // jogging and homing 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_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_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_PAUSE_TYPE: - case EMC_TASK_PLAN_REVERSE_TYPE: - case EMC_TASK_PLAN_FORWARD_TYPE: - case EMC_TASK_PLAN_RESUME_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; // commands that start a run - case EMC_TASK_PLAN_EXECUTE_TYPE: - retval = taskRunStart(TaskRun::MDI); - if (retval == 0) { - retval = emcTaskIssueCommand(emcCommand); - if (retval != 0) { - taskRunEnd(); - } - } + retval = taskRunIssue(TaskRun::MDI, emcCommand); break; case EMC_TASK_PLAN_RUN_TYPE: - retval = taskRunStart(TaskRun::PROGRAM); - if (retval == 0) { - retval = emcTaskIssueCommand(emcCommand); - if (retval != 0) { - taskRunEnd(); - } - } + retval = taskRunIssue(TaskRun::PROGRAM, emcCommand); break; case EMC_TASK_PLAN_STEP_TYPE: // handles case where first action is to step the program - retval = taskRunStart(TaskRun::PROGRAM); - if (retval != 0) break; 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) { - taskRunEnd(); - break; - } + retval = taskRunIssue(TaskRun::PROGRAM, &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; - // queued commands - - case EMC_TOOL_LOAD_TOOL_TABLE_TYPE: { - // send to IO - emcTaskQueueCommand(std::make_unique(*static_cast(emcCommand))); - // signify no more reading - emcTaskPlanSetWait(); - // then resynch interpreter - emcTaskQueueTaskPlanSynchCmd(); + case EMC_TOOL_LOAD_TOOL_TABLE_TYPE: + case EMC_TOOL_SET_OFFSET_TYPE: + case EMC_TOOL_SET_NUMBER_TYPE: + queueToolCommand(emcCommand); break; - } - case EMC_TOOL_SET_OFFSET_TYPE: { - // send to IO - emcTaskQueueCommand(std::make_unique(*static_cast(emcCommand))); - // signify no more reading - emcTaskPlanSetWait(); - // then resynch interpreter - emcTaskQueueTaskPlanSynchCmd(); - break; - } - - case EMC_TOOL_SET_NUMBER_TYPE: { - // send to IO - emcTaskQueueCommand(std::make_unique(*static_cast(emcCommand))); - // signify no more reading - emcTaskPlanSetWait(); - // then resynch interpreter - emcTaskQueueTaskPlanSynchCmd(); - break; - } - // otherwise we can't handle it default: + if (isImmediate(type)) { + retval = emcTaskIssueCommand(emcCommand); + break; + } emcOperatorError(_("can't do that (%s:%d) while idle"), emc_symbol_lookup(type),(int) type); retval = -1; break; - - } // switch (type) in ON, idle - + } break; // case TaskRun::NONE case TaskRun::PROGRAM: // ON, program running switch (emcStatus->task.interpState) { case EMC_TASK_INTERP::READING: // ON, program, READING + case EMC_TASK_INTERP::WAITING: // ON, program, WAITING: interpreter ran to end + { + const bool reading = emcStatus->task.interpState == EMC_TASK_INTERP::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_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_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: - retval = emcTaskIssueCommand(emcCommand); - return retval; break; case EMC_TASK_PLAN_STEP_TYPE: @@ -1224,69 +1152,34 @@ static int emcTaskPlan(void) steppingWait = 0; // clear the wait break; - // otherwise we can't handle it default: - emcOperatorError(_("can't do that (%s) while a program runs, with the interpreter reading"), emc_symbol_lookup(type)); + if (isImmediate(type)) { + retval = emcTaskIssueCommand(emcCommand); + if (reading) { + // no readahead in this cycle + return retval; + } + break; + } + emcOperatorError(_("can't do that (%s) while a program runs, with the interpreter %s"), emc_symbol_lookup(type), + reading ? "reading" : "waiting"); retval = -1; break; + } - } // switch (type) in ON, program, READING - - // handle interp readahead logic - readahead_reading(); - - break; // EMC_TASK_INTERP::READING + // handle interp readahead logic + if (reading) { + readahead_reading(); + } else { + readahead_waiting(); + } + break; // EMC_TASK_INTERP::READING, WAITING + } case EMC_TASK_INTERP::PAUSED: // ON, program, 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_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_TASK_SET_STATE_TYPE: - case EMC_TASK_ABORT_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: @@ -1303,148 +1196,28 @@ static int emcTaskPlan(void) emcStatus->task.task_paused = 1; break; - // otherwise we can't handle it default: + if (isImmediate(type)) { + retval = emcTaskIssueCommand(emcCommand); + break; + } emcOperatorError(_("can't do that (%s) while a program runs, with the interpreter paused"), emc_symbol_lookup(type)); retval = -1; break; - - } // switch (type) in ON, program, 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_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_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: - retval = emcTaskIssueCommand(emcCommand); - break; - - case EMC_TASK_PLAN_STEP_TYPE: - emcStatus->motion.traj.single_stepping = 1; - stepping = 1; // set stepping mode in case it's not - steppingWait = 0; // clear the wait - break; - - // otherwise we can't handle it - default: - emcOperatorError(_("can't do that (%s) while a program runs, with the interpreter waiting"), emc_symbol_lookup(type)); - retval = -1; - break; - - } // switch (type) in ON, program, WAITING - - // handle interp readahead logic - readahead_waiting(); - - break; // end of case EMC_TASK_INTERP::WAITING - case EMC_TASK_INTERP::IDLE: // aborted in this cycle, taskRunCheckDone() ends the run in // the next one break; - - } // switch (interpState) in ON, program - + } break; // case TaskRun::PROGRAM case TaskRun::MDI: // ON, MDI running 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_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: @@ -1469,45 +1242,28 @@ static int emcTaskPlan(void) } break; - case EMC_TOOL_LOAD_TOOL_TABLE_TYPE: { - // send to IO - emcTaskQueueCommand(std::make_unique(*static_cast(emcCommand))); - // signify no more reading - emcTaskPlanSetWait(); - // then resynch interpreter - emcTaskQueueTaskPlanSynchCmd(); - break; - } - case EMC_TOOL_SET_OFFSET_TYPE: { - // send to IO - emcTaskQueueCommand(std::make_unique(*static_cast(emcCommand))); - // signify no more reading - emcTaskPlanSetWait(); - // then resynch interpreter - emcTaskQueueTaskPlanSynchCmd(); + case EMC_TOOL_LOAD_TOOL_TABLE_TYPE: + case EMC_TOOL_SET_OFFSET_TYPE: + queueToolCommand(emcCommand); break; - } - // otherwise we can't handle it default: + if (isImmediate(type)) { + retval = emcTaskIssueCommand(emcCommand); + break; + } emcOperatorError(_("can't do that (%s) while MDI is running"), emc_symbol_lookup(type)); - retval = -1; break; - - } // switch (type) in ON, MDI running + } mdi_execute_hook(); - break; // case TaskRun::MDI - - } // switch (taskRun) - + } break; // case EMC_TASK_STATE::ON default: break; - - } // switch (task.state) + } return retval; } From 3468df24479ae271c28eb5744e6d30a0ac2ba2fa Mon Sep 17 00:00:00 2001 From: Rene Hopf Date: Fri, 16 Oct 2026 20:57:03 +0200 Subject: [PATCH 15/21] jog while paused, and return to the paused position on resume Axes can be jogged (keyboard, AXIS, halui, linuxcncrsh, wheel) while a program or MDI command is paused, M0/M1 included, once the pause has stopped the motion. Joints cannot. Motion keeps the paused program position and adds a per-axis pause offset on top of it, as the external offsets are added (axis_pause_*() in axis.c), within the soft limits. The queued moves and the interpreter are untouched. On resume or step, do_pause_resume() (control.c): - puts the spindles back as they were at the pause (state, direction, speed, CSS) and waits for them to be at speed; - returns the axes: the ones not in [TRAJ]PAUSE_RETURN_LAST (default Z) together in a straight line, then those, at the axis limits, and sets the offsets to exactly zero; - then resumes or steps. Task restores mist and flood. Pausing during the return stops it there. An abort keeps the machine where it was jogged to: the planner takes the offsets into its position. Reverse run is refused while jogged away. Status: pause_offset, pause_jog_ok and pause_returning in EMC_MOTION_STAT and Python. Task accepts axis jogs while paused, halui and linuxcncrsh send them, AXIS enables its jog and spindle controls (not homing). Tests: new tests/jog-while-paused; motion-logger expectations gain the SET_PAUSE_RETURN_LAST startup command. --- docs/src/config/ini-config.adoc | 3 + docs/src/config/python-interface.adoc | 14 + .../getting-started/updating-linuxcnc.adoc | 18 + share/axis/tcl/axis.tcl | 7 + src/emc/ini/initraj.cc | 19 ++ src/emc/motion-logger/motion-logger.c | 4 + src/emc/motion/axis.c | 322 +++++++++++++++++- src/emc/motion/axis.h | 18 +- src/emc/motion/command.c | 185 +++++++++- src/emc/motion/control.c | 92 ++++- src/emc/motion/mot_priv.h | 5 + src/emc/motion/motion.h | 16 + src/emc/nml_intf/emc.cc | 3 + src/emc/nml_intf/emc.hh | 1 + src/emc/nml_intf/emc_nml.hh | 3 + src/emc/nml_intf/emcops.cc | 3 + src/emc/task/emctaskmain.cc | 90 +++++ src/emc/task/halui.cc | 6 +- src/emc/task/taskintf.cc | 15 + src/emc/usr_intf/axis/extensions/emcmodule.cc | 7 + src/emc/usr_intf/axis/scripts/axis.py | 39 ++- src/emc/usr_intf/shcom.cc | 9 +- .../expected.motion-logger | 1 + tests/jog-while-paused/.gitignore | 2 + tests/jog-while-paused/checkresult | 2 + tests/jog-while-paused/m0.ngc | 5 + tests/jog-while-paused/program.ngc | 9 + tests/jog-while-paused/sim.hal | 16 + tests/jog-while-paused/test-ui.py | 223 ++++++++++++ tests/jog-while-paused/test.ini | 82 +++++ tests/jog-while-paused/test.sh | 3 + tests/jog-while-paused/tool.tbl | 1 + .../basic/expected.builtin-startup.in | 1 + .../mountaindew/expected.motion-logger | 1 + .../expected.motion-logger.in | 1 + 35 files changed, 1191 insertions(+), 35 deletions(-) create mode 100644 tests/jog-while-paused/.gitignore create mode 100755 tests/jog-while-paused/checkresult create mode 100644 tests/jog-while-paused/m0.ngc create mode 100644 tests/jog-while-paused/program.ngc create mode 100644 tests/jog-while-paused/sim.hal create mode 100755 tests/jog-while-paused/test-ui.py create mode 100644 tests/jog-while-paused/test.ini create mode 100755 tests/jog-while-paused/test.sh create mode 100644 tests/jog-while-paused/tool.tbl diff --git a/docs/src/config/ini-config.adoc b/docs/src/config/ini-config.adoc index c019009d7de..9fe0aeb6fa5 100644 --- a/docs/src/config/ini-config.adoc +++ b/docs/src/config/ini-config.adoc @@ -950,6 +950,9 @@ Finally, no amount of tweaking will speed up a tool path with lots of small, tig * `MAX_LINEAR_VELOCITY = 5.0` - (((MAX VELOCITY))) The maximum velocity for any axis or coordinated move, in 'machine units' per second. The value shown equals 300 units per minute. * `MAX_LINEAR_ACCELERATION = 20.0` - (((MAX ACCELERATION))) The maximum acceleration for any axis or coordinated axis move, in 'machine units' per second per second. +* `PAUSE_RETURN_LAST = Z` - (((PAUSE RETURN LAST))) The axes that return last when a paused program or MDI command resumes after jogs while paused. + The other axes return to the paused position first, together in a straight line, then these, so by default the tool comes down onto the point last. + Empty: all axes return in one straight line. The return runs at the axis velocity and acceleration limits. * `PLANNER_TYPE = 0` - (((PLANNER TYPE))) Selects the trajectory planner type: 0 = trapezoidal (default), 1 = S-curve with jerk limiting. S-curve planning is only active when `PLANNER_TYPE = 1` AND `MAX_LINEAR_JERK` is 1.0 or above; a smaller value falls back to trapezoidal, with an operator message. diff --git a/docs/src/config/python-interface.adoc b/docs/src/config/python-interface.adoc index 4fc52957d7f..aa33bd3c575 100644 --- a/docs/src/config/python-interface.adoc +++ b/docs/src/config/python-interface.adoc @@ -287,6 +287,20 @@ see <> for an example. *paused*:: '(returns boolean)' - `motion paused` flag. +*pause_jog_ok*:: '(returns boolean)' - + a pause has stopped the motion of a program or MDI command: axes may + jog, see `pause_offset`. + +*pause_offset*:: '(returns tuple of floats)' - + how far jogs while paused have moved each axis off the paused position. + Resume (or step) brings them back to zero first: the spindles and the + coolant as they were at the pause, the spindles at speed, the axes other + than `[TRAJ]PAUSE_RETURN_LAST` in a straight line, then those, then the + program goes on. An abort keeps the machine where it was jogged to. + +*pause_returning*:: '(returns boolean)' - + resuming after a pause: spindles, back to the paused position, then on. + *single_stepping*:: '(returns boolean)' - `motion single_stepping` flag. diff --git a/docs/src/getting-started/updating-linuxcnc.adoc b/docs/src/getting-started/updating-linuxcnc.adoc index 793ac8e2288..4a0eea2114e 100644 --- a/docs/src/getting-started/updating-linuxcnc.adoc +++ b/docs/src/getting-started/updating-linuxcnc.adoc @@ -282,6 +282,24 @@ the same time without taking the machine away from each other. * While MDI runs, jogs and switching between joint and world mode are refused; they used to be passed to motion. +=== Jogging while paused + +Axes can now be jogged, by keyboard, halui, linuxcncrsh or a wheel, while +a program or MDI command is paused, including at M0 and M1, once the pause +has stopped the motion. Joints cannot. On resume (or step) LinuxCNC first: + +. puts the spindles and the coolant back as they were at the pause, and + waits for the spindles to be at speed; +. returns the axes to the paused position: the axes other than + `[TRAJ]PAUSE_RETURN_LAST` (default `Z`) together in a straight line, + then those, at the axis limits; +. goes on with the program. + +Pausing again during the return stops it; the axes can be jogged again +from there. An abort keeps the machine where it was jogged to. Reverse +run is refused while the axes are away from the paused position. AXIS +enables its jog and spindle controls while paused. + == Preview renderer now requires OpenGL 3.3 core diff --git a/share/axis/tcl/axis.tcl b/share/axis/tcl/axis.tcl index 2b99ad86ae8..98ba9ffbc0b 100644 --- a/share/axis/tcl/axis.tcl +++ b/share/axis/tcl/axis.tcl @@ -1891,6 +1891,11 @@ proc update_state {args} { set_mode_from_tab } enable_group $::manualgroup + } elseif {$::task_state == $::STATE_ON && $::pause_jog_ok} { + # a paused program or MDI: jogs and the spindle, see jog_ok, but + # no homing + enable_group $::manualgroup + $::_tabs_manual.jogf.zerohome.home configure -state disabled } else { disable_group $::manualgroup } @@ -1999,6 +2004,7 @@ set block_delete 0 set interp_pause 0 set last_interp_state 0 set interp_state 0 +set pause_jog_ok 0 set running_line -1 set highlight_line -1 set coord_type 1 @@ -2020,6 +2026,7 @@ trace add variable optional_stop write queue_update_state trace add variable block_delete write queue_update_state trace add variable interp_pause write queue_update_state trace add variable interp_state write queue_update_state +trace add variable pause_jog_ok write queue_update_state trace add variable running_line write queue_update_state trace add variable highlight_line write queue_update_state trace add variable spindledir write queue_update_state diff --git a/src/emc/ini/initraj.cc b/src/emc/ini/initraj.cc index 36537e70bdc..6e6e9eb31e6 100644 --- a/src/emc/ini/initraj.cc +++ b/src/emc/ini/initraj.cc @@ -66,6 +66,7 @@ static int loadKins(const IniFile &ini) // [TRAJ]MAX_LINEAR_ACCELERATION Maximum linear acceleration (dv/dt) // [TRAJ]MAX_LINEAR_JERK Maximum linear jerk (da/dt) // [TRAJ]PLANNER_TYPE Planner type (0=standard, 1=S-curve) +// [TRAJ]PAUSE_RETURN_LAST Axes that return last after jogs while paused (default Z) // [TRAJ]ARC_BLEND_ENABLE S-curve planner settings // [TRAJ]ARC_BLEND_FALLBACK_ENABLE ... // [TRAJ]ARC_BLEND_OPTIMIZATION_DEPTH ... @@ -152,6 +153,24 @@ static int loadTraj(const IniFile &ini) return -1; } + // After jogs while paused, the other axes return to the paused position + // first, then these: by default Z, so the tool comes down onto the point + // last. Empty: all axes in one straight line. + unsigned pause_return_last = 1 << 2; + if (auto last = ini.findString("PAUSE_RETURN_LAST", "TRAJ")) { + static const std::string axes{"XYZABCUVW"}; + pause_return_last = 0; + for (auto c : *last) { + size_t n = axes.find_first_of(std::toupper(c & 0xff)); + if (n != std::string::npos) + pause_return_last |= 1u << n; + } + } + if (0 != emcTrajSetPauseReturnLast(pause_return_last)) { + print_dbg_config("emcTrajSetPauseReturnLast"); + return -1; + } + // Planner: 0 = trapezoidal, 1 = S-curve // Default = 0 int planner_type = ini.findIntV("PLANNER_TYPE", "TRAJ", 0, 0, 1); diff --git a/src/emc/motion-logger/motion-logger.c b/src/emc/motion-logger/motion-logger.c index 36b77e54528..303c62ed5b9 100644 --- a/src/emc/motion-logger/motion-logger.c +++ b/src/emc/motion-logger/motion-logger.c @@ -576,6 +576,10 @@ int main(int argc, char* argv[]) { log_print("SET_SCURVE_PEAK_SCALE scale=%.6g\n", c->scurve_peak_scale); break; + case EMCMOT_SET_PAUSE_RETURN_LAST: + log_print("SET_PAUSE_RETURN_LAST mask=0x%x\n", (unsigned)c->flags); + break; + case EMCMOT_SET_TERM_COND: log_print("SET_TERM_COND termCond=%d, tolerance=%.6g\n", c->termCond, c->tolerance); break; diff --git a/src/emc/motion/axis.c b/src/emc/motion/axis.c index 457d1d6fd9c..0fe5f431873 100644 --- a/src/emc/motion/axis.c +++ b/src/emc/motion/axis.c @@ -36,6 +36,11 @@ typedef struct { double ext_offset_acc_limit; /* upper limit of axis accel for ext offset */ rtapi_sint old_eoffset_counts; simple_tp_t ext_offset_tp; /* planner for external coordinate offsets*/ + + simple_tp_t pause_tp; /* planner for jogs while paused, see axis_pause_update() */ + double pause_base; /* paused program position plus external offset */ + int kb_pjog_active; /* non-zero during a keyboard jog while paused */ + int wheel_pjog_active; /* non-zero during a wheel jog while paused */ } emcmot_axis_t; typedef struct { @@ -69,6 +74,12 @@ typedef struct { static emcmot_axis_t axis_array[EMCMOT_MAX_AXIS]; static axis_hal_data_t *hal_data = NULL; +// The axes that return last when a paused program resumes after jogs, +// [TRAJ]PAUSE_RETURN_LAST, and how far that return has got: 0 not +// returning, 1 the other axes, 2 these. +static unsigned pause_return_last_mask = 1 << 2; // Z +static int pause_return_phase = 0; + // Mark strings for translation, but defer translation to userspace #define _(s) (s) @@ -417,14 +428,17 @@ bool axis_jog_is_active(void) emcmot_axis_t *axis; for (n = 0; n < EMCMOT_MAX_AXIS; n++) { axis = &axis_array[n]; - if (axis->kb_ajog_active || axis->wheel_ajog_active) { + if (axis->kb_ajog_active || axis->wheel_ajog_active + || axis->kb_pjog_active || axis->wheel_pjog_active) { return 1; } } return 0; } -void axis_handle_jogwheels(bool motion_teleop_flag, bool motion_enable_flag, bool homing_is_active) +static void pause_jog_limits(int axis_num, double *min_lim, double *max_lim); + +void axis_handle_jogwheels(bool motion_teleop_flag, bool pause_jog_flag, bool motion_enable_flag, bool homing_is_active) { int axis_num; emcmot_axis_t *axis; @@ -455,6 +469,34 @@ void axis_handle_jogwheels(bool motion_teleop_flag, bool motion_enable_flag, boo //just update counts continue; } + if (pause_jog_flag) { + // a wheel jog while a coordinated move is paused moves the + // pause offset, see axis_pause_update() + double min_lim, max_lim; + if (!motion_enable_flag) { continue; } + if (!hal_get_bool(axis_data->ajog_enable)) { continue; } + if (axis->kb_pjog_active) { continue; } + if (axis->locking_joint >= 0) { continue; } + pos = axis->pause_tp.pos_cmd + delta * hal_get_real(axis_data->ajog_scale); + if ( hal_get_bool(axis_data->ajog_vel_mode) ) { + double v = axis->vel_limit; + stop_dist = v * v / ( 2 * aaccel_limit); + if ( pos > axis->pause_tp.curr_pos + stop_dist ) { + pos = axis->pause_tp.curr_pos + stop_dist; + } else if ( pos < axis->pause_tp.curr_pos - stop_dist ) { + pos = axis->pause_tp.curr_pos - stop_dist; + } + } + pause_jog_limits(axis_num, &min_lim, &max_lim); + if (pos > max_lim) { continue; } + if (pos < min_lim) { continue; } + axis->pause_tp.pos_cmd = pos; + axis->pause_tp.max_vel = axis->vel_limit; + axis->pause_tp.max_acc = aaccel_limit; + axis->wheel_pjog_active = 1; + axis->pause_tp.enable = 1; + continue; + } if (!motion_teleop_flag) { axis->teleop_tp.enable = 0; return; @@ -769,3 +811,279 @@ int axis_calc_motion(double servo_period) } return violated_teleop_limit; } + +/* +** Jogs while a coordinated move is paused. +** +** The paused program position stays where it is. A jog moves the axis by +** an offset on top of it (pause_tp), added in axis_pause_update() the way +** the external offsets are. On resume the offsets run back to zero first +** (axis_pause_return_start()), so the machine is back where it paused +** before the program continues: the other axes together in a straight +** line, then the [TRAJ]PAUSE_RETURN_LAST ones, at the axis limits. +*/ + +void axis_set_pause_return_last(unsigned mask) +{ + pause_return_last_mask = mask; +} + +/* The range the pause offset may jog in: the soft limits, less the paused +** position, for a homed axis; one limit range either way otherwise, as +** axis_jog_limits() does. */ +static void pause_jog_limits(int axis_num, double *min_lim, double *max_lim) +{ + emcmot_axis_t *axis = &axis_array[axis_num]; + + if (axis_is_homed(axis_num)) { + *min_lim = axis->min_pos_limit - axis->pause_base; + *max_lim = axis->max_pos_limit - axis->pause_base; + } else { + double range = axis->max_pos_limit - axis->min_pos_limit; + *min_lim = axis->pause_tp.curr_pos - range; + *max_lim = axis->pause_tp.curr_pos + range; + } +} + +void axis_pause_jog_cont(int axis_num, double vel) +{ + emcmot_axis_t *axis = &axis_array[axis_num]; + double min_lim, max_lim; + + if (axis->wheel_pjog_active) { return; } + pause_jog_limits(axis_num, &min_lim, &max_lim); + axis->pause_tp.pos_cmd = (vel > 0.0) ? max_lim : min_lim; + axis->pause_tp.max_vel = fabs(vel); + axis->pause_tp.max_acc = axis->acc_limit; + axis->kb_pjog_active = 1; + axis->pause_tp.enable = 1; +} + +void axis_pause_jog_incr(int axis_num, double offset, double vel) +{ + emcmot_axis_t *axis = &axis_array[axis_num]; + double target, min_lim, max_lim; + + if (axis->wheel_pjog_active) { return; } + target = axis->pause_tp.pos_cmd + ((vel > 0.0) ? offset : -offset); + pause_jog_limits(axis_num, &min_lim, &max_lim); + if (target > max_lim) { return; } + if (target < min_lim) { return; } + axis->pause_tp.pos_cmd = target; + axis->pause_tp.max_vel = fabs(vel); + axis->pause_tp.max_acc = axis->acc_limit; + axis->kb_pjog_active = 1; + axis->pause_tp.enable = 1; +} + +void axis_pause_jog_abs(int axis_num, double pos, double vel) +{ + emcmot_axis_t *axis = &axis_array[axis_num]; + double target, min_lim, max_lim; + + if (axis->wheel_pjog_active) { return; } + // pos is where the axis should go; the offset is the way there + target = pos - axis->pause_base; + pause_jog_limits(axis_num, &min_lim, &max_lim); + if (target > max_lim) { target = max_lim; } + if (target < min_lim) { target = min_lim; } + axis->pause_tp.pos_cmd = target; + axis->pause_tp.max_vel = fabs(vel); + axis->pause_tp.max_acc = axis->acc_limit; + axis->kb_pjog_active = 1; + axis->pause_tp.enable = 1; +} + +void axis_pause_jog_abort(int axis_num) +{ + emcmot_axis_t *axis = &axis_array[axis_num]; + + if (pause_return_phase) { return; } + axis->pause_tp.enable = 0; + axis->kb_pjog_active = 0; + axis->wheel_pjog_active = 0; +} + +void axis_pause_update(double *pcmd_p[], double servo_period) +{ + int n; + + for (n = 0; n < EMCMOT_MAX_AXIS; n++) { + emcmot_axis_t *axis = &axis_array[n]; + double save_curr_pos = axis->pause_tp.curr_pos; + + axis->pause_base = *pcmd_p[n] + axis->ext_offset_tp.curr_pos; + if (!pause_return_phase) { + axis->pause_tp.max_jerk = axis->jerk_limit; + if (axis->pause_tp.max_vel > axis->vel_limit) { + axis->pause_tp.max_vel = axis->vel_limit; + } + } + simple_tp_update(&axis->pause_tp, servo_period); + + // stay within the soft limits, as update_teleop_with_check() does; + // a return only moves back toward the paused position + if ( !pause_return_phase + && !((0 == axis->max_pos_limit) && (0 == axis->min_pos_limit)) + && axis_is_homed(n)) { + double pos = axis->pause_base + axis->pause_tp.curr_pos; + if ( (pos >= axis->max_pos_limit && axis->pause_tp.curr_pos > save_curr_pos) + || (pos <= axis->min_pos_limit && axis->pause_tp.curr_pos < save_curr_pos)) { + axis->pause_tp.curr_pos = save_curr_pos; + axis->pause_tp.curr_vel = 0; + axis->pause_tp.pos_cmd = save_curr_pos; + } + } + if (!axis->pause_tp.active) { + axis->kb_pjog_active = 0; + axis->wheel_pjog_active = 0; + } + *pcmd_p[n] += axis->pause_tp.curr_pos; + } +} + +/* Send the axes in mask back to zero offset in a straight line: the same +** profile for all, scaled by each one's distance, as fast as the slowest +** axis allows. Returns whether any axis has to move. */ +static bool pause_return_plan(unsigned mask) +{ + double v = 1e99, a = 1e99, j = 1e99; + bool jerk = true, any = false; + int n; + + for (n = 0; n < EMCMOT_MAX_AXIS; n++) { + emcmot_axis_t *axis = &axis_array[n]; + double d = fabs(axis->pause_tp.curr_pos); + if (!(mask & (1u << n))) { continue; } + if (d < 1e-12) { continue; } + any = true; + if (axis->vel_limit / d < v) { v = axis->vel_limit / d; } + if (axis->acc_limit / d < a) { a = axis->acc_limit / d; } + if (axis->jerk_limit > 0) { + if (axis->jerk_limit / d < j) { j = axis->jerk_limit / d; } + } else { + jerk = false; + } + } + for (n = 0; n < EMCMOT_MAX_AXIS; n++) { + emcmot_axis_t *axis = &axis_array[n]; + double d = fabs(axis->pause_tp.curr_pos); + if (!(mask & (1u << n))) { continue; } + axis->kb_pjog_active = 0; + axis->wheel_pjog_active = 0; + if (d < 1e-12) { + axis->pause_tp.curr_pos = axis->pause_tp.pos_cmd = 0; + continue; + } + axis->pause_tp.pos_cmd = 0; + axis->pause_tp.max_vel = d * v; + axis->pause_tp.max_acc = d * a; + axis->pause_tp.max_jerk = jerk ? d * j : 0; + axis->pause_tp.enable = 1; + } + return any; +} + +static bool pause_return_settled(unsigned mask) +{ + int n; + + for (n = 0; n < EMCMOT_MAX_AXIS; n++) { + if (!(mask & (1u << n))) { continue; } + if (axis_array[n].pause_tp.active) { return false; } + } + // the planner stops within a tiny distance of zero; make it zero + for (n = 0; n < EMCMOT_MAX_AXIS; n++) { + if (!(mask & (1u << n))) { continue; } + axis_array[n].pause_tp.curr_pos = axis_array[n].pause_tp.pos_cmd = 0; + axis_array[n].pause_tp.curr_vel = 0; + axis_array[n].pause_tp.curr_acc = 0; + } + return true; +} + +void axis_pause_return_start(void) +{ + pause_return_phase = 1; + if (!pause_return_plan(~pause_return_last_mask)) { + pause_return_settled(~pause_return_last_mask); + pause_return_phase = 2; + if (!pause_return_plan(pause_return_last_mask)) { + pause_return_settled(pause_return_last_mask); + pause_return_phase = 0; + } + } +} + +bool axis_pause_return_update(void) +{ + if (pause_return_phase == 1 && pause_return_settled(~pause_return_last_mask)) { + pause_return_phase = 2; + if (!pause_return_plan(pause_return_last_mask)) { + pause_return_settled(pause_return_last_mask); + pause_return_phase = 0; + } + } else if (pause_return_phase == 2 && pause_return_settled(pause_return_last_mask)) { + pause_return_phase = 0; + } + return pause_return_phase == 0; +} + +void axis_pause_return_cancel(void) +{ + int n; + + pause_return_phase = 0; + for (n = 0; n < EMCMOT_MAX_AXIS; n++) { + axis_array[n].pause_tp.enable = 0; + } +} + +bool axis_pause_returning(void) +{ + return pause_return_phase != 0; +} + +bool axis_pause_offset_active(void) +{ + int n; + + for (n = 0; n < EMCMOT_MAX_AXIS; n++) { + if (axis_array[n].pause_tp.curr_pos != 0 || axis_array[n].pause_tp.active) { + return true; + } + } + return false; +} + +bool axis_pause_jog_is_active(void) +{ + int n; + + for (n = 0; n < EMCMOT_MAX_AXIS; n++) { + if (axis_array[n].kb_pjog_active || axis_array[n].wheel_pjog_active) { + return true; + } + } + return false; +} + +void axis_pause_clear(void) +{ + int n; + + pause_return_phase = 0; + for (n = 0; n < EMCMOT_MAX_AXIS; n++) { + simple_tp_t *tp = &axis_array[n].pause_tp; + tp->pos_cmd = tp->curr_pos = tp->curr_vel = tp->curr_acc = 0; + tp->enable = 0; + tp->active = 0; + axis_array[n].kb_pjog_active = 0; + axis_array[n].wheel_pjog_active = 0; + } +} + +double axis_get_pause_offset(int axis_num) +{ + return axis_array[axis_num].pause_tp.curr_pos; +} diff --git a/src/emc/motion/axis.h b/src/emc/motion/axis.h index 5d61f0b13f0..fd542994dfb 100644 --- a/src/emc/motion/axis.h +++ b/src/emc/motion/axis.h @@ -13,7 +13,7 @@ void axis_init_all(void); void axis_initialize_external_offsets(void); int axis_init_hal_io(int mot_comp_id); -void axis_handle_jogwheels(bool motion_teleop_flag, bool motion_enable_flag, bool homing_is_active); +void axis_handle_jogwheels(bool motion_teleop_flag, bool pause_jog_flag, bool motion_enable_flag, bool homing_is_active); bool axis_plan_external_offsets(double servo_period, bool motion_enable_flag, bool all_homed); void axis_check_constraints(double pos[], int failing_axes[]); @@ -53,6 +53,22 @@ int axis_update_coord_with_bound(double *pcmd_p[], double servo_period); int axis_calc_motion(double servo_period); +// jogs while a coordinated move is paused, see axis.c +void axis_set_pause_return_last(unsigned mask); +void axis_pause_jog_cont(int axis_num, double vel); +void axis_pause_jog_incr(int axis_num, double offset, double vel); +void axis_pause_jog_abs(int axis_num, double pos, double vel); +void axis_pause_jog_abort(int axis_num); +void axis_pause_update(double *pcmd_p[], double servo_period); +void axis_pause_return_start(void); +bool axis_pause_return_update(void); +void axis_pause_return_cancel(void); +bool axis_pause_returning(void); +bool axis_pause_offset_active(void); +bool axis_pause_jog_is_active(void); +void axis_pause_clear(void); +double axis_get_pause_offset(int axis_num); + #ifdef __cplusplus } diff --git a/src/emc/motion/command.c b/src/emc/motion/command.c index 14356e1c9c1..d9d295c64ec 100644 --- a/src/emc/motion/command.c +++ b/src/emc/motion/command.c @@ -220,6 +220,100 @@ void apply_spindle_limits(spindle_status_t *s){ } } +/* Jogs while paused. In coordinated mode a jog moves the pause offset + (axis_pause_*() in axis.c): only an axis, and only once a pause has + stopped the motion (emcmotStatus->pause_jog_ok, set in control.c). */ +static bool pause_jog_check(void) +{ + int axis_num = emcmotCommand->axis; + + if (axis_num < 0 || axis_num >= EMCMOT_MAX_AXIS) { + reportError(_("Can't jog a joint while a coordinated move is paused, jog an axis")); + return false; + } + if (!emcmotStatus->pause_jog_ok) { + reportError(_("Can't jog until the paused motion has stopped")); + return false; + } + if (axis_get_locking_joint(axis_num) >= 0) { + reportError(_("Cannot jog a locking indexer AXIS_%c"), "XYZABCUVW"[axis_num]); + return false; + } + return true; +} + +/* What EMCMOT_RESUME and EMCMOT_STEP do, right away or, after jogs while + paused, once do_pause_resume() (control.c) has the machine back. */ +void pause_resume_now(int cmd) +{ + if (cmd == EMCMOT_STEP) { + if (emcmotStatus->paused) { + emcmotInternal->idForStep = emcmotStatus->id; + emcmotStatus->stepping = 1; + tpResume(&emcmotInternal->coord_tp); + emcmotStatus->paused = 1; + } else { + reportError(_("MOTION: can't STEP while already executing")); + } + return; + } + emcmotStatus->stepping = 0; + tpResume(&emcmotInternal->coord_tp); + emcmotStatus->paused = 0; + emcmotInternal->pause_spindles_saved = 0; +} + +/* The spindles as they were when the motion paused. */ +void pause_save_spindles(void) +{ + int n; + + for (n = 0; n < emcmotConfig->numSpindles; n++) { + spindle_status_t *sp = &emcmotStatus->spindle_status[n]; + emcmotInternal->pause_spindle[n].state = sp->state; + emcmotInternal->pause_spindle[n].direction = sp->direction; + emcmotInternal->pause_spindle[n].brake = sp->brake; + emcmotInternal->pause_spindle[n].speed = sp->speed; + emcmotInternal->pause_spindle[n].css_factor = sp->css_factor; + emcmotInternal->pause_spindle[n].xoffset = sp->xoffset; + } + emcmotInternal->pause_spindles_saved = 1; +} + +/* Put the spindles back the way they were when the motion paused, as + EMCMOT_SPINDLE_ON and EMCMOT_SPINDLE_OFF would. Returns whether any of + them changed. */ +bool pause_restore_spindles(void) +{ + bool changed = false; + int n; + + if (!emcmotInternal->pause_spindles_saved) { return false; } + for (n = 0; n < emcmotConfig->numSpindles; n++) { + spindle_status_t *sp = &emcmotStatus->spindle_status[n]; + const emcmot_pause_spindle_t *saved = &emcmotInternal->pause_spindle[n]; + if ( sp->state == saved->state && sp->direction == saved->direction + && sp->speed == saved->speed && sp->css_factor == saved->css_factor + && sp->xoffset == saved->xoffset) { + continue; + } + changed = true; + hal_set_bool(emcmot_hal_data->spindle[n].spindle_locked, 0); + hal_set_bool(emcmot_hal_data->spindle[n].spindle_orient, 0); + sp->orient_state = EMCMOT_ORIENT_NONE; + sp->state = saved->state; + sp->speed = saved->speed; + sp->css_factor = saved->css_factor; + sp->xoffset = saved->xoffset; + sp->direction = saved->direction; + sp->brake = saved->brake; + if (sp->state) { + apply_spindle_limits(sp); + } + } + return changed; +} + /* inRange() returns non-zero if the position lies within the joint limits, or 0 if not. It also reports an error for each joint limit @@ -449,9 +543,10 @@ void emcmotCommandHandler_locked(void *arg, long servo_period) // joints_axes test for unexpected conditions // example: non-cooperating guis // example: attempt to jog locking indexer axis letter - if ( emcmotCommand->command == EMCMOT_JOG_CONT - || emcmotCommand->command == EMCMOT_JOG_INCR - || emcmotCommand->command == EMCMOT_JOG_ABS + if ( ( emcmotCommand->command == EMCMOT_JOG_CONT + || emcmotCommand->command == EMCMOT_JOG_INCR + || emcmotCommand->command == EMCMOT_JOG_ABS) + && !GET_MOTION_COORD_FLAG() // jogs while paused, see pause_jog_check() ) { if (GET_MOTION_TELEOP_FLAG() && (emcmotCommand->axis < 0)) { emsg = "command.com teleop: unexpected negative axis_num"; @@ -507,6 +602,7 @@ void emcmotCommandHandler_locked(void *arg, long servo_period) || emcmotCommand->command == EMCMOT_JOG_ABS ) && !(GET_MOTION_TELEOP_FLAG()) + && !GET_MOTION_COORD_FLAG() && get_home_is_synchronized(joint_num) && !get_homing_is_active() ) { @@ -579,6 +675,14 @@ void emcmotCommandHandler_locked(void *arg, long servo_period) SET_JOINT_FAULT_FLAG(joint, 0); } emcmotStatus->paused = 0; + /* stop jogs while paused and any return; control.c takes the + offsets into the planner position once it is idle */ + emcmotInternal->pause_resume_cmd = 0; + emcmotInternal->pause_spindles_saved = 0; + axis_pause_return_cancel(); + for (n = 0; n < EMCMOT_MAX_AXIS; n++) { + axis_pause_jog_abort(n); + } /* Drop any pending at-speed barrier so it can't strand a later move. */ emcmotStatus->atspeed_next_feed = 0; // Clear pins on abort so tests see a clean state @@ -597,7 +701,12 @@ void emcmotCommandHandler_locked(void *arg, long servo_period) /* abort one joint number or axis number */ /* can happen at any time */ rtapi_print_msg(RTAPI_MSG_DBG, "JOG_ABORT: %i", joint_num); - if (GET_MOTION_TELEOP_FLAG()) { + if (GET_MOTION_COORD_FLAG()) { + /* a jog while paused */ + if ((emcmotCommand->axis >= 0) && (emcmotCommand->axis < EMCMOT_MAX_AXIS)) { + axis_pause_jog_abort(emcmotCommand->axis); + } + } else if (GET_MOTION_TELEOP_FLAG()) { /* tell teleop planner to stop */ if ((emcmotCommand->axis >= 0) && (emcmotCommand->axis < EMCMOT_MAX_AXIS)) { axis_jog_abort(emcmotCommand->axis, 0); @@ -853,6 +962,13 @@ void emcmotCommandHandler_locked(void *arg, long servo_period) SET_JOINT_ERROR_FLAG(joint, 1); break; } + if (GET_MOTION_COORD_FLAG()) { + // COORD (paused) JOG_CONT + if (pause_jog_check()) { + axis_pause_jog_cont(emcmotCommand->axis, emcmotCommand->vel); + } + break; + } if (!GET_MOTION_TELEOP_FLAG()) { if (joint->wheel_jjog_active) { /* can't do two kinds of jog at once */ @@ -922,6 +1038,13 @@ void emcmotCommandHandler_locked(void *arg, long servo_period) SET_JOINT_ERROR_FLAG(joint, 1); break; } + if (GET_MOTION_COORD_FLAG()) { + // COORD (paused) JOG_INCR + if (pause_jog_check()) { + axis_pause_jog_incr(emcmotCommand->axis, emcmotCommand->offset, emcmotCommand->vel); + } + break; + } if (!GET_MOTION_TELEOP_FLAG()) { if (joint->wheel_jjog_active) { /* can't do two kinds of jog at once */ @@ -984,6 +1107,15 @@ void emcmotCommandHandler_locked(void *arg, long servo_period) /* do an absolute jog */ rtapi_print_msg(RTAPI_MSG_DBG, "JOG_ABS"); rtapi_print_msg(RTAPI_MSG_DBG, " %d", joint_num); + if (GET_MOTION_COORD_FLAG()) { + // COORD (paused) JOG_ABS + if ( GET_MOTION_ENABLE_FLAG() + && !hal_get_bool(emcmot_hal_data->jog_inhibit) + && pause_jog_check()) { + axis_pause_jog_abs(emcmotCommand->axis, emcmotCommand->offset, emcmotCommand->vel); + } + break; + } if (joint == 0) { break; } @@ -1301,6 +1433,11 @@ void emcmotCommandHandler_locked(void *arg, long servo_period) /* ===== END PLANNER_SWITCH_DEFER ==================================== */ break; + case EMCMOT_SET_PAUSE_RETURN_LAST: + rtapi_print_msg(RTAPI_MSG_DBG, "SET_PAUSE_RETURN_LAST"); + axis_set_pause_return_last((unsigned)emcmotCommand->flags); + break; + case EMCMOT_SET_SCURVE_PEAK_SCALE: /* S-curve rest-to-rest peak velocity scale: 0.5 = faithful (original * behaviour), 1.0 = physically-correct (full jerk-feasible cornering). @@ -1319,6 +1456,14 @@ void emcmotCommandHandler_locked(void *arg, long servo_period) /* pause the motion */ /* can happen at any time */ rtapi_print_msg(RTAPI_MSG_DBG, "PAUSE"); + if (!emcmotStatus->paused) { + pause_save_spindles(); + } + /* pausing again while resuming stops the return where it is */ + if (emcmotInternal->pause_resume_cmd) { + emcmotInternal->pause_resume_cmd = 0; + axis_pause_return_cancel(); + } tpPause(&emcmotInternal->coord_tp); emcmotStatus->paused = 1; break; @@ -1327,6 +1472,10 @@ void emcmotCommandHandler_locked(void *arg, long servo_period) /* run motion in reverse*/ /* only allowed during a pause */ rtapi_print_msg(RTAPI_MSG_DBG, "REVERSE"); + if (axis_pause_offset_active() || emcmotInternal->pause_resume_cmd) { + reportError(_("Can't run in reverse while jogged away from the paused position")); + break; + } tpSetRunDir(&emcmotInternal->coord_tp, TC_DIR_REVERSE); break; @@ -1334,6 +1483,10 @@ void emcmotCommandHandler_locked(void *arg, long servo_period) /* run motion in reverse*/ /* only allowed during a pause */ rtapi_print_msg(RTAPI_MSG_DBG, "FORWARD"); + if (axis_pause_offset_active() || emcmotInternal->pause_resume_cmd) { + reportError(_("Can't change direction while jogged away from the paused position")); + break; + } tpSetRunDir(&emcmotInternal->coord_tp, TC_DIR_FORWARD); break; @@ -1341,23 +1494,27 @@ void emcmotCommandHandler_locked(void *arg, long servo_period) /* resume paused motion */ /* can happen at any time */ rtapi_print_msg(RTAPI_MSG_DBG, "RESUME"); - emcmotStatus->stepping = 0; - tpResume(&emcmotInternal->coord_tp); - emcmotStatus->paused = 0; + if (emcmotStatus->paused && GET_MOTION_COORD_FLAG()) { + /* spindles, then back to the paused position, then on: + do_pause_resume() in control.c */ + emcmotInternal->pause_resume_cmd = EMCMOT_RESUME; + emcmotInternal->pause_resume_phase = 0; + break; + } + pause_resume_now(EMCMOT_RESUME); break; case EMCMOT_STEP: /* resume paused motion until id changes */ /* can happen at any time */ rtapi_print_msg(RTAPI_MSG_DBG, "STEP"); - if(emcmotStatus->paused) { - emcmotInternal->idForStep = emcmotStatus->id; - emcmotStatus->stepping = 1; - tpResume(&emcmotInternal->coord_tp); - emcmotStatus->paused = 1; - } else { - reportError(_("MOTION: can't STEP while already executing")); + if (emcmotStatus->paused && GET_MOTION_COORD_FLAG()) { + /* as EMCMOT_RESUME, see do_pause_resume() */ + emcmotInternal->pause_resume_cmd = EMCMOT_STEP; + emcmotInternal->pause_resume_phase = 0; + break; } + pause_resume_now(EMCMOT_STEP); break; case EMCMOT_FEED_SCALE: diff --git a/src/emc/motion/control.c b/src/emc/motion/control.c index 17fb96b7ddd..ff4af89a4ab 100644 --- a/src/emc/motion/control.c +++ b/src/emc/motion/control.c @@ -195,6 +195,9 @@ static void update_status(void); static void handle_kinematicsSwitch(void); +/* resume after jogs while paused: spindles, at speed, back, on */ +static void do_pause_resume(void); + /*********************************************************************** * PUBLIC FUNCTION CODE * ************************************************************************/ @@ -259,7 +262,7 @@ void emcmotController(void *arg, long period) handle_jjogwheels(); } if (!emcmotStatus->on_soft_limit && !hal_get_bool(emcmot_hal_data->jog_inhibit)) { // change from teleop to move off joint soft limit - axis_handle_jogwheels(GET_MOTION_TELEOP_FLAG(), GET_MOTION_ENABLE_FLAG(), get_homing_is_active()); + axis_handle_jogwheels(GET_MOTION_TELEOP_FLAG(), emcmotStatus->pause_jog_ok, GET_MOTION_ENABLE_FLAG(), get_homing_is_active()); } if ( (emcmotStatus->motion_state == EMCMOT_MOTION_FREE) && do_homing()) { @@ -972,6 +975,8 @@ static void set_operating_mode(void) hal_set_bool(emcmot_hal_data->eoffset_limited, 0); } axis_initialize_external_offsets(); + axis_pause_clear(); + emcmotInternal->pause_resume_cmd = 0; tpSetPos(&emcmotInternal->coord_tp, &emcmotStatus->carte_pos_cmd); for (joint_num = 0; joint_num < ALL_JOINTS; joint_num++) { /* point to joint data */ @@ -1017,6 +1022,11 @@ static void set_operating_mode(void) } } coord_cubic_active = 0; + /* jogs while paused end with coordinated mode; their offsets + are in carte_pos_cmd */ + axis_pause_clear(); + emcmotInternal->pause_resume_cmd = 0; + emcmotStatus->pause_jog_ok = 0; /* Initialize things to do when starting teleop mode. */ SET_MOTION_TELEOP_FLAG(1); SET_MOTION_COORD_FLAG(0); @@ -1082,6 +1092,9 @@ static void set_operating_mode(void) /* but it can stay disabled until a move is required */ joint->free_tp.enable = 0; } + axis_pause_clear(); + emcmotInternal->pause_resume_cmd = 0; + emcmotStatus->pause_jog_ok = 0; SET_MOTION_COORD_FLAG(0); SET_MOTION_TELEOP_FLAG(0); SET_MOTION_ERROR_FLAG(0); @@ -1430,6 +1443,25 @@ static void get_pos_cmds(long period) /* get new commanded traj pos */ tpGetPos(&emcmotInternal->coord_tp, &emcmotStatus->carte_pos_cmd); + /* jogs while paused move the axes off the paused position by + the pause offsets; a resume first brings them back */ + emcmotStatus->pause_jog_ok = emcmotStatus->paused + && !emcmotStatus->stepping + && !emcmotInternal->pause_resume_cmd + && emcmotStatus->current_vel < 1e-9; + axis_pause_update(pcmd_p, servo_period); + do_pause_resume(); + if ( !emcmotStatus->paused + && !emcmotInternal->pause_resume_cmd + && axis_pause_offset_active() + && !axis_pause_jog_is_active() + && tpIsDone(&emcmotInternal->coord_tp)) { + /* aborted while jogged away: stay here, the planner + takes the offsets into its position */ + tpSetPos(&emcmotInternal->coord_tp, &emcmotStatus->carte_pos_cmd); + axis_pause_clear(); + } + if (axis_update_coord_with_bound(pcmd_p, servo_period)) { ext_offset_coord_limit = 1; } else { @@ -2258,6 +2290,20 @@ static void update_status(void) emcmotStatus->external_offsets_applied = hal_get_bool(emcmot_hal_data->eoffset_active); + emcmotStatus->pause_offset.tran.x = axis_get_pause_offset(0); + emcmotStatus->pause_offset.tran.y = axis_get_pause_offset(1); + emcmotStatus->pause_offset.tran.z = axis_get_pause_offset(2); + emcmotStatus->pause_offset.a = axis_get_pause_offset(3); + emcmotStatus->pause_offset.b = axis_get_pause_offset(4); + emcmotStatus->pause_offset.c = axis_get_pause_offset(5); + emcmotStatus->pause_offset.u = axis_get_pause_offset(6); + emcmotStatus->pause_offset.v = axis_get_pause_offset(7); + emcmotStatus->pause_offset.w = axis_get_pause_offset(8); + emcmotStatus->pause_returning = emcmotInternal->pause_resume_cmd != 0; + if (!GET_MOTION_COORD_FLAG()) { + emcmotStatus->pause_jog_ok = 0; + } + for (dio = 0; dio < emcmotConfig->numDIO; dio++) { emcmotStatus->synch_di[dio] = hal_get_bool(emcmot_hal_data->synch_di[dio]); emcmotStatus->synch_do[dio] = hal_get_bool(emcmot_hal_data->synch_do[dio]); @@ -2374,3 +2420,47 @@ static void update_status(void) } #endif } + +/* Resuming a pause (EMCMOT_RESUME or EMCMOT_STEP, see command.c): put the + spindles back the way they were when the motion paused and wait until + they are at speed, return the axes from jogs while paused to the paused + position (axis_pause_return_*()), then resume. A pause on the way stops + it (command.c). */ +static void do_pause_resume(void) +{ + // a changed spindle's at-speed input needs a moment to follow the new + // command before it can be trusted + static const double SPINDLE_SETTLE = 0.1; + static double settle; + int n; + + if (!emcmotInternal->pause_resume_cmd) { return; } + + switch (emcmotInternal->pause_resume_phase) { + case 0: + settle = pause_restore_spindles() ? SPINDLE_SETTLE : 0; + emcmotInternal->pause_resume_phase = 1; + /* fall through */ + case 1: + if (settle > 0) { + settle -= servo_period; + return; + } + for (n = 0; n < emcmotConfig->numSpindles; n++) { + if (emcmotStatus->spindle_status[n].state + && !emcmotStatus->spindle_status[n].at_speed) { + return; + } + } + axis_pause_return_start(); + emcmotInternal->pause_resume_phase = 2; + /* fall through */ + case 2: + if (!axis_pause_return_update()) { return; } + n = emcmotInternal->pause_resume_cmd; + emcmotInternal->pause_resume_cmd = 0; + emcmotInternal->pause_resume_phase = 0; + pause_resume_now(n); + break; + } +} diff --git a/src/emc/motion/mot_priv.h b/src/emc/motion/mot_priv.h index 954de98dd84..df94e1cbe90 100644 --- a/src/emc/motion/mot_priv.h +++ b/src/emc/motion/mot_priv.h @@ -265,6 +265,11 @@ extern int emcmotGetRotaryIsUnlocked(int axis); // void switch_to_teleop_mode(void); +/* resuming after jogs while paused, see command.c and do_pause_resume() */ +void pause_resume_now(int cmd); +void pause_save_spindles(void); +bool pause_restore_spindles(void); + /* recalculates jog limits */ extern void refresh_jog_limits(emcmot_joint_t *joint,int joint_num); /* handles 'homed' flags, see command.c for details */ diff --git a/src/emc/motion/motion.h b/src/emc/motion/motion.h index 7f3572eda73..ae4306d2ed0 100644 --- a/src/emc/motion/motion.h +++ b/src/emc/motion/motion.h @@ -128,6 +128,7 @@ extern "C" { EMCMOT_SET_JERK, /* set the max jerk for moves (tooltip) */ EMCMOT_SET_PLANNER_TYPE, /* set planner type (0=trapezoidal, 1=S-curve) */ EMCMOT_SET_SCURVE_PEAK_SCALE, /* set S-curve rest-to-rest peak scale (0.5=faithful..1.0=full) */ + EMCMOT_SET_PAUSE_RETURN_LAST, /* axes (flags mask) that return last after jogs while paused */ EMCMOT_SET_TERM_COND, /* set termination condition (stop, blend) */ EMCMOT_SET_NUM_JOINTS, /* set the number of joints */ EMCMOT_SET_NUM_SPINDLES, /* set the number of spindles */ @@ -676,6 +677,9 @@ Suggestion: Split this in to an Error and a Status flag register.. unsigned char tail; /* flag count for mutex detect */ int external_offsets_applied; EmcPose eoffset_pose; + EmcPose pause_offset; /* how far jogs while paused moved off the paused position */ + int pause_jog_ok; /* paused and stopped in coordinated mode: axes may jog */ + int pause_returning; /* resuming: back to the paused position, then on */ int numExtraJoints; int stepping; bool jogging_active; @@ -775,6 +779,12 @@ Suggestion: Split this in to an Error and a Status flag register.. } emcmot_error_t; +/* a spindle as it was when the motion paused, see pause_save_spindles() */ +typedef struct { + int state, direction, brake; + double speed, css_factor, xoffset; +} emcmot_pause_spindle_t; + typedef struct emcmot_internal_t { unsigned char head; /* flag count for mutex detect */ unsigned char tail; /* flag count for mutex detect */ @@ -786,6 +796,12 @@ typedef struct emcmot_internal_t { move while overriding limits */ TP_STRUCT coord_tp; /* coordinated mode planner */ int idForStep; /* status id while stepping */ + /* resuming after jogs while paused, see do_pause_resume() in control.c: + 0 nothing to do, EMCMOT_RESUME or EMCMOT_STEP once back */ + int pause_resume_cmd; + int pause_resume_phase; /* 0 spindles, 1 at speed, 2 return */ + int pause_spindles_saved; + emcmot_pause_spindle_t pause_spindle[EMCMOT_MAX_SPINDLES]; /* the spindles when paused */ } emcmot_internal_t; /* error ring buffer access functions */ diff --git a/src/emc/nml_intf/emc.cc b/src/emc/nml_intf/emc.cc index da9b88e1e78..db9e68c4838 100644 --- a/src/emc/nml_intf/emc.cc +++ b/src/emc/nml_intf/emc.cc @@ -1840,6 +1840,9 @@ void EMC_MOTION_STAT::update(CMS * cms) cms->update(on_soft_limit); cms->update(external_offsets_applied); EmcPose_update(cms, &eoffset_pose); + EmcPose_update(cms, &pause_offset); + cms->update(pause_jog_ok); + cms->update(pause_returning); cms->update(numExtraJoints); cms->update(jogging_active); cms->update(homing_active); diff --git a/src/emc/nml_intf/emc.hh b/src/emc/nml_intf/emc.hh index d251e08abc6..7745cc5b501 100644 --- a/src/emc/nml_intf/emc.hh +++ b/src/emc/nml_intf/emc.hh @@ -393,6 +393,7 @@ extern int emcTrajUpdate(EMC_TRAJ_STAT * stat); extern int emcTrajSetJerk(double jerk); extern int emcTrajSetMaxJerk(double jerk); extern int emcTrajPlannerType(int type); +extern int emcTrajSetPauseReturnLast(unsigned axis_mask); extern int emcTrajSetScurvePeakScale(double scale); /* G64_R_PLANNER: [TRAJ]SMOOTH_PLANNER - planner a G64 R>0 request resolves to */ extern int emcTrajSetSmoothPlanner(int type); diff --git a/src/emc/nml_intf/emc_nml.hh b/src/emc/nml_intf/emc_nml.hh index 6e5d2277849..a53c5cbe301 100644 --- a/src/emc/nml_intf/emc_nml.hh +++ b/src/emc/nml_intf/emc_nml.hh @@ -1182,6 +1182,9 @@ class EMC_MOTION_STAT:public EMC_MOTION_STAT_MSG { int on_soft_limit; int external_offsets_applied; EmcPose eoffset_pose; + EmcPose pause_offset; // how far jogs while paused moved off the paused position + bool pause_jog_ok; // paused and stopped: axes may jog + bool pause_returning; // resuming: spindles, back to the paused position, then on int numExtraJoints; bool jogging_active; // Aggregate "the homing state machine is running", from diff --git a/src/emc/nml_intf/emcops.cc b/src/emc/nml_intf/emcops.cc index 708ec2a9f52..a53af59382c 100644 --- a/src/emc/nml_intf/emcops.cc +++ b/src/emc/nml_intf/emcops.cc @@ -124,6 +124,9 @@ EMC_MOTION_STAT::EMC_MOTION_STAT() on_soft_limit(0), external_offsets_applied(0), eoffset_pose{}, + pause_offset{}, + pause_jog_ok(false), + pause_returning(false), numExtraJoints(0), jogging_active(0), homing_active(false), diff --git a/src/emc/task/emctaskmain.cc b/src/emc/task/emctaskmain.cc index 7bf1c851aff..f609864790e 100644 --- a/src/emc/task/emctaskmain.cc +++ b/src/emc/task/emctaskmain.cc @@ -795,6 +795,12 @@ void readahead_waiting(void) // makes that switch once in position, so a run waits for it before the // first command leaves interp_list (see coordWaiting in emcTaskExecute()). +// The coolant as it was when a program or MDI paused: resume puts it back, +// as motion does with the spindles (pause_restore_spindles()). +static bool pauseCoolantSaved = false; +static int pauseMist = 0; +static int pauseFlood = 0; + // Set by taskRunStart(), cleared once motion is in coordinated mode. static bool coordWaiting = false; static double coordWaitStart = 0.0; @@ -860,6 +866,7 @@ static void taskRunEnd() { taskRun = TaskRun::NONE; coordWaiting = false; + pauseCoolantSaved = false; EMC_TRAJ_MODE mode = all_homed() ? EMC_TRAJ_MODE::TELEOP : EMC_TRAJ_MODE::FREE; if (runPriorHomed == (bool)all_homed()) { @@ -992,6 +999,63 @@ static void queueToolCommand(NMLmsg *cmd) emcTaskQueueTaskPlanSynchCmd(); } +// Coolant across a pause, see pauseCoolantSaved. +static void pauseSaveCoolant() +{ + if (pauseCoolantSaved) { + return; + } + pauseMist = emcStatus->io.coolant.mist; + pauseFlood = emcStatus->io.coolant.flood; + pauseCoolantSaved = true; +} + +static void pauseRestoreCoolant(bool resuming) +{ + if (!pauseCoolantSaved) { + return; + } + if (emcStatus->io.coolant.mist != pauseMist) { + pauseMist ? emcCoolantMistOn() : emcCoolantMistOff(); + } + if (emcStatus->io.coolant.flood != pauseFlood) { + pauseFlood ? emcCoolantFloodOn() : emcCoolantFloodOff(); + } + // a step pauses again, with the same coolant to come back to + pauseCoolantSaved = !resuming; +} + +// A jog while a program or MDI is paused moves the axes off the paused +// position, and resuming brings them back first (motion, axis_pause_*()). +// Only axes jog, and only once the pause has stopped the motion. +static int pausedJog(NMLmsg *cmd) +{ + int jjogmode = 0; + + switch (cmd->_type) { + case EMC_JOG_STOP_TYPE: + return emcTaskIssueCommand(cmd); + case EMC_JOG_CONT_TYPE: + jjogmode = static_cast(cmd)->jjogmode; + break; + case EMC_JOG_INCR_TYPE: + jjogmode = static_cast(cmd)->jjogmode; + break; + case EMC_JOG_ABS_TYPE: + jjogmode = static_cast(cmd)->jjogmode; + break; + } + if (jjogmode) { + emcOperatorError(_("Can't jog a joint while paused, jog an axis")); + return -1; + } + if (!emcStatus->motion.pause_jog_ok) { + emcOperatorError(_("Can't jog until the paused motion has stopped")); + return -1; + } + return emcTaskIssueCommand(cmd); +} + // Start a run from idle with cmd, see taskRunStart(). static int taskRunIssue(TaskRun run, NMLmsg *cmd) { @@ -1186,6 +1250,7 @@ static int emcTaskPlan(void) emcStatus->motion.traj.single_stepping = 1; stepping = 1; steppingWait = 0; + pauseRestoreCoolant(false); if (emcStatus->motion.traj.paused && emcStatus->motion.traj.queue > 0) { // there are pending motions paused; step them @@ -1196,6 +1261,13 @@ static int emcTaskPlan(void) emcStatus->task.task_paused = 1; break; + case EMC_JOG_CONT_TYPE: + case EMC_JOG_INCR_TYPE: + case EMC_JOG_ABS_TYPE: + case EMC_JOG_STOP_TYPE: + retval = pausedJog(emcCommand); + break; + default: if (isImmediate(type)) { retval = emcTaskIssueCommand(emcCommand); @@ -1247,6 +1319,19 @@ static int emcTaskPlan(void) queueToolCommand(emcCommand); break; + case EMC_JOG_CONT_TYPE: + case EMC_JOG_INCR_TYPE: + case EMC_JOG_ABS_TYPE: + case EMC_JOG_STOP_TYPE: + if (emcStatus->task.interpState == EMC_TASK_INTERP::PAUSED + || type == EMC_JOG_STOP_TYPE) { + retval = pausedJog(emcCommand); + break; + } + emcOperatorError(_("can't do that (%s) while MDI is running"), emc_symbol_lookup(type)); + retval = -1; + break; + default: if (isImmediate(type)) { retval = emcTaskIssueCommand(emcCommand); @@ -2125,6 +2210,7 @@ static int emcTaskIssueCommand(NMLmsg * cmd) break; case EMC_TASK_PLAN_PAUSE_TYPE: + pauseSaveCoolant(); emcTrajPause(); if (emcStatus->task.interpState != EMC_TASK_INTERP::PAUSED) { interpResumeState = emcStatus->task.interpState; @@ -2136,6 +2222,7 @@ static int emcTaskIssueCommand(NMLmsg * cmd) case EMC_TASK_PLAN_OPTIONAL_STOP_TYPE: if (GET_OPTIONAL_PROGRAM_STOP() == ON) { + pauseSaveCoolant(); emcTrajPause(); if (emcStatus->task.interpState != EMC_TASK_INTERP::PAUSED) { interpResumeState = emcStatus->task.interpState; @@ -2157,6 +2244,9 @@ static int emcTaskIssueCommand(NMLmsg * cmd) break; case EMC_TASK_PLAN_RESUME_TYPE: + // motion puts the spindles back and returns from jogs while paused + // before it goes on + pauseRestoreCoolant(true); emcTrajResume(); emcStatus->task.interpState = interpResumeState; emcStatus->task.task_paused = 0; diff --git a/src/emc/task/halui.cc b/src/emc/task/halui.cc index af1847372a9..d182384e292 100644 --- a/src/emc/task/halui.cc +++ b/src/emc/task/halui.cc @@ -859,7 +859,7 @@ static void sendJogStop(int ja, int jjogmode) EMC_JOG_STOP emc_jog_stop_msg; if ( ( (jjogmode == JOGJOINT) && (emcStatus->motion.traj.mode == EMC_TRAJ_MODE::TELEOP) ) - || ( (jjogmode == JOGTELEOP ) && (emcStatus->motion.traj.mode != EMC_TRAJ_MODE::TELEOP) ) + || ( (jjogmode == JOGTELEOP ) && (emcStatus->motion.traj.mode != EMC_TRAJ_MODE::TELEOP) && !emcStatus->motion.pause_jog_ok && (emcStatus->motion.traj.mode != EMC_TRAJ_MODE::COORD) ) ) { return; } @@ -880,7 +880,7 @@ static void sendJogCont(int ja, double speed, int jjogmode) if (emcStatus->task.state != EMC_TASK_STATE::ON) { return; } if ( ( (jjogmode == JOGJOINT) && (emcStatus->motion.traj.mode == EMC_TRAJ_MODE::TELEOP) ) - || ( (jjogmode == JOGTELEOP ) && (emcStatus->motion.traj.mode != EMC_TRAJ_MODE::TELEOP) ) + || ( (jjogmode == JOGTELEOP ) && (emcStatus->motion.traj.mode != EMC_TRAJ_MODE::TELEOP) && !emcStatus->motion.pause_jog_ok ) ) { return; } @@ -902,7 +902,7 @@ static void sendJogIncr(int ja, double speed, double incr, int jjogmode) if (emcStatus->task.state != EMC_TASK_STATE::ON) { return; } if ( ( (jjogmode == JOGJOINT) && (emcStatus->motion.traj.mode == EMC_TRAJ_MODE::TELEOP) ) - || ( (jjogmode == JOGTELEOP ) && (emcStatus->motion.traj.mode != EMC_TRAJ_MODE::TELEOP) ) + || ( (jjogmode == JOGTELEOP ) && (emcStatus->motion.traj.mode != EMC_TRAJ_MODE::TELEOP) && !emcStatus->motion.pause_jog_ok ) ) { return; } diff --git a/src/emc/task/taskintf.cc b/src/emc/task/taskintf.cc index 049ae4d26d4..a4a52d29a81 100644 --- a/src/emc/task/taskintf.cc +++ b/src/emc/task/taskintf.cc @@ -1167,6 +1167,18 @@ int emcTrajSetJerk(double jerk) return retval; } +// The axes that return last after jogs while paused, [TRAJ]PAUSE_RETURN_LAST +int emcTrajSetPauseReturnLast(unsigned axis_mask) +{ + emcmotCommand.command = EMCMOT_SET_PAUSE_RETURN_LAST; + emcmotCommand.flags = (int)axis_mask; + + int retval = usrmotWriteEmcmotCommand(&emcmotCommand); + + log_debug(EMC_DEBUG_CONFIG, "{}({:#x}) returned {}\n", __FUNCTION__, axis_mask, retval); + return retval; +} + int emcTrajPlannerType(int type) { emcmotCommand.command = EMCMOT_SET_PLANNER_TYPE; @@ -2148,6 +2160,9 @@ int emcMotionUpdate(EMC_MOTION_STAT * stat) } stat->jogging_active = emcmotStatus.jogging_active; + stat->pause_offset = emcmotStatus.pause_offset; + stat->pause_jog_ok = emcmotStatus.pause_jog_ok; + stat->pause_returning = emcmotStatus.pause_returning; stat->homing_active = emcmotStatus.homing_active; stat->numExtraJoints = emcmotStatus.numExtraJoints; diff --git a/src/emc/usr_intf/axis/extensions/emcmodule.cc b/src/emc/usr_intf/axis/extensions/emcmodule.cc index bdf297c286e..0e9463801f9 100644 --- a/src/emc/usr_intf/axis/extensions/emcmodule.cc +++ b/src/emc/usr_intf/axis/extensions/emcmodule.cc @@ -1153,6 +1153,8 @@ static PyMemberDef Stat_members[] = { { "interpreter_errcode", T_INT, O(task.interpreter_errcode), READONLY, NULL}, { "optional_stop", T_BOOL, O(task.optional_stop_state), READONLY, NULL}, { "block_delete", T_BOOL, O(task.block_delete_state), READONLY, NULL}, + { "pause_jog_ok", T_BOOL, O(motion.pause_jog_ok), READONLY, NULL}, + { "pause_returning", T_BOOL, O(motion.pause_returning), READONLY, NULL}, { "task_paused", T_INT, O(task.task_paused), READONLY, NULL}, { "input_timeout", T_BOOL, O(task.input_timeout), READONLY, NULL}, { "rotation_xy", T_DOUBLE, O(task.rotation_xy), READONLY, NULL}, @@ -1305,6 +1307,10 @@ static PyObject *Stat_actual(pyStatChannel *s, void *) { return pose(s->status.motion.traj.actualPosition); } +static PyObject *Stat_pause_offset(pyStatChannel *s, void *) { + return pose(s->status.motion.pause_offset); +} + static PyObject *Stat_joint_position(pyStatChannel *s, void *) { PyObject *res = PyTuple_New(EMCMOT_MAX_JOINTS); for(int i=0; imotion.traj.mode == EMC_TRAJ_MODE::TELEOP) ) || ( (jjogmode == JOGTELEOP ) - && (emcStatus->motion.traj.mode != EMC_TRAJ_MODE::TELEOP) ) + && (emcStatus->motion.traj.mode != EMC_TRAJ_MODE::TELEOP) + && !emcStatus->motion.pause_jog_ok ) ) { return -1; } @@ -543,7 +544,8 @@ int sendJogCont(int ja, int jjogmode, double speed) if ( ( (jjogmode == JOGJOINT) && (emcStatus->motion.traj.mode == EMC_TRAJ_MODE::TELEOP) ) || ( (jjogmode == JOGTELEOP ) - && (emcStatus->motion.traj.mode != EMC_TRAJ_MODE::TELEOP) ) + && (emcStatus->motion.traj.mode != EMC_TRAJ_MODE::TELEOP) + && !emcStatus->motion.pause_jog_ok ) ) { return -1; } @@ -571,7 +573,8 @@ int sendJogIncr(int ja, int jjogmode, double speed, double incr) if ( ( (jjogmode == JOGJOINT) && ( emcStatus->motion.traj.mode == EMC_TRAJ_MODE::TELEOP) ) || ( (jjogmode == JOGTELEOP ) - && ( emcStatus->motion.traj.mode != EMC_TRAJ_MODE::TELEOP) ) + && ( emcStatus->motion.traj.mode != EMC_TRAJ_MODE::TELEOP) + && !emcStatus->motion.pause_jog_ok ) ) { return -1; } diff --git a/tests/interp/m98m99/12-M99-endless-main-program/expected.motion-logger b/tests/interp/m98m99/12-M99-endless-main-program/expected.motion-logger index 6a98f7318c1..252da1de385 100644 --- a/tests/interp/m98m99/12-M99-endless-main-program/expected.motion-logger +++ b/tests/interp/m98m99/12-M99-endless-main-program/expected.motion-logger @@ -4,6 +4,7 @@ SET_VEL vel=0, ini_maxvel=1.2 SET_VEL_LIMIT vel=4 SET_ACC acc=1e+99 SET_JERK jerk=1e+09 +SET_PAUSE_RETURN_LAST mask=0x4 SET_PLANNER_TYPE planner_type=0 SET_SCURVE_PEAK_SCALE scale=1 SETUP_ARC_BLENDS diff --git a/tests/jog-while-paused/.gitignore b/tests/jog-while-paused/.gitignore new file mode 100644 index 00000000000..57585c75340 --- /dev/null +++ b/tests/jog-while-paused/.gitignore @@ -0,0 +1,2 @@ +sim.var +sim.var.bak diff --git a/tests/jog-while-paused/checkresult b/tests/jog-while-paused/checkresult new file mode 100755 index 00000000000..24dc9aa53e3 --- /dev/null +++ b/tests/jog-while-paused/checkresult @@ -0,0 +1,2 @@ +#!/bin/sh +exit 0 # test failure is indicated by test.sh exit value diff --git a/tests/jog-while-paused/m0.ngc b/tests/jog-while-paused/m0.ngc new file mode 100644 index 00000000000..f0a1bac706e --- /dev/null +++ b/tests/jog-while-paused/m0.ngc @@ -0,0 +1,5 @@ +G21 G90 G17 +G1 F1200 X10 +M0 +G1 X0 +M2 diff --git a/tests/jog-while-paused/program.ngc b/tests/jog-while-paused/program.ngc new file mode 100644 index 00000000000..ba981850341 --- /dev/null +++ b/tests/jog-while-paused/program.ngc @@ -0,0 +1,9 @@ +G21 G90 G17 +S1000 M3 +M8 +G1 F600 X20 +G1 Y20 +G1 X0 +G1 Y0 +M5 M9 +M2 diff --git a/tests/jog-while-paused/sim.hal b/tests/jog-while-paused/sim.hal new file mode 100644 index 00000000000..5779ccc98f6 --- /dev/null +++ b/tests/jog-while-paused/sim.hal @@ -0,0 +1,16 @@ +loadrt [KINS]KINEMATICS +loadrt [EMCMOT]EMCMOT 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 + +# a wheel on Y: one count is 0.01 +setp axis.y.jog-scale 0.01 +setp axis.y.jog-vel-mode 0 diff --git a/tests/jog-while-paused/test-ui.py b/tests/jog-while-paused/test-ui.py new file mode 100755 index 00000000000..8ab7709f309 --- /dev/null +++ b/tests/jog-while-paused/test-ui.py @@ -0,0 +1,223 @@ +#!/usr/bin/env python3 +# Jogs while a program is paused: axes move off the paused position, and +# resume brings them back (the other axes first, then Z) with the spindle +# and coolant as they were, before the program goes on. + +import math +import os +import sys +import time + +import hal +import linuxcnc + +c = linuxcnc.command() +s = linuxcnc.stat() +e = linuxcnc.error_channel() +h = hal.component("test-ui") +h.ready() + +fails = 0 + + +def check(name, ok, detail=''): + global fails + print('%s: %s %s' % ('ok' if ok else 'FAIL', name, detail), flush=True) + if not ok: + fails += 1 + + +def wait(fn, timeout=5.0): + end = time.time() + timeout + while time.time() < end: + s.poll() + if fn(): + return True + time.sleep(0.005) + s.poll() + return fn() + + +def errors(): + msgs = [] + while True: + m = e.poll() + if not m: + return msgs + msgs.append(m[1]) + + +def pos(): + return s.actual_position[:3] + + +def near(a, b, tol=1e-6): + return all(abs(x - y) <= tol for x, y in zip(a, b)) + + +def idle(): + return s.interp_state == linuxcnc.INTERP_IDLE and s.queue == 0 and hal.get_value('halui.mode.is-manual') + + +def run_and_pause(prog, at_x): + c.program_open(os.path.abspath(prog)) + c.wait_complete() + c.auto(linuxcnc.AUTO_RUN, 0) + if not wait(lambda: s.actual_position[0] >= at_x, 10): + check('program reached X%g' % at_x, False, pos()) + c.auto(linuxcnc.AUTO_PAUSE) + c.wait_complete() + return wait(lambda: s.pause_jog_ok, 2) + + +wait(lambda: s.task_state != 0, 10) +c.state(linuxcnc.STATE_ESTOP_RESET) +c.state(linuxcnc.STATE_ON) +c.home(-1) +c.wait_complete() +wait(lambda: all(s.homed[:3]), 10) +c.teleop_enable(1) +c.wait_complete() +c.mdi('G0 X0 Y0 Z0') +wait(idle) +errors() + +# --- pause in the middle of a G1, jog three axes three ways +check('paused and ready to jog', run_and_pause('program.ngc', 5.0)) +p = pos() +print('paused at', p, flush=True) +check('spindle and flood on at the pause', s.spindle[0]['direction'] == 1 and s.flood, (s.spindle[0]['direction'], s.flood)) + +c.jog(linuxcnc.JOG_INCREMENT, False, 2, 20, 5.0) # Z +5 +check('incremental Z jog', wait(lambda: near(pos(), (p[0], p[1], p[2] + 5))), pos()) +c.jog(linuxcnc.JOG_CONTINUOUS, False, 0, 10) # X +, 10 mm/s +time.sleep(0.3) +c.jog(linuxcnc.JOG_STOP, False, 0) +check('continuous X jog stopped', wait(lambda: s.current_vel == 0 and not s.motion.jogging_active + if hasattr(s, 'motion') else not hal.get_value('motion.jog-is-active')), pos()) +dx = pos()[0] - p[0] +check('continuous X jog moved', 1.0 < dx < 5.0, dx) +hal.set_p('axis.y.jog-enable', '1') +hal.set_p('axis.y.jog-counts', '200') # Y +2 +check('wheel Y jog', wait(lambda: near(pos(), (p[0] + dx, p[1] + 2, p[2] + 5))), pos()) +s.poll() +check('pause offset reported', near(s.pause_offset[:3], (dx, 2, 5)), s.pause_offset[:3]) +check('still paused', s.paused and s.interp_state == linuxcnc.INTERP_PAUSED) +check('no errors from the jogs', not errors()) + +# --- joint jogs and reverse run are refused while jogged away +c.jog(linuxcnc.JOG_INCREMENT, True, 0, 10, 1) +c.wait_complete() +time.sleep(0.1) +msgs = errors() +check('joint jog refused while paused', any('jog a joint' in m for m in msgs), msgs) +c.auto(linuxcnc.AUTO_REVERSE) +c.wait_complete() +time.sleep(0.1) +msgs = errors() +check('reverse refused while jogged away', any('reverse' in m for m in msgs), msgs) + +# --- the operator stops spindle and coolant; resume puts them back and +# waits for the spindle to be at speed before moving +c.spindle(linuxcnc.SPINDLE_OFF) +c.flood(linuxcnc.FLOOD_OFF) +c.wait_complete() +check('spindle and flood off', wait(lambda: s.spindle[0]['direction'] == 0 and not s.flood)) +hal.set_p('spindle.0.at-speed', '0') +off = pos() +c.auto(linuxcnc.AUTO_RESUME) +c.wait_complete() +check('resume restores the spindle', wait(lambda: s.spindle[0]['direction'] == 1 and s.spindle[0]['speed'] == 1000, 1), s.spindle[0]['speed']) +check('resume restores the flood', wait(lambda: s.flood, 1)) +check('returning', wait(lambda: s.pause_returning, 1)) +time.sleep(0.5) +s.poll() +check('no move until the spindle is at speed', near(pos(), off), (pos(), off)) + +# --- at speed: XY back in a straight line with Z up, then Z down, then on. +# The commanded offsets (pause_offset) show the path; actual_position lags +# them by the joint interpolation. +offsets = [] +hal.set_p('spindle.0.at-speed', '1') +end = time.time() + 5 +while time.time() < end: + s.poll() + offsets.append(s.pause_offset[:3]) + if not s.pause_returning: + break + time.sleep(0.002) +s.poll() +check('back at the paused position: offsets exactly zero', offsets and offsets[-1] == (0.0, 0.0, 0.0), offsets[-1:]) +z_early = [o for o in offsets if abs(o[2] - 5) > 1e-6 and (abs(o[0]) > 0 or abs(o[1]) > 0)] +check('Z stays up until XY are back', not z_early, z_early[:3]) +off_line = [o for o in offsets if abs(o[0] * 2 - o[1] * dx) > 1e-6] +check('XY return is a straight line', not off_line, off_line[:3]) +check('program finished at the end point', wait(lambda: idle(), 20), pos()) +check('program end position', near(pos()[:2], (0, 0), 1e-6), pos()) +check('no errors from the resume', not errors()) + +# --- abort while jogged away: no jump, stay there +check('paused again', run_and_pause('program.ngc', 5.0)) +p = pos() +c.jog(linuxcnc.JOG_INCREMENT, False, 2, 20, 3.0) +check('Z jog before abort', wait(lambda: near(pos(), (p[0], p[1], p[2] + 3))), pos()) +c.abort() +c.wait_complete() +check('idle after abort', wait(idle)) +time.sleep(0.2) +s.poll() +check('abort keeps the jogged position', near(pos(), (p[0], p[1], p[2] + 3)), pos()) +check('pause offset gone after abort', near(s.pause_offset[:3], (0, 0, 0), 0), s.pause_offset[:3]) +c.mdi('G0 X1') +check('MDI after the abort', wait(lambda: idle() and near(pos(), (1, p[1], p[2] + 3))), pos()) +errors() + +# --- soft limits hold during a jog while paused (X max is 30) +check('paused for the limit test', run_and_pause('program.ngc', 5.0)) +c.jog(linuxcnc.JOG_CONTINUOUS, False, 0, 40) +time.sleep(1.5) +s.poll() +check('X stops at its soft limit', s.actual_position[0] <= 30 + 1e-9 and s.actual_position[0] > 29, s.actual_position[0]) +c.jog(linuxcnc.JOG_STOP, False, 0) +c.abort() +c.wait_complete() +wait(idle) +c.mdi('G0 X0 Y0 Z0') +wait(idle) +errors() + +# --- step with an offset returns first, then steps +check('paused for the step test', run_and_pause('program.ngc', 5.0)) +p = pos() +c.jog(linuxcnc.JOG_INCREMENT, False, 1, 20, 4.0) +wait(lambda: near(pos(), (p[0], p[1] + 4, p[2]))) +c.auto(linuxcnc.AUTO_STEP) +c.wait_complete() +check('step brings the offset back', wait(lambda: near(s.pause_offset[:3], (0, 0, 0), 0), 5), s.pause_offset[:3]) +check('step moved on along the program', wait(lambda: s.actual_position[0] > p[0] + 1e-3 or s.actual_position[1] > p[1] + 1e-3, 5), pos()) +c.abort() +c.wait_complete() +wait(idle) +c.mdi('G0 X0 Y0 Z0') +wait(idle) +errors() + +# --- an M0 stop is a pause too +c.program_open(os.path.abspath('m0.ngc')) +c.wait_complete() +c.auto(linuxcnc.AUTO_RUN, 0) +check('stopped at M0', wait(lambda: s.paused and s.pause_jog_ok, 10), pos()) +p = pos() +c.jog(linuxcnc.JOG_INCREMENT, False, 2, 20, 2.0) +wait(lambda: near(pos(), (p[0], p[1], p[2] + 2))) +c.auto(linuxcnc.AUTO_RESUME) +c.wait_complete() +check('M0: back and finished', wait(lambda: idle() and near(pos(), (0, p[1], p[2])), 10), pos()) + +msgs = errors() +check('no unexpected errors', not msgs, msgs) + +c.state(linuxcnc.STATE_OFF) +c.wait_complete() +print('%d failures' % fails, flush=True) +os._exit(1 if fails else 0) diff --git a/tests/jog-while-paused/test.ini b/tests/jog-while-paused/test.ini new file mode 100644 index 00000000000..26aa8e03958 --- /dev/null +++ b/tests/jog-while-paused/test.ini @@ -0,0 +1,82 @@ +[EMC] +VERSION = 1.1 +DEBUG = 0 + +[DISPLAY] +DISPLAY = ./test-ui.py + +[RS274NGC] +PARAMETER_FILE = sim.var + +[EMCMOT] +EMCMOT = motmod +COMM_TIMEOUT = 4.0 +SERVO_PERIOD = 1000000 + +[TASK] +TASK = milltask +CYCLE_TIME = 0.001 + +[HAL] +HALFILE = sim.hal + +[TRAJ] +COORDINATES = X Y Z +LINEAR_UNITS = mm +ANGULAR_UNITS = degree +MAX_LINEAR_VELOCITY = 40 + +[EMCIO] +TOOL_TABLE = tool.tbl + +[KINS] +KINEMATICS = trivkins +JOINTS = 3 + +[AXIS_X] +MIN_LIMIT = -100.0 +MAX_LIMIT = 30.0 +MAX_VELOCITY = 40 +MAX_ACCELERATION = 1000.0 + +[JOINT_0] +TYPE = LINEAR +HOME_SEQUENCE = 0 +MAX_VELOCITY = 40 +MAX_ACCELERATION = 1000.0 +MIN_LIMIT = -100.0 +MAX_LIMIT = 30.0 +FERROR = 1 +MIN_FERROR = 1 + +[AXIS_Y] +MIN_LIMIT = -100.0 +MAX_LIMIT = 100.0 +MAX_VELOCITY = 40 +MAX_ACCELERATION = 1000.0 + +[JOINT_1] +TYPE = LINEAR +HOME_SEQUENCE = 0 +MAX_VELOCITY = 40 +MAX_ACCELERATION = 1000.0 +MIN_LIMIT = -100.0 +MAX_LIMIT = 100.0 +FERROR = 1 +MIN_FERROR = 1 + +[AXIS_Z] +MIN_LIMIT = -100.0 +MAX_LIMIT = 100.0 +MAX_VELOCITY = 40 +MAX_ACCELERATION = 1000.0 + +[JOINT_2] +TYPE = LINEAR +HOME_SEQUENCE = 0 +MAX_VELOCITY = 40 +MAX_ACCELERATION = 1000.0 +MIN_LIMIT = -100.0 +MAX_LIMIT = 100.0 +FERROR = 1 +MIN_FERROR = 1 diff --git a/tests/jog-while-paused/test.sh b/tests/jog-while-paused/test.sh new file mode 100755 index 00000000000..972cf4ffcb8 --- /dev/null +++ b/tests/jog-while-paused/test.sh @@ -0,0 +1,3 @@ +#!/bin/bash +rm -f sim.var +linuxcnc -r test.ini diff --git a/tests/jog-while-paused/tool.tbl b/tests/jog-while-paused/tool.tbl new file mode 100644 index 00000000000..aee1343f663 --- /dev/null +++ b/tests/jog-while-paused/tool.tbl @@ -0,0 +1 @@ +T1 P1 Z0.5 ;tool 1 diff --git a/tests/motion-logger/basic/expected.builtin-startup.in b/tests/motion-logger/basic/expected.builtin-startup.in index 0a36ebc4e40..0818431c052 100644 --- a/tests/motion-logger/basic/expected.builtin-startup.in +++ b/tests/motion-logger/basic/expected.builtin-startup.in @@ -4,6 +4,7 @@ SET_VEL vel=0, ini_maxvel=1.2 SET_VEL_LIMIT vel=4 SET_ACC acc=1e+99 SET_JERK jerk=1e+09 +SET_PAUSE_RETURN_LAST mask=0x4 SET_PLANNER_TYPE planner_type=0 SET_SCURVE_PEAK_SCALE scale=1 SETUP_ARC_BLENDS diff --git a/tests/motion-logger/mountaindew/expected.motion-logger b/tests/motion-logger/mountaindew/expected.motion-logger index 132f381701b..95321cb72b9 100644 --- a/tests/motion-logger/mountaindew/expected.motion-logger +++ b/tests/motion-logger/mountaindew/expected.motion-logger @@ -4,6 +4,7 @@ SET_VEL vel=0, ini_maxvel=120 SET_VEL_LIMIT vel=400 SET_ACC acc=1e+99 SET_JERK jerk=1e+09 +SET_PAUSE_RETURN_LAST mask=0x4 SET_PLANNER_TYPE planner_type=0 SET_SCURVE_PEAK_SCALE scale=1 SETUP_ARC_BLENDS diff --git a/tests/motion-logger/startup-gcode-abort/expected.motion-logger.in b/tests/motion-logger/startup-gcode-abort/expected.motion-logger.in index 8bef6b8b1a0..7d14e152e0c 100644 --- a/tests/motion-logger/startup-gcode-abort/expected.motion-logger.in +++ b/tests/motion-logger/startup-gcode-abort/expected.motion-logger.in @@ -9,6 +9,7 @@ SET_VEL vel=0, ini_maxvel=1.2 SET_VEL_LIMIT vel=4 SET_ACC acc=1e+99 SET_JERK jerk=1e+09 +SET_PAUSE_RETURN_LAST mask=0x4 SET_PLANNER_TYPE planner_type=0 SET_SCURVE_PEAK_SCALE scale=1 SETUP_ARC_BLENDS From e9f2bd4667d592f858966bea78fadc2699355d6a Mon Sep 17 00:00:00 2001 From: Rene Hopf Date: Fri, 16 Oct 2026 21:04:26 +0200 Subject: [PATCH 16/21] user interfaces: no wait after a mode change mode() sends nothing to task any more; it sets the page the user interface shows. The wait_complete() after it waited on whatever command came before, and while a program runs or is paused task does not report DONE, so each one sat out its timeout: AXIS hung for 5 s on a spindle button while paused (ensure_mode()). Remove the wait after every mode() call in the user interfaces, their libraries and the sample configs: AXIS, gmoccapy, gscreen and the silverdragon skin, touchy, pyui, GStat, the gladevcp and qtvcp actions, the gladevcp offset page and probe panels, the 3pcenter panel. The waits after teleop_enable() that follow some of them stay. --- configs/sim/axis/gladevcp/probe.py | 1 - .../gmoccapy/lathe_configs/lathehandler.py | 1 - .../qtvcp_experimental/lathehandler.py | 1 - lib/python/common/hal_glib.py | 2 -- .../gtk_little_probe/gtk_little_probe.py | 23 --------------- .../gtk_verser_probe/gtk_verser_probe.py | 23 --------------- lib/python/gladevcp/gtk_action.py | 1 - lib/python/gladevcp/hal_actions.py | 1 - lib/python/gladevcp/offsetpage_widget.py | 9 ------ lib/python/qtvcp/qt_action.py | 1 - .../silverdragon/silverdragon_handler.py | 20 ------------- .../qtvcp/panels/3pcenter/3pcenter_handler.py | 2 -- src/emc/usr_intf/axis/scripts/axis.py | 6 ++-- src/emc/usr_intf/gmoccapy/gmoccapy.py | 28 ------------------- src/emc/usr_intf/gscreen/emc_interface.py | 5 ---- src/emc/usr_intf/gscreen/mdi.py | 12 -------- src/emc/usr_intf/pyui/commands.py | 6 ---- src/emc/usr_intf/touchy/emc_interface.py | 1 - src/emc/usr_intf/touchy/mdi.py | 1 - 19 files changed, 3 insertions(+), 141 deletions(-) diff --git a/configs/sim/axis/gladevcp/probe.py b/configs/sim/axis/gladevcp/probe.py index fcca3592815..089dedd378b 100644 --- a/configs/sim/axis/gladevcp/probe.py +++ b/configs/sim/axis/gladevcp/probe.py @@ -65,7 +65,6 @@ def ensure_mode(self,m, *p): if self.s.task_mode == m or self.s.task_mode in p: return True if self.running(do_poll=False): return False self.c.mode(m) - self.c.wait_complete() return True def active_codes(self): diff --git a/configs/sim/gmoccapy/lathe_configs/lathehandler.py b/configs/sim/gmoccapy/lathe_configs/lathehandler.py index b8ae574d4b0..46e2bd403a9 100755 --- a/configs/sim/gmoccapy/lathe_configs/lathehandler.py +++ b/configs/sim/gmoccapy/lathe_configs/lathehandler.py @@ -198,7 +198,6 @@ def cycle_pin(self, pin, data = None): if c is not None: self.cmd.abort() self.cmd.mode(linuxcnc.MODE_MDI) - self.cmd.wait_complete() c.emit('clicked') print(c.get_name(), "clicked") diff --git a/configs/sim/qtvcp_screens/qtvcp_experimental/lathehandler.py b/configs/sim/qtvcp_screens/qtvcp_experimental/lathehandler.py index 4997894099e..eedbc15047c 100644 --- a/configs/sim/qtvcp_screens/qtvcp_experimental/lathehandler.py +++ b/configs/sim/qtvcp_screens/qtvcp_experimental/lathehandler.py @@ -188,7 +188,6 @@ def cycle_pin(self, pin, data = None): if c.name.partition('.')[2] == 'action': self.cmd.abort() self.cmd.mode(linuxcnc.MODE_MANUAL) - self.cmd.wait_complete() c.emit('clicked') def gash(self, obj, data = None): diff --git a/lib/python/common/hal_glib.py b/lib/python/common/hal_glib.py index 6227a3dae3b..807067bf3e9 100644 --- a/lib/python/common/hal_glib.py +++ b/lib/python/common/hal_glib.py @@ -1381,7 +1381,6 @@ def set_tool_touchoff(self,tool,axis,value): if self.stat.task_mode != linuxcnc.MODE_MDI: premode = self.stat.task_mode self.cmd.mode(linuxcnc.MODE_MDI) - self.cmd.wait_complete() self.cmd.mdi(m) self.cmd.wait_complete() self.cmd.mdi("g43") @@ -1396,7 +1395,6 @@ def set_axis_origin(self,axis,value): if self.stat.task_mode != linuxcnc.MODE_MDI: premode = self.stat.task_mode self.cmd.mode(linuxcnc.MODE_MDI) - self.cmd.wait_complete() self.cmd.mdi(m) self.cmd.wait_complete() if premode: diff --git a/lib/python/gladevcp/builtin-panels/gtk_little_probe/gtk_little_probe.py b/lib/python/gladevcp/builtin-panels/gtk_little_probe/gtk_little_probe.py index 7f790cf2d7b..b23f59427f1 100644 --- a/lib/python/gladevcp/builtin-panels/gtk_little_probe/gtk_little_probe.py +++ b/lib/python/gladevcp/builtin-panels/gtk_little_probe/gtk_little_probe.py @@ -626,21 +626,18 @@ def lenght_y(self, data = None): def on_btn1_set_x_released(self, gtkbutton, data = None): self.prefs.putpref( "ps_offs_x", self.spbtn_offs_x.get_value(), float ) self.command.mode( linuxcnc.MODE_MDI ) - self.command.wait_complete() self.command.mdi( "G10 L20 P0 X%f" % self.spbtn_offs_x.get_value() ) time.sleep(1) def on_btn1_set_y_released(self, gtkbutton, data = None): self.prefs.putpref( "ps_offs_y", self.spbtn_offs_y.get_value(), float ) self.command.mode( linuxcnc.MODE_MDI ) - self.command.wait_complete() self.command.mdi( "G10 L20 P0 Y%f" % self.spbtn_offs_y.get_value() ) time.sleep(1) def on_btn1_set_z_released(self, gtkbutton, data = None): self.prefs.putpref( "ps_offs_z", self.spbtn_offs_z.get_value(), float ) self.command.mode( linuxcnc.MODE_MDI ) - self.command.wait_complete() self.command.mdi( "G10 L20 P0 Z%f" % self.spbtn_offs_z.get_value() ) time.sleep(1) @@ -648,7 +645,6 @@ def on_btn1_set_angle_released(self, gtkbutton, data = None): self.prefs.putpref( "ps_offs_angle", self.spbtn_offs_angle.get_value(), float ) self.lb_probe_a.set_text( "%.3f" % self.spbtn_offs_angle.get_value()) self.command.mode( linuxcnc.MODE_MDI ) - self.command.wait_complete() s="G10 L2 P0" if self.chk_set_zero.get_active() : s += " X%.4f"%self.spbtn_offs_x.get_value() @@ -672,7 +668,6 @@ def on_btn1_set_angle_released(self, gtkbutton, data = None): # Down def on_down_released(self, gtkbutton, data = None): self.command.mode( linuxcnc.MODE_MDI ) - self.command.wait_complete() # Start gtk_probe_down.ngc if self.ocode ("O call") == -1: return @@ -686,7 +681,6 @@ def on_down_released(self, gtkbutton, data = None): # X+ def on_xp_released(self, gtkbutton, data = None): self.command.mode( linuxcnc.MODE_MDI ) - self.command.wait_complete() # move X - xy_clearance s="""G91 G1 X-%f @@ -717,7 +711,6 @@ def on_xp_released(self, gtkbutton, data = None): # Y+ def on_yp_released(self, gtkbutton, data = None): self.command.mode( linuxcnc.MODE_MDI ) - self.command.wait_complete() # move Y - xy_clearance s="""G91 G1 Y-%f @@ -748,7 +741,6 @@ def on_yp_released(self, gtkbutton, data = None): # X- def on_xm_released(self, gtkbutton, data = None): self.command.mode( linuxcnc.MODE_MDI ) - self.command.wait_complete() # move X + xy_clearance s="""G91 G1 X%f @@ -779,7 +771,6 @@ def on_xm_released(self, gtkbutton, data = None): # Y- def on_ym_released(self, gtkbutton, data = None): self.command.mode( linuxcnc.MODE_MDI ) - self.command.wait_complete() # move Y + xy_clearance s="""G91 G1 Y%f @@ -812,7 +803,6 @@ def on_ym_released(self, gtkbutton, data = None): # X+Y+ def on_xpyp_released(self, gtkbutton, data = None): self.command.mode( linuxcnc.MODE_MDI ) - self.command.wait_complete() # move X - xy_clearance Y + edge_lenght s="""G91 G1 X-%f Y%f @@ -865,7 +855,6 @@ def on_xpyp_released(self, gtkbutton, data = None): # X+Y- def on_xpym_released(self, gtkbutton, data = None): self.command.mode( linuxcnc.MODE_MDI ) - self.command.wait_complete() # move X - xy_clearance Y + edge_lenght s="""G91 G1 X-%f Y-%f @@ -917,7 +906,6 @@ def on_xpym_released(self, gtkbutton, data = None): # X-Y+ def on_xmyp_released(self, gtkbutton, data = None): self.command.mode( linuxcnc.MODE_MDI ) - self.command.wait_complete() # move X + xy_clearance Y + edge_lenght s="""G91 G1 X%f Y%f @@ -970,7 +958,6 @@ def on_xmyp_released(self, gtkbutton, data = None): # X-Y- def on_xmym_released(self, gtkbutton, data = None): self.command.mode( linuxcnc.MODE_MDI ) - self.command.wait_complete() # move X + xy_clearance Y - edge_lenght s="""G91 G1 X%f Y-%f @@ -1023,7 +1010,6 @@ def on_xmym_released(self, gtkbutton, data = None): # Center X+ X- Y+ Y- def on_xy_center_released(self, gtkbutton, data = None): self.command.mode( linuxcnc.MODE_MDI ) - self.command.wait_complete() # move X - edge_lenght- xy_clearance s="""G91 G1 X-%f @@ -1137,7 +1123,6 @@ def on_xy_center_released(self, gtkbutton, data = None): # X+Y+ def on_xpyp1_released(self, gtkbutton, data = None): self.command.mode( linuxcnc.MODE_MDI ) - self.command.wait_complete() # move Y - edge_lenght X - xy_clearance s="""G91 G1 X-%f Y-%f @@ -1185,7 +1170,6 @@ def on_xpyp1_released(self, gtkbutton, data = None): # X+Y- def on_xpym1_released(self, gtkbutton, data = None): self.command.mode( linuxcnc.MODE_MDI ) - self.command.wait_complete() # move Y + edge_lenght X - xy_clearance s="""G91 G1 X-%f Y%f @@ -1233,7 +1217,6 @@ def on_xpym1_released(self, gtkbutton, data = None): # X-Y+ def on_xmyp1_released(self, gtkbutton, data = None): self.command.mode( linuxcnc.MODE_MDI ) - self.command.wait_complete() # move Y - edge_lenght X + xy_clearance s="""G91 G1 X%f Y-%f @@ -1282,7 +1265,6 @@ def on_xmyp1_released(self, gtkbutton, data = None): # X-Y- def on_xmym1_released(self, gtkbutton, data = None): self.command.mode( linuxcnc.MODE_MDI ) - self.command.wait_complete() # move Y + edge_lenght X + xy_clearance s="""G91 G1 X%f Y%f @@ -1330,7 +1312,6 @@ def on_xmym1_released(self, gtkbutton, data = None): # Hole Xin- Xin+ Yin- Yin+ def on_xy_hole_released(self, gtkbutton, data = None): self.command.mode( linuxcnc.MODE_MDI ) - self.command.wait_complete() if self.z_clearance_down() == -1: return # move X - edge_lenght Y + xy_clearance @@ -1428,7 +1409,6 @@ def on_angle_yp_released(self, gtkbutton, data = None): self.stat.poll() xstart=self.stat.position[0]-self.stat.g5x_offset[0] - self.stat.g92_offset[0] - self.stat.tool_offset[0] self.command.mode( linuxcnc.MODE_MDI ) - self.command.wait_complete() # move Y - xy_clearance s="""G91 G1 Y-%f @@ -1477,7 +1457,6 @@ def on_angle_ym_released(self, gtkbutton, data = None): self.stat.poll() xstart=self.stat.position[0]-self.stat.g5x_offset[0] - self.stat.g92_offset[0] - self.stat.tool_offset[0] self.command.mode( linuxcnc.MODE_MDI ) - self.command.wait_complete() # move Y + xy_clearance s="""G91 G1 Y%f @@ -1525,7 +1504,6 @@ def on_angle_xp_released(self, gtkbutton, data = None): self.stat.poll() ystart=self.stat.position[1]-self.stat.g5x_offset[1] - self.stat.g92_offset[1] - self.stat.tool_offset[1] self.command.mode( linuxcnc.MODE_MDI ) - self.command.wait_complete() # move X - xy_clearance s="""G91 G1 X-%f @@ -1573,7 +1551,6 @@ def on_angle_xm_released(self, gtkbutton, data = None): self.stat.poll() ystart=self.stat.position[1]-self.stat.g5x_offset[1] - self.stat.g92_offset[1] - self.stat.tool_offset[1] self.command.mode( linuxcnc.MODE_MDI ) - self.command.wait_complete() # move X + xy_clearance s="""G91 G1 X%f diff --git a/lib/python/gladevcp/builtin-panels/gtk_verser_probe/gtk_verser_probe.py b/lib/python/gladevcp/builtin-panels/gtk_verser_probe/gtk_verser_probe.py index b538e0b26d2..9f6aa1287a7 100644 --- a/lib/python/gladevcp/builtin-panels/gtk_verser_probe/gtk_verser_probe.py +++ b/lib/python/gladevcp/builtin-panels/gtk_verser_probe/gtk_verser_probe.py @@ -627,21 +627,18 @@ def lenght_y(self, data = None): def on_btn1_set_x_released(self, gtkbutton, data = None): self.prefs.putpref( "ps_offs_x", self.spbtn_offs_x.get_value(), float ) self.command.mode( linuxcnc.MODE_MDI ) - self.command.wait_complete() self.command.mdi( "G10 L20 P0 X%f" % self.spbtn_offs_x.get_value() ) time.sleep(1) def on_btn1_set_y_released(self, gtkbutton, data = None): self.prefs.putpref( "ps_offs_y", self.spbtn_offs_y.get_value(), float ) self.command.mode( linuxcnc.MODE_MDI ) - self.command.wait_complete() self.command.mdi( "G10 L20 P0 Y%f" % self.spbtn_offs_y.get_value() ) time.sleep(1) def on_btn1_set_z_released(self, gtkbutton, data = None): self.prefs.putpref( "ps_offs_z", self.spbtn_offs_z.get_value(), float ) self.command.mode( linuxcnc.MODE_MDI ) - self.command.wait_complete() self.command.mdi( "G10 L20 P0 Z%f" % self.spbtn_offs_z.get_value() ) time.sleep(1) @@ -649,7 +646,6 @@ def on_btn1_set_angle_released(self, gtkbutton, data = None): self.prefs.putpref( "ps_offs_angle", self.spbtn_offs_angle.get_value(), float ) self.lb_probe_a.set_text( "%.3f" % self.spbtn_offs_angle.get_value()) self.command.mode( linuxcnc.MODE_MDI ) - self.command.wait_complete() s="G10 L2 P0" if self.chk_set_zero.get_active() : s += " X%.4f"%self.spbtn_offs_x.get_value() @@ -673,7 +669,6 @@ def on_btn1_set_angle_released(self, gtkbutton, data = None): # Down def on_down_released(self, gtkbutton, data = None): self.command.mode( linuxcnc.MODE_MDI ) - self.command.wait_complete() # Start gtk_probe_down.ngc if self.ocode ("O call") == -1: return @@ -684,7 +679,6 @@ def on_down_released(self, gtkbutton, data = None): # X+ def on_xp_released(self, gtkbutton, data = None): self.command.mode( linuxcnc.MODE_MDI ) - self.command.wait_complete() # move X - xy_clearance s="""G91 G1 X-%f @@ -713,7 +707,6 @@ def on_xp_released(self, gtkbutton, data = None): # Y+ def on_yp_released(self, gtkbutton, data = None): self.command.mode( linuxcnc.MODE_MDI ) - self.command.wait_complete() # move Y - xy_clearance s="""G91 G1 Y-%f @@ -742,7 +735,6 @@ def on_yp_released(self, gtkbutton, data = None): # X- def on_xm_released(self, gtkbutton, data = None): self.command.mode( linuxcnc.MODE_MDI ) - self.command.wait_complete() # move X + xy_clearance s="""G91 G1 X%f @@ -771,7 +763,6 @@ def on_xm_released(self, gtkbutton, data = None): # Y- def on_ym_released(self, gtkbutton, data = None): self.command.mode( linuxcnc.MODE_MDI ) - self.command.wait_complete() # move Y + xy_clearance s="""G91 G1 Y%f @@ -802,7 +793,6 @@ def on_ym_released(self, gtkbutton, data = None): # X+Y+ def on_xpyp_released(self, gtkbutton, data = None): self.command.mode( linuxcnc.MODE_MDI ) - self.command.wait_complete() # move X - xy_clearance Y + edge_lenght s="""G91 G1 X-%f Y%f @@ -853,7 +843,6 @@ def on_xpyp_released(self, gtkbutton, data = None): # X+Y- def on_xpym_released(self, gtkbutton, data = None): self.command.mode( linuxcnc.MODE_MDI ) - self.command.wait_complete() # move X - xy_clearance Y + edge_lenght s="""G91 G1 X-%f Y-%f @@ -903,7 +892,6 @@ def on_xpym_released(self, gtkbutton, data = None): # X-Y+ def on_xmyp_released(self, gtkbutton, data = None): self.command.mode( linuxcnc.MODE_MDI ) - self.command.wait_complete() # move X + xy_clearance Y + edge_lenght s="""G91 G1 X%f Y%f @@ -954,7 +942,6 @@ def on_xmyp_released(self, gtkbutton, data = None): # X-Y- def on_xmym_released(self, gtkbutton, data = None): self.command.mode( linuxcnc.MODE_MDI ) - self.command.wait_complete() # move X + xy_clearance Y - edge_lenght s="""G91 G1 X%f Y-%f @@ -1005,7 +992,6 @@ def on_xmym_released(self, gtkbutton, data = None): # Center X+ X- Y+ Y- def on_xy_center_released(self, gtkbutton, data = None): self.command.mode( linuxcnc.MODE_MDI ) - self.command.wait_complete() # move X - edge_lenght- xy_clearance s="""G91 G1 X-%f @@ -1117,7 +1103,6 @@ def on_xy_center_released(self, gtkbutton, data = None): # X+Y+ def on_xpyp1_released(self, gtkbutton, data = None): self.command.mode( linuxcnc.MODE_MDI ) - self.command.wait_complete() # move Y - edge_lenght X - xy_clearance s="""G91 G1 X-%f Y-%f @@ -1163,7 +1148,6 @@ def on_xpyp1_released(self, gtkbutton, data = None): # X+Y- def on_xpym1_released(self, gtkbutton, data = None): self.command.mode( linuxcnc.MODE_MDI ) - self.command.wait_complete() # move Y + edge_lenght X - xy_clearance s="""G91 G1 X-%f Y%f @@ -1209,7 +1193,6 @@ def on_xpym1_released(self, gtkbutton, data = None): # X-Y+ def on_xmyp1_released(self, gtkbutton, data = None): self.command.mode( linuxcnc.MODE_MDI ) - self.command.wait_complete() # move Y - edge_lenght X + xy_clearance s="""G91 G1 X%f Y-%f @@ -1256,7 +1239,6 @@ def on_xmyp1_released(self, gtkbutton, data = None): # X-Y- def on_xmym1_released(self, gtkbutton, data = None): self.command.mode( linuxcnc.MODE_MDI ) - self.command.wait_complete() # move Y + edge_lenght X + xy_clearance s="""G91 G1 X%f Y%f @@ -1302,7 +1284,6 @@ def on_xmym1_released(self, gtkbutton, data = None): # Hole Xin- Xin+ Yin- Yin+ def on_xy_hole_released(self, gtkbutton, data = None): self.command.mode( linuxcnc.MODE_MDI ) - self.command.wait_complete() if self.z_clearance_down() == -1: return # move X - edge_lenght Y + xy_clearance @@ -1398,7 +1379,6 @@ def on_angle_yp_released(self, gtkbutton, data = None): self.stat.poll() xstart=self.stat.position[0]-self.stat.g5x_offset[0] - self.stat.g92_offset[0] - self.stat.tool_offset[0] self.command.mode( linuxcnc.MODE_MDI ) - self.command.wait_complete() # move Y - xy_clearance s="""G91 G1 Y-%f @@ -1445,7 +1425,6 @@ def on_angle_ym_released(self, gtkbutton, data = None): self.stat.poll() xstart=self.stat.position[0]-self.stat.g5x_offset[0] - self.stat.g92_offset[0] - self.stat.tool_offset[0] self.command.mode( linuxcnc.MODE_MDI ) - self.command.wait_complete() # move Y + xy_clearance s="""G91 G1 Y%f @@ -1491,7 +1470,6 @@ def on_angle_xp_released(self, gtkbutton, data = None): self.stat.poll() ystart=self.stat.position[1]-self.stat.g5x_offset[1] - self.stat.g92_offset[1] - self.stat.tool_offset[1] self.command.mode( linuxcnc.MODE_MDI ) - self.command.wait_complete() # move X - xy_clearance s="""G91 G1 X-%f @@ -1537,7 +1515,6 @@ def on_angle_xm_released(self, gtkbutton, data = None): self.stat.poll() ystart=self.stat.position[1]-self.stat.g5x_offset[1] - self.stat.g92_offset[1] - self.stat.tool_offset[1] self.command.mode( linuxcnc.MODE_MDI ) - self.command.wait_complete() # move X + xy_clearance s="""G91 G1 X%f diff --git a/lib/python/gladevcp/gtk_action.py b/lib/python/gladevcp/gtk_action.py index 1316c29f2dd..a5981f3a0c7 100644 --- a/lib/python/gladevcp/gtk_action.py +++ b/lib/python/gladevcp/gtk_action.py @@ -674,7 +674,6 @@ def ensure_mode(self, *modes): truth, premode = STATUS.check_for_modes(modes) if truth is False: self.cmd.mode(modes[0]) - self.cmd.wait_complete() return (True, premode) else: return (truth, premode) diff --git a/lib/python/gladevcp/hal_actions.py b/lib/python/gladevcp/hal_actions.py index 2adacc30110..b8f5862fd21 100644 --- a/lib/python/gladevcp/hal_actions.py +++ b/lib/python/gladevcp/hal_actions.py @@ -299,7 +299,6 @@ def ensure_mode(s, c, *modes): if s.task_mode in modes: return True if running(s, do_poll=False): return False c.mode(modes[0]) - c.wait_complete() return True class EMC_Action_Python(_EMC_Action): diff --git a/lib/python/gladevcp/offsetpage_widget.py b/lib/python/gladevcp/offsetpage_widget.py index 11dad262b3a..a295d3e77e8 100755 --- a/lib/python/gladevcp/offsetpage_widget.py +++ b/lib/python/gladevcp/offsetpage_widget.py @@ -445,7 +445,6 @@ def system_to_p(system): if lncnc_running: if self.status.task_mode != self.linuxcnc.MODE_MDI: self.cmd.mode(self.linuxcnc.MODE_MDI) - self.cmd.wait_complete() if row == 0: self.cmd.mdi("G43.1 %s %10.4f" % (self.axisletters[axisnum], qualified)) elif row == 1: @@ -462,9 +461,7 @@ def system_to_p(system): else: self.cmd.mdi("G10 L2 P%d %s %10.4f" % (pnum, self.axisletters[axisnum], qualified)) self.cmd.mode(self.linuxcnc.MODE_MANUAL) - self.cmd.wait_complete() self.cmd.mode(self.linuxcnc.MODE_MDI) - self.cmd.wait_complete() self.gstat.emit('reload-display') except Exception as error: print(_("offsetpage widget error: MDI call error")) @@ -479,12 +476,9 @@ def zero_g92(self, widget): try: if self.status.task_mode != self.linuxcnc.MODE_MDI: self.cmd.mode(self.linuxcnc.MODE_MDI) - self.cmd.wait_complete() self.cmd.mdi("G92.1") self.cmd.mode(self.linuxcnc.MODE_MANUAL) - self.cmd.wait_complete() self.cmd.mode(self.linuxcnc.MODE_MDI) - self.cmd.wait_complete() self.gstat.emit('reload-display') except: print(_("MDI error in offsetpage widget -zero G92")) @@ -496,12 +490,9 @@ def zero_rot(self, widget): try: if self.status.task_mode != self.linuxcnc.MODE_MDI: self.cmd.mode(self.linuxcnc.MODE_MDI) - self.cmd.wait_complete() self.cmd.mdi("G10 L2 P0 R 0") self.cmd.mode(self.linuxcnc.MODE_MANUAL) - self.cmd.wait_complete() self.cmd.mode(self.linuxcnc.MODE_MDI) - self.cmd.wait_complete() self.gstat.emit('reload-display') except: print(_("MDI error in offsetpage widget-zero rotational offset")) diff --git a/lib/python/qtvcp/qt_action.py b/lib/python/qtvcp/qt_action.py index 1ef2912d51b..8c81b08a3d6 100644 --- a/lib/python/qtvcp/qt_action.py +++ b/lib/python/qtvcp/qt_action.py @@ -1037,7 +1037,6 @@ def ensure_mode(self, *modes): truth, premode = STATUS.check_for_modes(modes) if truth is False: self.cmd.mode(modes[0]) - self.cmd.wait_complete() return (True, premode) else: return (truth, premode) diff --git a/share/gscreen/skins/silverdragon/silverdragon_handler.py b/share/gscreen/skins/silverdragon/silverdragon_handler.py index e78c1a1db8c..846e68b16f5 100644 --- a/share/gscreen/skins/silverdragon/silverdragon_handler.py +++ b/share/gscreen/skins/silverdragon/silverdragon_handler.py @@ -187,7 +187,6 @@ def initialize_widgets(self): self.widgets.ntb_main.set_current_page(_NB_PREVIEW) self.gscreen.sensitize_widgets(self.data.sensitive_on_off, False) self.command.mode(linuxcnc.MODE_MANUAL) - self.command.wait_complete() def initialize_preferences(self): self.gscreen.init_general_pref() @@ -426,7 +425,6 @@ def on_rbt_manual_clicked(self, widget): if self.widgets.ntb_main.get_current_page() == _NB_SETUP: return self.command.mode(linuxcnc.MODE_MANUAL) - self.command.wait_complete() def on_rbt_mdi_clicked(self, widget): if self.widgets.ntb_main.get_current_page() == _NB_SETUP: @@ -434,7 +432,6 @@ def on_rbt_mdi_clicked(self, widget): self.widgets.rbt_mdi.set_active(False) else: self.command.mode(linuxcnc.MODE_MDI) - self.command.wait_complete() def on_rbt_auto_clicked(self, widget): if self.widgets.ntb_main.get_current_page() == _NB_SETUP: @@ -442,7 +439,6 @@ def on_rbt_auto_clicked(self, widget): self.widgets.rbt_auto.set_active(False) else: self.command.mode(linuxcnc.MODE_AUTO) - self.command.wait_complete() def on_ntb_main_switch_page(self, widget, tab, index): if self.stat.task_mode == linuxcnc.MODE_AUTO: @@ -511,13 +507,11 @@ def on_zero_axis_clicked(self, widget): self.gscreen.notify(_("ERROR"), _("Unknown axis selected"), ALERT_ICON) return self.command.mode(linuxcnc.MODE_MDI) - self.command.wait_complete() command = "G10 L20 P0 {0}0".format(self.axis_to_ref) self.command.mdi(command) self.command.wait_complete() self.gscreen.reload_plot() self.command.mode(linuxcnc.MODE_MDI) - self.command.wait_complete() self.gscreen.prefs.putpref("offset_axis_{0}".format(self.axis_to_ref), 0, float) def on_ref_axis_clicked(self, widget): @@ -540,7 +534,6 @@ def on_ref_axis_clicked(self, widget): title = "Enter Offset for Axis %s"%self.axis_to_ref self.gscreen.launch_numerical_input(callback, 0, 0, title) self.command.mode(linuxcnc.MODE_MDI) - self.command.wait_complete() def on_tbtn_flood_toggled(self, widget, data=None): if self.stat.flood == widget.get_active(): @@ -782,10 +775,8 @@ def on_default_window_pressed(self, widget): def on_btn_zero_g92_clicked(self, widget, data=None): self.command.mode(linuxcnc.MODE_MDI) - self.command.wait_complete() self.command.mdi("G92.1") self.command.mode(linuxcnc.MODE_MANUAL) - self.command.wait_complete() self.widgets.rbt_offset.emit("toggled") def on_tbtn_edit_offsets_toggled(self, widget, data=None): @@ -795,7 +786,6 @@ def on_tbtn_edit_offsets_toggled(self, widget, data=None): self.gscreen.sensitize_widgets(widgetlist, not state) if not state: # must switch back to manual mode, otherwise jogging is not possible self.command.mode(linuxcnc.MODE_MANUAL) - self.command.wait_complete() def on_chk_ignore_limits_toggled(self, widget, data=None): if self.widgets.chk_ignore_limits.get_active(): @@ -933,7 +923,6 @@ def on_hal_status_all_homed(self, widget): self.data.all_homed = True self.widgets.ntb_main.set_current_page(_NB_PREVIEW) self.command.mode(linuxcnc.MODE_MANUAL) - self.command.wait_complete() self.gscreen.sensitize_widgets(self.data.sensitive_all_homed, True) self.set_motion_mode(1) self.widgets.statusbar1.remove(self.gscreen.statusbar_id, self.gscreen.homed_status_message) @@ -977,7 +966,6 @@ def on_hal_status_interp_idle(self, widget): self.gscreen.sensitize_widgets(self.data.sensitive_run_idle, True) if self.tool_change: self.command.mode(linuxcnc.MODE_MANUAL) - self.command.wait_complete() self.tool_change = False self.current_line = 0 @@ -997,7 +985,6 @@ def on_hal_status_state_estop(self, widget=None): self.widgets.tbtn_estop.set_label("ESTOP") self.widgets.chk_ignore_limits.set_sensitive(False) self.command.mode(linuxcnc.MODE_MANUAL) - self.command.wait_complete() def on_hal_status_state_estop_reset(self, widget=None): self.widgets.tbtn_estop.set_active(False) @@ -1022,7 +1009,6 @@ def on_hal_status_state_on(self, widget): self.widgets.rbt_manual.set_active(True) self.widgets.ntb_mode.set_current_page(_MODE_MANUAL) self.command.mode(linuxcnc.MODE_MANUAL) - self.command.wait_complete() def on_hal_status_mode_manual(self, widget): print("MANUAL Mode") @@ -1041,7 +1027,6 @@ def on_hal_status_mode_mdi(self, widget): if not self.widgets.rbt_mdi.get_sensitive(): self.command.abort() self.command.mode(linuxcnc.MODE_MANUAL) - self.command.wait_complete() self.gscreen.notify(_("INFO"), _("It is not possible to change to MDI Mode at the moment"), INFO_ICON) return else: @@ -1055,7 +1040,6 @@ def on_hal_status_mode_auto(self, widget): if not self.widgets.rbt_auto.get_sensitive(): self.command.abort() self.command.mode(linuxcnc.MODE_MANUAL) - self.command.wait_complete() self.gscreen.notify(_("INFO"), _("It is not possible to change to AUTO Mode at the moment"), INFO_ICON) else: print("AUTO Mode") @@ -1245,7 +1229,6 @@ def reload_tool(self): self.load_tool = True self.tool_change = True self.command.mode(linuxcnc.MODE_MDI) - self.command.wait_complete() command = "M61 Q {0} G43".format(tool_to_load) self.command.mdi(command) self.command.wait_complete() @@ -1411,7 +1394,6 @@ def update_toolinfo(self, tool): return if "G43" in self.data.active_gcodes and self.stat.task_mode != linuxcnc.MODE_AUTO: self.command.mode(linuxcnc.MODE_MDI) - self.command.wait_complete() self.command.mdi("G43") self.command.wait_complete() @@ -1456,12 +1438,10 @@ def on_offset_axis_return(self, widget, result, calc, userdata, userdata2): r = self.axis_to_ref self.gscreen.prefs.putpref("offset_axis_{}".format(r), value, str) self.command.mode(linuxcnc.MODE_MDI) - self.command.wait_complete() command = "G10 L20 P0 {}{}".format(r, value) self.command.mdi(command) self.gscreen.reload_plot() self.command.mode(linuxcnc.MODE_MDI) - self.command.wait_complete() widget.destroy() self.data.entry_dialog = None diff --git a/share/qtvcp/panels/3pcenter/3pcenter_handler.py b/share/qtvcp/panels/3pcenter/3pcenter_handler.py index 5e736833ade..dd3d70b68af 100644 --- a/share/qtvcp/panels/3pcenter/3pcenter_handler.py +++ b/share/qtvcp/panels/3pcenter/3pcenter_handler.py @@ -115,7 +115,6 @@ def set_no_ok(self): def goCenter(self): c.mode(linuxcnc.MODE_MDI) - c.wait_complete() c.mdi('g53 g0 z0') c.mdi('g54 g0 x'+str(round(self.X, 4))+'y'+str(round(self.Y, 4))) @@ -123,7 +122,6 @@ def setCenter(self): offset_X = (hal.get_value("halui.axis.x.pos-relative") - self.X) offset_Y = (hal.get_value("halui.axis.y.pos-relative") - self.Y) c.mode(linuxcnc.MODE_MDI) - c.wait_complete() c.mdi('g10 l20 p1 x'+str(round(offset_X, 4))+'y'+str(round(offset_Y, 4))) self.w.label_4.setText("OK") self.w.label_4.setStyleSheet("background-color: rgba(50, 150, 50, 120);") diff --git a/src/emc/usr_intf/axis/scripts/axis.py b/src/emc/usr_intf/axis/scripts/axis.py index 2bbe030441a..c0e951b00d2 100755 --- a/src/emc/usr_intf/axis/scripts/axis.py +++ b/src/emc/usr_intf/axis/scripts/axis.py @@ -1020,13 +1020,13 @@ def manual_ok(do_poll=True): if s.task_state != linuxcnc.STATE_ON: return False return s.interp_state == linuxcnc.INTERP_IDLE or (s.task_mode == linuxcnc.MODE_MDI and s.queued_mdi_commands < vars.max_queued_mdi_commands.get()) -# If LinuxCNC is not already in one of the modes given, switch it to the -# first (task) mode MANUAL,MDI,AUTO +# If AXIS does not already show one of the modes given, show the first +# MANUAL,MDI,AUTO. The mode is AXIS's own (see stat.task_mode): nothing goes +# to task, so there is nothing to wait for. def ensure_mode(m, *p): s.poll() if s.task_mode == m or s.task_mode in p: return True c.mode(m) # task_mode - c.wait_complete() s.poll() return True diff --git a/src/emc/usr_intf/gmoccapy/gmoccapy.py b/src/emc/usr_intf/gmoccapy/gmoccapy.py index c8c9bd39506..f654c5edaa7 100644 --- a/src/emc/usr_intf/gmoccapy/gmoccapy.py +++ b/src/emc/usr_intf/gmoccapy/gmoccapy.py @@ -2896,17 +2896,14 @@ def on_tbtn_on_toggled(self, widget, data=None): def on_rbt_manual_pressed(self, widget, data=None): LOG.debug("mode Manual") self.command.mode(linuxcnc.MODE_MANUAL) - self.command.wait_complete() def on_rbt_mdi_pressed(self, widget, data=None): LOG.debug("mode MDI") self.command.mode(linuxcnc.MODE_MDI) - self.command.wait_complete() def on_rbt_auto_pressed(self, widget, data=None): LOG.debug("mode Auto") self.command.mode(linuxcnc.MODE_AUTO) - self.command.wait_complete() # If button exit is clicked, press emergency button before closing the application def on_btn_exit_clicked(self, widget, data=None): @@ -3067,7 +3064,6 @@ def on_hal_status_interp_idle(self, widget): if self.tool_change: self.command.mode(linuxcnc.MODE_MANUAL) - self.command.wait_complete() self.tool_change = False self.halcomp["program.current-line"] = 0 @@ -3154,7 +3150,6 @@ def on_hal_status_state_on(self, widget): self.widgets.btn_exit.set_sensitive(False) if self.widgets.ntb_main.get_current_page() != 0: self.command.mode(linuxcnc.MODE_MANUAL) - self.command.wait_complete() # activate limit override only if limit switch active if any(self.stat.limit): @@ -3226,7 +3221,6 @@ def on_hal_status_mode_mdi(self, widget): if not self.widgets.rbt_mdi.get_sensitive(): self.command.abort() self.command.mode(linuxcnc.MODE_MANUAL) - self.command.wait_complete() self._show_error((linuxcnc.OPERATOR_DISPLAY, _("It is not possible to change to MDI Mode at the moment"))) return else: @@ -3277,7 +3271,6 @@ def on_hal_status_mode_auto(self, widget): if not self.widgets.rbt_auto.get_sensitive(): self.command.abort() self.command.mode(linuxcnc.MODE_MANUAL) - self.command.wait_complete() self._show_error((linuxcnc.OPERATOR_DISPLAY, _("It is not possible to change to Auto Mode at the moment"))) return else: @@ -3429,7 +3422,6 @@ def on_window1_show(self, widget, data=None): self.on_chk_use_tool_measurement_toggled(self.widgets.chk_use_tool_measurement) self.command.mode(linuxcnc.MODE_MANUAL) - self.command.wait_complete() self.initialized = True @@ -3609,7 +3601,6 @@ def on_key_event(self, widget, event, signal): # F3 change to manual mode if keyname == "F3" and signal: self.command.mode(linuxcnc.MODE_MANUAL) - self.command.wait_complete() # we need to leave here, otherwise the check for jogging # only allowed in manual mode will finish the sub self.last_key_event = keyname, signal @@ -3618,7 +3609,6 @@ def on_key_event(self, widget, event, signal): # F5 should change to mdi mode if keyname == "F5" and signal: self.command.mode(linuxcnc.MODE_MDI) - self.command.wait_complete() # we need to leave here, otherwise the check for jogging # only allowed in manual mode will finish the sub self.last_key_event = keyname, signal @@ -4296,7 +4286,6 @@ def on_tbtn_setup_toggled(self, widget, data=None): self.stat.poll() if widget.get_active(): self.command.mode(linuxcnc.MODE_MANUAL) - self.command.wait_complete() self.widgets.rbt_manual.set_active(True) # save the mode to restore when leaving the settings page self.last_mode = self.stat.task_mode @@ -4364,7 +4353,6 @@ def on_tbtn_setup_toggled(self, widget, data=None): else: # restore mode self.command.mode(self.last_mode) - self.command.wait_complete() widget.set_image(self.widgets.img_settings) @@ -4923,11 +4911,9 @@ def on_btn_back_clicked(self, widget, data=None): result = self.dialogs.yesno_dialog(self, message, _("Attention!")) if result: # user says YES self.command.mode(linuxcnc.MODE_MDI) - self.command.wait_complete() self.command.mdi("G43") self.command.wait_complete() self.command.mode(linuxcnc.MODE_MANUAL) - self.command.wait_complete() self.widgets.ntb_button.set_current_page(_BB_MANUAL) self.widgets.ntb_main.set_current_page(0) self.widgets.ntb_preview.set_current_page(0) @@ -4969,7 +4955,6 @@ def on_tbtn_edit_offsets_toggled(self, widget, data=None): if not state: # we must switch back to manual mode, otherwise jogging is not possible self.command.mode(linuxcnc.MODE_MANUAL) - self.command.wait_complete() # show virtual keyboard? if state and self.widgets.chk_use_kb_on_offset.get_active(): @@ -4978,10 +4963,8 @@ def on_tbtn_edit_offsets_toggled(self, widget, data=None): def on_btn_zero_g92_clicked(self, widget, data=None): self.command.mode(linuxcnc.MODE_MDI) - self.command.wait_complete() self.command.mdi("G92.1") self.command.mode(linuxcnc.MODE_MANUAL) - self.command.wait_complete() self.widgets.btn_touch.emit("clicked") def _on_btn_set_value_clicked(self, widget, data=None): @@ -5016,12 +4999,10 @@ def _on_btn_set_value_clicked(self, widget, data=None): _("Please enter only numerical values. Values have not been applied")) else: self.command.mode(linuxcnc.MODE_MDI) - self.command.wait_complete() command = "G10 L20 P0 {0}{1:f}".format(axis, offset) self.command.mdi(command) self.widgets.hal_action_reload.emit("activate") self.command.mode(linuxcnc.MODE_MANUAL) - self.command.wait_complete() self.prefs.putpref("offset_axis_{0}".format(axis), offset, float) def _on_btn_edit_offsets_clicked(self, widget, data=None): @@ -5040,10 +5021,8 @@ def _on_btn_set_selected_clicked(self, widget, data=None): return else: self.command.mode(linuxcnc.MODE_MDI) - self.command.wait_complete() self.command.mdi(system) self.command.mode(linuxcnc.MODE_MANUAL) - self.command.wait_complete() def on_spbtn_probe_height_value_changed(self, widget, data=None): self.halcomp["probeheight"] = widget.get_value() @@ -5103,11 +5082,9 @@ def on_btn_block_height_clicked(self, widget, data=None): # set coordinate system to new origin origin = self.get_ini_info.get_axis_2_min_limit() + blockheight self.command.mode(linuxcnc.MODE_MDI) - self.command.wait_complete() self.command.mdi("G10 L2 P0 Z{0}".format(origin)) self.widgets.hal_action_reload.emit("activate") self.command.mode(linuxcnc.MODE_MANUAL) - self.command.wait_complete() # choose a theme to apply def on_theme_choice_changed(self, widget): @@ -5640,7 +5617,6 @@ def reload_tool(self): self.tool_change = True self.command.mode(linuxcnc.MODE_MDI) - self.command.wait_complete() command = "M61 Q {0} G43".format(tool_to_load) self.command.mdi(command) @@ -5759,14 +5735,12 @@ def on_btn_tool_touchoff_clicked(self, widget, data=None): else: command = "G10 L10 P{0} {1}{2}".format(self.stat.tool_in_spindle, axis, value) self.command.mode(linuxcnc.MODE_MDI) - self.command.wait_complete() self.command.mdi(command) self.command.wait_complete() if "G43" in self.active_gcodes: self.command.mdi("G43") self.command.wait_complete() self.command.mode(linuxcnc.MODE_MANUAL) - self.command.wait_complete() # select a tool entering a number def on_btn_select_tool_by_no_clicked(self, widget, data=None): @@ -5791,7 +5765,6 @@ def on_btn_select_tool_by_no_clicked(self, widget, data=None): else: self.tool_change = True self.command.mode(linuxcnc.MODE_MDI) - self.command.wait_complete() command = "T{0} M6".format(int(value)) self.command.mdi(command) # Next two lines fix issue #3129 caused by GStat missing changes in interpreter mode @@ -5817,7 +5790,6 @@ def on_btn_selected_tool_clicked(self, widget, data=None): self.tool_change = True tool = int(tool) self.command.mode(linuxcnc.MODE_MDI) - self.command.wait_complete() if widget == self.widgets.btn_change_tool: command = "T{0} M6".format(tool) diff --git a/src/emc/usr_intf/gscreen/emc_interface.py b/src/emc/usr_intf/gscreen/emc_interface.py index ff4f3dc767f..e2bb6f784cf 100644 --- a/src/emc/usr_intf/gscreen/emc_interface.py +++ b/src/emc/usr_intf/gscreen/emc_interface.py @@ -189,7 +189,6 @@ def quill_up(self): if self.masked: return self.set_motion_mode() self.emccommand.mode(self.emc.MODE_MANUAL) - self.emccommand.wait_complete() self.emccommand.jog(self.emc.JOG_CONTINUOUS, 0, 2, 100) def feed_hold(self, data): @@ -245,7 +244,6 @@ def single_block(self, s): def cycle_start(self): if self.emcstat.task_mode != self.emc.MODE_AUTO: self.emccommand.mode(self.emc.MODE_AUTO) - self.emccommand.wait_complete() self.emcstat.poll() if self.emcstat.paused: self.emccommand.auto(self.emc.AUTO_STEP) @@ -258,7 +256,6 @@ def cycle_start(self): # This restarts the program at the line specified directly (without cyscle start push) def re_start(self,line): self.emccommand.mode(self.emc.MODE_AUTO) - self.emccommand.wait_complete() self.emccommand.auto(self.emc.AUTO_RUN, line) self.restart_line_number = self.restart_reset_line @@ -285,13 +282,11 @@ def set_mdi_mode(self): self.emcstat.poll() if self.emcstat.task_mode != self.emc.MODE_MDI: self.emccommand.mode(self.emc.MODE_MDI) - self.emccommand.wait_complete() def set_auto_mode(self): self.emcstat.poll() if self.emcstat.task_mode != self.emc.MODE_AUTO: self.emccommand.mode(self.emc.MODE_AUTO) - self.emccommand.wait_complete() def get_mode(self): self.emcstat.poll() diff --git a/src/emc/usr_intf/gscreen/mdi.py b/src/emc/usr_intf/gscreen/mdi.py index c4f5083bcc2..16ec72e2e57 100644 --- a/src/emc/usr_intf/gscreen/mdi.py +++ b/src/emc/usr_intf/gscreen/mdi.py @@ -145,7 +145,6 @@ def issue(self): self.emcstat.poll() if self.emcstat.task_mode != self.emc.MODE_MDI: self.emccommand.mode(self.emc.MODE_MDI) - self.emccommand.wait_complete() self.emccommand.mdi(m) def set_tool_touchoff(self,tool,axis,value): @@ -153,7 +152,6 @@ def set_tool_touchoff(self,tool,axis,value): self.emcstat.poll() if self.emcstat.task_mode != self.emc.MODE_MDI: self.emccommand.mode(self.emc.MODE_MDI) - self.emccommand.wait_complete() self.emccommand.mdi(m) self.emccommand.wait_complete() self.emccommand.mdi("g43") @@ -163,7 +161,6 @@ def set_axis_origin(self,axis,value): self.emcstat.poll() if self.emcstat.task_mode != self.emc.MODE_MDI: self.emccommand.mode(self.emc.MODE_MDI) - self.emccommand.wait_complete() self.emccommand.mdi(m) def go_to_position(self,axis,position,feedrate): @@ -171,7 +168,6 @@ def go_to_position(self,axis,position,feedrate): self.emcstat.poll() if self.emcstat.task_mode != self.emc.MODE_MDI: self.emccommand.mode(self.emc.MODE_MDI) - self.emccommand.wait_complete() self.emccommand.mdi(m) def set_spindle_speed(self,value): @@ -179,7 +175,6 @@ def set_spindle_speed(self,value): self.emcstat.poll() if self.emcstat.task_mode != self.emc.MODE_MDI: self.emccommand.mode(self.emc.MODE_MDI) - self.emccommand.wait_complete() self.emccommand.mdi(m) def set_user_system(self,value): @@ -187,7 +182,6 @@ def set_user_system(self,value): self.emcstat.poll() if self.emcstat.task_mode != self.emc.MODE_MDI: self.emccommand.mode(self.emc.MODE_MDI) - self.emccommand.wait_complete() self.emccommand.mdi(m) def index_tool(self,toolnumber): @@ -195,14 +189,12 @@ def index_tool(self,toolnumber): self.emcstat.poll() if self.emcstat.task_mode != self.emc.MODE_MDI: self.emccommand.mode(self.emc.MODE_MDI) - self.emccommand.wait_complete() self.emccommand.mdi("m6 T %f"%(toolnumber)) self.emccommand.mdi("g43 h%f"%(toolnumber)) def arbitrary_mdi(self,command): if self.emcstat.task_mode != self.emc.MODE_MDI: self.emccommand.mode(self.emc.MODE_MDI) - self.emccommand.wait_complete() self.emccommand.mdi(command) class mdi_control: @@ -231,19 +223,16 @@ def set_mdi_mode(self): self.mdi.emcstat.poll() if self.mdi.emcstat.task_mode != self.mdi.emc.MODE_MDI: self.mdi.emccommand.mode(self.mdi.emc.MODE_MDI) - self.mdi.emccommand.wait_complete() def set_axis(self,axis,value): premode = self.mdi.emcstat.task_mode self.mdi.set_axis_origin(axis,value) self.mdi.emccommand.mode(premode) - self.mdi.emccommand.wait_complete() def touchoff(self,tool,axis,value): premode = self.mdi.emcstat.task_mode self.mdi.set_tool_touchoff(tool,axis,value) self.mdi.emccommand.mode(premode) - self.mdi.emccommand.wait_complete() def set_spindle_speed(self,value): self.mdi.set_spindle_speed(value) @@ -256,7 +245,6 @@ def set_user_system(self,system): premode = self.mdi.emcstat.task_mode self.mdi.set_user_system(system) self.mdi.emccommand.mode(premode) - self.mdi.emccommand.wait_complete() def index_tool(self,toolnumber): print("set tool number to :T",toolnumber) diff --git a/src/emc/usr_intf/pyui/commands.py b/src/emc/usr_intf/pyui/commands.py index 96fabe7c811..521ccd260a1 100644 --- a/src/emc/usr_intf/pyui/commands.py +++ b/src/emc/usr_intf/pyui/commands.py @@ -268,7 +268,6 @@ def incremental_jog(self, wname, cmd): def quill_up(self, wname, cmd): self.emccommand.mode(self.emc.MODE_MANUAL) - self.emccommand.wait_complete() self.mdi('G53 G0 Z %f'% float(cmd)) def feed_hold(self, wname, cmd): @@ -323,7 +322,6 @@ def smart_cycle_start(self, wname, cmd=None): self.emcstat.poll() if self.emcstat.task_mode != self.emc.MODE_AUTO: self.emccommand.mode(self.emc.MODE_AUTO) - self.emccommand.wait_complete() self.emcstat.poll() if self.emcstat.paused: self.emccommand.auto(self.emc.AUTO_STEP) @@ -336,7 +334,6 @@ def smart_cycle_start(self, wname, cmd=None): # This restarts the program at the line specified directly (without cyscle start push) def re_start(self, wname, line): self.emccommand.mode(self.emc.MODE_AUTO) - self.emccommand.wait_complete() self.emccommand.auto(self.emc.AUTO_RUN, line) self.restart_line_number = self.restart_reset_line @@ -377,19 +374,16 @@ def set_manual_mode(self): self.emcstat.poll() if self.emcstat.task_mode != self.emc.MODE_MANUAL: self.emccommand.mode(self.emc.MODE_MANUAL) - self.emccommand.wait_complete() def set_mdi_mode(self): self.emcstat.poll() if self.emcstat.task_mode != self.emc.MODE_MDI: self.emccommand.mode(self.emc.MODE_MDI) - self.emccommand.wait_complete() def set_auto_mode(self): self.emcstat.poll() if self.emcstat.task_mode != self.emc.MODE_AUTO: self.emccommand.mode(self.emc.MODE_AUTO) - self.emccommand.wait_complete() def get_mode(self): self.emcstat.poll() diff --git a/src/emc/usr_intf/touchy/emc_interface.py b/src/emc/usr_intf/touchy/emc_interface.py index 25ba4e8f4e0..7eb79f9ea30 100644 --- a/src/emc/usr_intf/touchy/emc_interface.py +++ b/src/emc/usr_intf/touchy/emc_interface.py @@ -227,7 +227,6 @@ def cycle_start(self): if self.emcstat.interp_state == self.emc.INTERP_IDLE: self.emccommand.mode(self.emc.MODE_AUTO) - self.emccommand.wait_complete() if self.sb: self.emccommand.auto(self.emc.AUTO_STEP) else: diff --git a/src/emc/usr_intf/touchy/mdi.py b/src/emc/usr_intf/touchy/mdi.py index 089c84c2f73..b4083ee0cb4 100644 --- a/src/emc/usr_intf/touchy/mdi.py +++ b/src/emc/usr_intf/touchy/mdi.py @@ -153,7 +153,6 @@ def issue(self): self.emcstat.poll() if self.emcstat.task_mode != self.emc.MODE_MDI: self.emccommand.mode(self.emc.MODE_MDI) - self.emccommand.wait_complete() self.emccommand.mdi(m) From e7651630713a2169014c3c578494078d873e75ff Mon Sep 17 00:00:00 2001 From: Rene Hopf Date: Fri, 16 Oct 2026 21:18:54 +0200 Subject: [PATCH 17/21] remove EMC_TASK_SET_MODE and halui's mode request pins The task mode follows what task runs, and nothing sets it any more: task accepted EMC_TASK_SET_MODE and did nothing, and the Python, Tcl and linuxcncrsh mode commands stopped sending it. - NML: drop EMC_TASK_SET_MODE (type 504) and task's handling of it. - shcom: drop sendManual(), sendAuto() and sendMdi(); schedrmt and emclcd no longer switch modes before MDI or opening a program, and emclcd's Test key no longer toggles the mode. - halui: drop halui.mode.manual, .auto and .mdi. The .is-* status pins stay. - Users of the pins: the xhc-hb04 pendant helper starts a program with halui.program.run only, the halui_pyvcp sim panel keeps the mode LEDs, the xhc-whb04b-6 example configuration and docs drop their mode nets, the remote start example needs halui.program.run only. --- configs/sim/axis/halui_pyvcp/pyvcp.hal | 4 --- configs/sim/axis/halui_pyvcp/vcp.xml | 24 ++++++--------- docs/src/code/nml-messages.adoc | 1 - .../getting-started/updating-linuxcnc.adoc | 5 +++- docs/src/gui/halui.adoc | 5 +--- docs/src/hal/halui-examples.adoc | 30 ++++--------------- docs/src/hal/intro.adoc | 3 -- docs/src/man/man1/halui.1.adoc | 9 ++---- docs/src/man/man1/xhc-whb04b-6.1.adoc | 10 +++---- lib/hallib/xhc-hb04.tcl | 3 +- src/emc/nml_intf/emc.cc | 16 ---------- src/emc/nml_intf/emc.hh | 1 - src/emc/nml_intf/emc_nml.hh | 15 ---------- src/emc/task/emctaskmain.cc | 12 ++------ src/emc/task/halui.cc | 9 ------ src/emc/usr_intf/emclcd.cc | 17 +---------- src/emc/usr_intf/emcsched.cc | 2 -- src/emc/usr_intf/shcom.cc | 24 --------------- src/emc/usr_intf/shcom.hh | 3 -- .../xhc-whb04b-6/example-configuration.hal | 3 -- 20 files changed, 29 insertions(+), 167 deletions(-) diff --git a/configs/sim/axis/halui_pyvcp/pyvcp.hal b/configs/sim/axis/halui_pyvcp/pyvcp.hal index 0554fa8344b..e6e7366d341 100644 --- a/configs/sim/axis/halui_pyvcp/pyvcp.hal +++ b/configs/sim/axis/halui_pyvcp/pyvcp.hal @@ -23,10 +23,6 @@ net flood-off pyvcp.flood.off halui.flood.off net mist-is-on pyvcp.mist.is-on halui.mist.is-on net flood-is-on pyvcp.flood.is-on halui.flood.is-on -net mode-manual pyvcp.mode.manual halui.mode.manual -net mode-auto pyvcp.mode.auto halui.mode.auto -net mode-mdi pyvcp.mode.mdi halui.mode.mdi - net spindle-start pyvcp.spindle.on halui.spindle.0.start net spindle-stop pyvcp.spindle.off halui.spindle.0.stop net spindle-forward pyvcp.spindle.forward halui.spindle.0.forward diff --git a/configs/sim/axis/halui_pyvcp/vcp.xml b/configs/sim/axis/halui_pyvcp/vcp.xml index dac57a1f5d1..b78e24c17d1 100644 --- a/configs/sim/axis/halui_pyvcp/vcp.xml +++ b/configs/sim/axis/halui_pyvcp/vcp.xml @@ -55,11 +55,9 @@ - + "mode.is-manual" 20 @@ -68,11 +66,9 @@ - + "mode.is-auto" 20 @@ -81,11 +77,9 @@ - + "mode.is-mdi" 20 diff --git a/docs/src/code/nml-messages.adoc b/docs/src/code/nml-messages.adoc index 307066ea39d..a0489298378 100644 --- a/docs/src/code/nml-messages.adoc +++ b/docs/src/code/nml-messages.adoc @@ -121,7 +121,6 @@ EMC_MOTION_STAT_TYPE EMC_TASK_INIT_TYPE EMC_TASK_HALT_TYPE EMC_TASK_ABORT_TYPE -EMC_TASK_SET_MODE_TYPE EMC_TASK_SET_STATE_TYPE EMC_TASK_PLAN_OPEN_TYPE EMC_TASK_PLAN_RUN_TYPE diff --git a/docs/src/getting-started/updating-linuxcnc.adoc b/docs/src/getting-started/updating-linuxcnc.adoc index 4a0eea2114e..06ec22bbbbb 100644 --- a/docs/src/getting-started/updating-linuxcnc.adoc +++ b/docs/src/getting-started/updating-linuxcnc.adoc @@ -270,7 +270,10 @@ the same time without taking the machine away from each other. Tcl process, linuxcncrsh connection) shows, which `task_mode`, `emc_mode` and `get mode` report while task is idle. User interfaces that switch pages on the mode keep working, each with its own page. -* The `halui.mode.manual`, `.mdi` and `.auto` pins do nothing. +* The `halui.mode.manual`, `.mdi` and `.auto` pins are gone. Remove the + nets that connect them from HAL files: a program start button only + needs `halui.program.run`. The `.is-manual`, `.is-mdi` and `.is-auto` + pins stay. * Switching to Manual used to abort a running MDI command. It no longer does: use abort. * Task puts motion into coordinated mode when a run starts and back into diff --git a/docs/src/gui/halui.adoc b/docs/src/gui/halui.adoc index f725bf4236d..fd9c6c1bc80 100644 --- a/docs/src/gui/halui.adoc +++ b/docs/src/gui/halui.adoc @@ -233,15 +233,12 @@ _L_ = axis letter (xyzabcuvw) === Mode -* 'halui.mode.auto' (bool, in) - does nothing, the task mode follows what task runs and cannot be set -* 'halui.mode.is-auto' (bool, out) - indicates a program runs, or is paused +* 'halui.mode.is-auto' (bool, out) - indicates a program runs, or is paused; the task mode follows what task runs and cannot be set * 'halui.mode.is-joint' (bool, out) - indicates joint by joint jog mode is on * 'halui.mode.is-manual' (bool, out) - indicates task is idle: neither a program nor MDI runs * 'halui.mode.is-mdi' (bool, out) - indicates MDI commands run * 'halui.mode.is-teleop' (bool, out) - indicates coordinated jog mode is on * 'halui.mode.joint' (bool, in) - pin for requesting joint by joint jog mode -* 'halui.mode.manual' (bool, in) - does nothing, see 'halui.mode.auto' -* 'halui.mode.mdi' (bool, in) - does nothing, see 'halui.mode.auto' * 'halui.mode.teleop' (bool, in) - pin for requesting coordinated jog mode === Program diff --git a/docs/src/hal/halui-examples.adoc b/docs/src/hal/halui-examples.adoc index f0f7daab4ad..ff0c4d51ee1 100644 --- a/docs/src/hal/halui-examples.adoc +++ b/docs/src/hal/halui-examples.adoc @@ -10,34 +10,14 @@ The Halui pins are always available, so these examples work as they stand. [[sec:halui-remote-start]] == Remote Start -To connect a remote program start button to LinuxCNC you use the -`halui.program.run` pin and the `halui.mode.auto` pin. -You have to ensure that it is OK to run first by using the `halui.mode.is-auto` pin. -You do this with an `and2` component. The following figure shows how this is done. -When the Remote Run Button is pressed it is connected to both `halui.mode.auto` and `and2.0.in0`. -If it is OK for auto mode the pin `halui.mode.is-auto` will be on. -If both the inputs to the `and2.0` component are on the `and2.0.out` will be on -and this will start the program. - -.Remote Start Example -image::images/remote-start.png["Remote Start Example"] - -The hal commands needed to accomplish the above are: - -[source,hal] ----- -net program-start-btn halui.mode.auto and2.0.in0 <= -net program-run-ok and2.0.in1 <= halui.mode.is-auto -net remote-program-run halui.program.run <= and2.0.out ----- - -Notice on line one that there are two reader pins, this can also be split -up to two lines like this: +To connect a remote program start button to LinuxCNC connect it to the +`halui.program.run` pin. There is no mode to switch to first: LinuxCNC +starts the program when it is idle and refuses the run otherwise, for +instance while MDI runs or a jog is active. [source,hal] ---- -net program-start-btn halui.mode.auto <= -net program-start-btn and2.0.in0 +net remote-program-run halui.program.run <= ---- == Pause & Resume diff --git a/docs/src/hal/intro.adoc b/docs/src/hal/intro.adoc index b9e3bc8cb1b..a21b3456423 100644 --- a/docs/src/hal/intro.adoc +++ b/docs/src/hal/intro.adoc @@ -242,9 +242,6 @@ The same commands used to build the system can be used to make changes as needed This document is aimed at people who already know how to do this kind of hardware system integration, but who do not know how to connect the hardware to LinuxCNC. See the <> section in the HAL UI Examples documentation. -.Remote Start Example (Schema) -image::images/remote-start.png["Remote Start Example (Schema)"] - The traditional hardware design as described above ends at the edge of the main control. Outside the control are a bunch of relatively simple boxes, connected together to do whatever is needed. Inside, the control is a big mystery -- one huge black box that we hope works. diff --git a/docs/src/man/man1/halui.1.adoc b/docs/src/man/man1/halui.1.adoc index e493e8ff122..82145890b8e 100644 --- a/docs/src/man/man1/halui.1.adoc +++ b/docs/src/man/man1/halui.1.adoc @@ -151,10 +151,9 @@ contact) connect the physical button to a HAL debounce filter first. === Mode -*halui.mode.auto* bool in:: - does nothing. The task mode follows what task runs and cannot be set. *halui.mode.is-auto* bool out:: - a program runs, or is paused + a program runs, or is paused. The task mode follows what task runs and + cannot be set. *halui.mode.is-joint* bool out:: pin showing joint by joint jog mode is on *halui.mode.is-manual* bool out:: @@ -165,10 +164,6 @@ contact) connect the physical button to a HAL debounce filter first. pin showing coordinated jog mode is on *halui.mode.joint* bool in:: pin for requesting joint by joint jog mode -*halui.mode.manual* bool in:: - does nothing, see *halui.mode.auto* -*halui.mode.mdi* bool in:: - does nothing, see *halui.mode.auto* *halui.mode.teleop* bool in:: pin for requesting coordinated jog mode diff --git a/docs/src/man/man1/xhc-whb04b-6.1.adoc b/docs/src/man/man1/xhc-whb04b-6.1.adoc index 6cd5f625ab2..fe06c5acb58 100644 --- a/docs/src/man/man1/xhc-whb04b-6.1.adoc +++ b/docs/src/man/man1/xhc-whb04b-6.1.adoc @@ -235,7 +235,8 @@ Signals for operating program and MDI mode. `whb.halui.program.is-idle` (bool, in):: Connect to `halui.program.is-idle`. Pin indicating no program is running. `whb.halui.mode.auto` (bool, out):: - Connect to `halui.mode.auto`. Pin for requesting auto mode. + Pin for requesting auto mode. Leave unconnected: the task mode cannot be set + and halui has no pin for it. `whb.halui.mode.is-auto` (bool, in):: Connect to `halui.mode.is-auto`. Pin for indicating auto mode is on. `whb.halui.mode.joint` (bool, out):: @@ -243,11 +244,11 @@ Signals for operating program and MDI mode. `whb.halui.mode.is-joint` (bool, in):: Connect to `halui.mode.is-joint`. Pin indicating joint by joint mode is on. `whb.halui.mode.manual` (bool, out):: - Connect to `halui.mode.manual`. Pin for requesting manual mode. + Pin for requesting manual mode. Leave unconnected, see `whb.halui.mode.auto`. `whb.halui.mode.is-manual` (bool, in):: Connect to `halui.mode.is-manual`. Pin indicating manual mode is on. `whb.halui.mode.mdi` (bool, out):: - Connect to `halui.mode.mdi`. Pin for requesting MDI mode. + Pin for requesting MDI mode. Leave unconnected, see `whb.halui.mode.auto`. `whb.halui.mode.is-mdi` (bool, in):: Connect to `halui.mode.is-mdi`. Pin indicating MDI mode is on. `whb.halui.mode.teleop` (bool, out):: @@ -419,9 +420,6 @@ net pdnt.program.run whb.halui.program.run net pdnt.program.stop whb.halui.program.stop halui.program.stop # machine mode related signals -net pdnt.mode.auto whb.halui.mode.auto halui.mode.auto -net pdnt.mode.manual whb.halui.mode.manual halui.mode.manual -net pdnt.mode.mdi whb.halui.mode.mdi halui.mode.mdi net pdnt.mode.joint whb.halui.mode.joint halui.mode.joint net pdnt.mode.teleop whb.halui.mode.teleop halui.mode.teleop net pdnt.mode.is-auto halui.mode.is-auto whb.halui.mode.is-auto diff --git a/lib/hallib/xhc-hb04.tcl b/lib/hallib/xhc-hb04.tcl index d9d3c7fdb3e..beb2c112394 100644 --- a/lib/hallib/xhc-hb04.tcl +++ b/lib/hallib/xhc-hb04.tcl @@ -384,8 +384,7 @@ proc std_start_pause_button {} { makenet pendant:program-pause <= pendant_util.pause \ => halui.program.pause makenet pendant:program-run <= pendant_util.run \ - => halui.program.run \ - => halui.mode.auto + => halui.program.run # accommodate existing signames for halui outpins: makenet [existing_outpin_signame halui.program.is-idle pendant:is-idle] \ diff --git a/src/emc/nml_intf/emc.cc b/src/emc/nml_intf/emc.cc index db9e68c4838..b4c06e59d43 100644 --- a/src/emc/nml_intf/emc.cc +++ b/src/emc/nml_intf/emc.cc @@ -217,8 +217,6 @@ int emcFormat(NMLTYPE type, void *buffer, CMS * cms) case EMC_TASK_PLAN_OPTIONAL_STOP_TYPE: ((EMC_TASK_PLAN_OPTIONAL_STOP *) buffer)->update(cms); break; - case EMC_TASK_SET_MODE_TYPE: - ((EMC_TASK_SET_MODE *) buffer)->update(cms); break; case EMC_TASK_SET_STATE_TYPE: ((EMC_TASK_SET_STATE *) buffer)->update(cms); @@ -458,8 +456,6 @@ const char *emc_symbol_lookup(uint32_t type) return "EMC_TASK_PLAN_SET_BLOCK_DELETE"; case EMC_TASK_PLAN_OPTIONAL_STOP_TYPE: return "EMC_TASK_PLAN_OPTIONAL_STOP"; - case EMC_TASK_SET_MODE_TYPE: - return "EMC_TASK_SET_MODE"; case EMC_TASK_SET_STATE_TYPE: return "EMC_TASK_SET_STATE"; case EMC_TASK_STAT_TYPE: @@ -1460,18 +1456,6 @@ void EMC_STAT_MSG::update(CMS * /*cms*/) } -/* -* NML/CMS Update function for EMC_TASK_SET_MODE -* Automatically generated by NML CodeGen Java Applet. -* on Sat Oct 11 13:45:16 UTC 2003 -*/ -// cppcheck-suppress duplInheritedMember -void EMC_TASK_SET_MODE::update(CMS * cms) -{ - EMC_TASK_CMD_MSG::update(cms); - cms->update((int *) &mode, 1); -} - /* * NML/CMS Update function for EMC_JOG_INCR */ diff --git a/src/emc/nml_intf/emc.hh b/src/emc/nml_intf/emc.hh index 7745cc5b501..5d46de23d48 100644 --- a/src/emc/nml_intf/emc.hh +++ b/src/emc/nml_intf/emc.hh @@ -124,7 +124,6 @@ struct PM_CARTESIAN; // NML for EMC_TASK #define EMC_TASK_ABORT_TYPE ((NMLTYPE) 503) -#define EMC_TASK_SET_MODE_TYPE ((NMLTYPE) 504) #define EMC_TASK_SET_STATE_TYPE ((NMLTYPE) 505) #define EMC_TASK_PLAN_OPEN_TYPE ((NMLTYPE) 506) #define EMC_TASK_PLAN_RUN_TYPE ((NMLTYPE) 507) diff --git a/src/emc/nml_intf/emc_nml.hh b/src/emc/nml_intf/emc_nml.hh index a53c5cbe301..f246849dbbb 100644 --- a/src/emc/nml_intf/emc_nml.hh +++ b/src/emc/nml_intf/emc_nml.hh @@ -1224,21 +1224,6 @@ class EMC_TASK_ABORT:public EMC_TASK_CMD_MSG { void update(CMS * cms); }; -class EMC_TASK_SET_MODE:public EMC_TASK_CMD_MSG { - public: - EMC_TASK_SET_MODE() - : EMC_TASK_CMD_MSG(EMC_TASK_SET_MODE_TYPE, sizeof(EMC_TASK_SET_MODE)), - mode(EMC_TASK_MODE::AUTO) - {}; - - // For internal NML/CMS use only. - // Sub-class update() calls base-class update() - // cppcheck-suppress duplInheritedMember - void update(CMS * cms); - - EMC_TASK_MODE mode; -}; - class EMC_TASK_SET_STATE:public EMC_TASK_CMD_MSG { public: EMC_TASK_SET_STATE() diff --git a/src/emc/task/emctaskmain.cc b/src/emc/task/emctaskmain.cc index f609864790e..e68a1005035 100644 --- a/src/emc/task/emctaskmain.cc +++ b/src/emc/task/emctaskmain.cc @@ -1088,13 +1088,11 @@ static int emcTaskPlan(void) type = 0; } - // Always display messages. A mode change is accepted in any state and - // does nothing, see EMC_TASK_SET_MODE_TYPE in emcTaskIssueCommand(). + // Always display messages switch (type) { case EMC_OPERATOR_ERROR_TYPE: case EMC_OPERATOR_TEXT_TYPE: case EMC_OPERATOR_DISPLAY_TYPE: - case EMC_TASK_SET_MODE_TYPE: retval = emcTaskIssueCommand(emcCommand); return retval; } @@ -2025,13 +2023,7 @@ static int emcTaskIssueCommand(NMLmsg * cmd) retval = 0; break; - // mode and state commands - - case EMC_TASK_SET_MODE_TYPE: - // The task mode reports what task is running (determineMode()) and - // cannot be set. Accept the request so existing clients keep working. - retval = 0; - break; + // state commands case EMC_TASK_SET_STATE_TYPE: state_msg = reinterpret_cast(cmd); diff --git a/src/emc/task/halui.cc b/src/emc/task/halui.cc index d182384e292..06c61771dbb 100644 --- a/src/emc/task/halui.cc +++ b/src/emc/task/halui.cc @@ -80,11 +80,8 @@ static int axis_mask = 0; FIELD(bool,estop_reset) /* pin for resetting ESTOP */ \ FIELD(bool,estop_is_activated) /* pin for status ESTOP is activated */ \ \ - FIELD(bool,mode_manual) /* pin for requesting manual mode, does nothing */ \ FIELD(bool,mode_is_manual) /* pin for manual mode is on: task is idle */ \ - FIELD(bool,mode_auto) /* pin for requesting auto mode, does nothing */ \ FIELD(bool,mode_is_auto) /* pin for auto mode is on: a program runs */ \ - FIELD(bool,mode_mdi) /* pin for requesting mdi mode, does nothing */ \ FIELD(bool,mode_is_mdi) /* pin for mdi mode is on: MDI runs */ \ FIELD(bool,mode_teleop) /* pin for requesting teleop mode */ \ FIELD(bool,mode_is_teleop) /* pin for teleop mode is on */ \ @@ -497,9 +494,6 @@ int halui_hal_init(void) CHK(halui_export_pin_IN_bool(&(halui_data->machine_off), "halui.machine.off")); CHK(halui_export_pin_IN_bool(&(halui_data->estop_activate), "halui.estop.activate")); CHK(halui_export_pin_IN_bool(&(halui_data->estop_reset), "halui.estop.reset")); - CHK(halui_export_pin_IN_bool(&(halui_data->mode_manual), "halui.mode.manual")); - CHK(halui_export_pin_IN_bool(&(halui_data->mode_auto), "halui.mode.auto")); - CHK(halui_export_pin_IN_bool(&(halui_data->mode_mdi), "halui.mode.mdi")); CHK(halui_export_pin_IN_bool(&(halui_data->mode_teleop), "halui.mode.teleop")); CHK(halui_export_pin_IN_bool(&(halui_data->mode_joint), "halui.mode.joint")); CHK(halui_export_pin_IN_bool(&(halui_data->mist_on), "halui.mist.on")); @@ -1234,9 +1228,6 @@ static void check_hal_changes() if (check_bit_changed(new_halui_data.estop_reset, old_halui_data.estop_reset) != 0) sendEstopReset(); - // halui.mode.manual, .auto and .mdi do nothing: the task mode follows - // what task runs - if (check_bit_changed(new_halui_data.mode_teleop, old_halui_data.mode_teleop) != 0) sendTeleop(); diff --git a/src/emc/usr_intf/emclcd.cc b/src/emc/usr_intf/emclcd.cc index 67305fa289e..ce3d9225b8f 100644 --- a/src/emc/usr_intf/emclcd.cc +++ b/src/emc/usr_intf/emclcd.cc @@ -926,7 +926,6 @@ static int openProgram(char *s) widgetSetStr(PROG_WIDGET1, s, ""); widgetSetStr(PROG_WIDGET2, s, ""); if (sendTaskPlanInit() != 0) return -1; - sendAuto(); return sendProgramOpen(fname); } @@ -1143,7 +1142,6 @@ static int jog(int jnum, float speed) else stepSize = 1.0; if ((jnum < 0) || (jnum > 5)) return -1; // if (runStatus == rsIdle) { -// sendManual(); switch (jogMode) { case jtCont: if (jogging == 1) { // toggle if driver does not support key down / key up @@ -1240,17 +1238,6 @@ static int stepKey() return sendProgramStep(); } -static int toggleMode() - -{ - switch (emcStatus->task.mode) { - case EMC_TASK_MODE::MANUAL: sendAuto(); break; - case EMC_TASK_MODE::AUTO: sendManual(); break; - case EMC_TASK_MODE::MDI: sendAuto(); break; - } - return 0; -} - static int nextKey() { int temp; @@ -1347,9 +1334,7 @@ static int doKey(keyType k) stepKey(); break; case ktStepRelease: break; - case ktTestPress: - toggleMode(); - break; + case ktTestPress: break; // used to toggle the task mode, which cannot be set case ktTestRelease: break; case ktHelpPress: break; case ktHelpRelease: break; diff --git a/src/emc/usr_intf/emcsched.cc b/src/emc/usr_intf/emcsched.cc index 00465cd1b7c..76d16eb9456 100644 --- a/src/emc/usr_intf/emcsched.cc +++ b/src/emc/usr_intf/emcsched.cc @@ -256,7 +256,6 @@ void updateQueue() { if (interlocksOk()) { sendFeedOverride(((double) q.front().getFeedOverride()) / 100.0); sendSpindleOverride(0, ((double) q.front().getSpindleOverride()) / 100.0); - sendMdi(); sendMdiCmd("G92.1\n"); if (emcCommandWaitDone() != 0) { queueStatus = qsError; @@ -296,7 +295,6 @@ void updateQueue() { if (sendTaskPlanInit() != 0) { queueStatus = qsError; } - sendAuto(); strxcpy(fileStr, defaultPath.c_str()); strxcat(fileStr, q.front().getFileName().c_str()); if (sendProgramOpen(fileStr) != 0) { diff --git a/src/emc/usr_intf/shcom.cc b/src/emc/usr_intf/shcom.cc index 262ca782f0c..18db82fdee2 100644 --- a/src/emc/usr_intf/shcom.cc +++ b/src/emc/usr_intf/shcom.cc @@ -478,30 +478,6 @@ int sendMachineOff() return emcSendCommandAndWait(state_msg); } -int sendManual() -{ - EMC_TASK_SET_MODE mode_msg; - - mode_msg.mode = EMC_TASK_MODE::MANUAL; - return emcSendCommandAndWait(mode_msg); -} - -int sendAuto() -{ - EMC_TASK_SET_MODE mode_msg; - - mode_msg.mode = EMC_TASK_MODE::AUTO; - return emcSendCommandAndWait(mode_msg); -} - -int sendMdi() -{ - EMC_TASK_SET_MODE mode_msg; - - mode_msg.mode = EMC_TASK_MODE::MDI; - return emcSendCommandAndWait(mode_msg); -} - int sendOverrideLimits(int joint) { EMC_JOINT_OVERRIDE_LIMITS lim_msg; diff --git a/src/emc/usr_intf/shcom.hh b/src/emc/usr_intf/shcom.hh index 9a7abd4fda4..a12a3d5f1b1 100644 --- a/src/emc/usr_intf/shcom.hh +++ b/src/emc/usr_intf/shcom.hh @@ -96,9 +96,6 @@ extern int sendEstop(); extern int sendEstopReset(); extern int sendMachineOn(); extern int sendMachineOff(); -extern int sendManual(); -extern int sendAuto(); -extern int sendMdi(); extern int sendOverrideLimits(int jnum); extern int sendJogStop(int jnum, int jjogmode); extern int sendJogCont(int jnum, int jjogmode, double speed); diff --git a/src/hal/user_comps/xhc-whb04b-6/example-configuration.hal b/src/hal/user_comps/xhc-whb04b-6/example-configuration.hal index 636908c9a2b..efc1f7982f0 100644 --- a/src/hal/user_comps/xhc-whb04b-6/example-configuration.hal +++ b/src/hal/user_comps/xhc-whb04b-6/example-configuration.hal @@ -55,9 +55,6 @@ net pdnt.program.run whb.halui.program.run net pdnt.program.stop whb.halui.program.stop halui.program.stop # machine mode related signals -net pdnt.mode.auto whb.halui.mode.auto halui.mode.auto -net pdnt.mode.manual whb.halui.mode.manual halui.mode.manual -net pdnt.mode.mdi whb.halui.mode.mdi halui.mode.mdi net pdnt.mode.joint whb.halui.mode.joint halui.mode.joint net pdnt.mode.teleop whb.halui.mode.teleop halui.mode.teleop net pdnt.mode.is-auto halui.mode.is-auto whb.halui.mode.is-auto From 51175cb240930715a4daadcb25bd60a134c47212 Mon Sep 17 00:00:00 2001 From: Rene Hopf Date: Fri, 16 Oct 2026 21:40:51 +0200 Subject: [PATCH 18/21] motion: no jump back to the paused position on resume pause_return_plan() starts a group of axes back toward the paused position, and pause_return_settled() can run in the same servo cycle, before the planner has. The axes still read 'not active' from the end of their jogs, so the group counted as arrived and its offsets were set to zero at once: X and Y always jumped back, Z when X and Y were not jogged. Mark a planned axis active until the planner reports. The test now requires positions on the way back for X, Y and Z. --- src/emc/motion/axis.c | 3 +++ tests/jog-while-paused/test-ui.py | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/src/emc/motion/axis.c b/src/emc/motion/axis.c index 0fe5f431873..59fba57f4b2 100644 --- a/src/emc/motion/axis.c +++ b/src/emc/motion/axis.c @@ -980,6 +980,9 @@ static bool pause_return_plan(unsigned mask) axis->pause_tp.max_acc = d * a; axis->pause_tp.max_jerk = jerk ? d * j : 0; axis->pause_tp.enable = 1; + // moving from now on: pause_return_settled() may run before the + // planner has, and must not take the old 'not active' for arrived + axis->pause_tp.active = 1; } return any; } diff --git a/tests/jog-while-paused/test-ui.py b/tests/jog-while-paused/test-ui.py index 8ab7709f309..545527f7d5e 100755 --- a/tests/jog-while-paused/test-ui.py +++ b/tests/jog-while-paused/test-ui.py @@ -152,6 +152,10 @@ def run_and_pause(prog, at_x): check('Z stays up until XY are back', not z_early, z_early[:3]) off_line = [o for o in offsets if abs(o[0] * 2 - o[1] * dx) > 1e-6] check('XY return is a straight line', not off_line, off_line[:3]) +xy_on_way = [o for o in offsets if 0.1 < o[0] < dx - 0.1] +check('XY move back, no jump', len(xy_on_way) > 10, len(xy_on_way)) +z_on_way = [o for o in offsets if 0.1 < o[2] < 4.9] +check('Z moves back, no jump', len(z_on_way) > 10, len(z_on_way)) check('program finished at the end point', wait(lambda: idle(), 20), pos()) check('program end position', near(pos()[:2], (0, 0), 1e-6), pos()) check('no errors from the resume', not errors()) From 423bf16b2e48e18d2712eb3ccfadbf2cfeff9e3e Mon Sep 17 00:00:00 2001 From: Rene Hopf Date: Fri, 16 Oct 2026 21:41:58 +0200 Subject: [PATCH 19/21] motion: return from jogs while paused at the speed of the jogs The return to the paused position ran at the axis velocity limits, too fast to follow or stop. Each axis now remembers the fastest it moved during jogs while paused (wheel jogs included), and each group of the return goes no faster along its line than the fastest of its axes, still within the axis limits. The test checks that a 2 mm return after a 4 mm/s jog takes about 0.5 s. --- docs/src/config/ini-config.adoc | 2 +- docs/src/config/python-interface.adoc | 4 +-- .../getting-started/updating-linuxcnc.adoc | 2 +- src/emc/motion/axis.c | 25 ++++++++++++++++--- tests/jog-while-paused/test-ui.py | 7 ++++-- 5 files changed, 31 insertions(+), 9 deletions(-) diff --git a/docs/src/config/ini-config.adoc b/docs/src/config/ini-config.adoc index 9fe0aeb6fa5..34adcb97837 100644 --- a/docs/src/config/ini-config.adoc +++ b/docs/src/config/ini-config.adoc @@ -952,7 +952,7 @@ Finally, no amount of tweaking will speed up a tool path with lots of small, tig * `MAX_LINEAR_ACCELERATION = 20.0` - (((MAX ACCELERATION))) The maximum acceleration for any axis or coordinated axis move, in 'machine units' per second per second. * `PAUSE_RETURN_LAST = Z` - (((PAUSE RETURN LAST))) The axes that return last when a paused program or MDI command resumes after jogs while paused. The other axes return to the paused position first, together in a straight line, then these, so by default the tool comes down onto the point last. - Empty: all axes return in one straight line. The return runs at the axis velocity and acceleration limits. + Empty: all axes return in one straight line. Each group returns no faster along its line than the fastest jog of its axes went, within the axis limits. * `PLANNER_TYPE = 0` - (((PLANNER TYPE))) Selects the trajectory planner type: 0 = trapezoidal (default), 1 = S-curve with jerk limiting. S-curve planning is only active when `PLANNER_TYPE = 1` AND `MAX_LINEAR_JERK` is 1.0 or above; a smaller value falls back to trapezoidal, with an operator message. diff --git a/docs/src/config/python-interface.adoc b/docs/src/config/python-interface.adoc index aa33bd3c575..39c6bedd057 100644 --- a/docs/src/config/python-interface.adoc +++ b/docs/src/config/python-interface.adoc @@ -295,8 +295,8 @@ see <> for an example. how far jogs while paused have moved each axis off the paused position. Resume (or step) brings them back to zero first: the spindles and the coolant as they were at the pause, the spindles at speed, the axes other - than `[TRAJ]PAUSE_RETURN_LAST` in a straight line, then those, then the - program goes on. An abort keeps the machine where it was jogged to. + than `[TRAJ]PAUSE_RETURN_LAST` in a straight line, then those, as fast + as they were jogged, then the program goes on. An abort keeps the machine where it was jogged to. *pause_returning*:: '(returns boolean)' - resuming after a pause: spindles, back to the paused position, then on. diff --git a/docs/src/getting-started/updating-linuxcnc.adoc b/docs/src/getting-started/updating-linuxcnc.adoc index 06ec22bbbbb..b84feb4444b 100644 --- a/docs/src/getting-started/updating-linuxcnc.adoc +++ b/docs/src/getting-started/updating-linuxcnc.adoc @@ -295,7 +295,7 @@ has stopped the motion. Joints cannot. On resume (or step) LinuxCNC first: waits for the spindles to be at speed; . returns the axes to the paused position: the axes other than `[TRAJ]PAUSE_RETURN_LAST` (default `Z`) together in a straight line, - then those, at the axis limits; + then those, as fast as they were jogged; . goes on with the program. Pausing again during the return stops it; the axes can be jogged again diff --git a/src/emc/motion/axis.c b/src/emc/motion/axis.c index 59fba57f4b2..061ecd68b2c 100644 --- a/src/emc/motion/axis.c +++ b/src/emc/motion/axis.c @@ -39,6 +39,7 @@ typedef struct { simple_tp_t pause_tp; /* planner for jogs while paused, see axis_pause_update() */ double pause_base; /* paused program position plus external offset */ + double pause_peak_vel; /* fastest the jogs while paused moved this axis */ int kb_pjog_active; /* non-zero during a keyboard jog while paused */ int wheel_pjog_active; /* non-zero during a wheel jog while paused */ } emcmot_axis_t; @@ -820,7 +821,8 @@ int axis_calc_motion(double servo_period) ** the external offsets are. On resume the offsets run back to zero first ** (axis_pause_return_start()), so the machine is back where it paused ** before the program continues: the other axes together in a straight -** line, then the [TRAJ]PAUSE_RETURN_LAST ones, at the axis limits. +** line, then the [TRAJ]PAUSE_RETURN_LAST ones, each group no faster along +** its line than the fastest of its axes was jogged, within the axis limits. */ void axis_set_pause_return_last(unsigned mask) @@ -920,6 +922,9 @@ void axis_pause_update(double *pcmd_p[], double servo_period) } } simple_tp_update(&axis->pause_tp, servo_period); + if (!pause_return_phase && fabs(axis->pause_tp.curr_vel) > axis->pause_peak_vel) { + axis->pause_peak_vel = fabs(axis->pause_tp.curr_vel); + } // stay within the soft limits, as update_teleop_with_check() does; // a return only moves back toward the paused position @@ -944,10 +949,11 @@ void axis_pause_update(double *pcmd_p[], double servo_period) /* Send the axes in mask back to zero offset in a straight line: the same ** profile for all, scaled by each one's distance, as fast as the slowest -** axis allows. Returns whether any axis has to move. */ +** axis allows and no faster along the line than the fastest jog of these +** axes went. Returns whether any axis has to move. */ static bool pause_return_plan(unsigned mask) { - double v = 1e99, a = 1e99, j = 1e99; + double v = 1e99, a = 1e99, j = 1e99, len2 = 0, peak = 0; bool jerk = true, any = false; int n; @@ -957,6 +963,8 @@ static bool pause_return_plan(unsigned mask) if (!(mask & (1u << n))) { continue; } if (d < 1e-12) { continue; } any = true; + len2 += d * d; + if (axis->pause_peak_vel > peak) { peak = axis->pause_peak_vel; } if (axis->vel_limit / d < v) { v = axis->vel_limit / d; } if (axis->acc_limit / d < a) { a = axis->acc_limit / d; } if (axis->jerk_limit > 0) { @@ -965,6 +973,10 @@ static bool pause_return_plan(unsigned mask) jerk = false; } } + // v is in line lengths per second + if (any && peak > 0 && peak / sqrt(len2) < v) { + v = peak / sqrt(len2); + } for (n = 0; n < EMCMOT_MAX_AXIS; n++) { emcmot_axis_t *axis = &axis_array[n]; double d = fabs(axis->pause_tp.curr_pos); @@ -1029,6 +1041,12 @@ bool axis_pause_return_update(void) } else if (pause_return_phase == 2 && pause_return_settled(pause_return_last_mask)) { pause_return_phase = 0; } + if (pause_return_phase == 0) { + int n; + for (n = 0; n < EMCMOT_MAX_AXIS; n++) { + axis_array[n].pause_peak_vel = 0; + } + } return pause_return_phase == 0; } @@ -1083,6 +1101,7 @@ void axis_pause_clear(void) tp->active = 0; axis_array[n].kb_pjog_active = 0; axis_array[n].wheel_pjog_active = 0; + axis_array[n].pause_peak_vel = 0; } } diff --git a/tests/jog-while-paused/test-ui.py b/tests/jog-while-paused/test-ui.py index 545527f7d5e..1b135a86936 100755 --- a/tests/jog-while-paused/test-ui.py +++ b/tests/jog-while-paused/test-ui.py @@ -212,10 +212,13 @@ def run_and_pause(prog, at_x): c.auto(linuxcnc.AUTO_RUN, 0) check('stopped at M0', wait(lambda: s.paused and s.pause_jog_ok, 10), pos()) p = pos() -c.jog(linuxcnc.JOG_INCREMENT, False, 2, 20, 2.0) +c.jog(linuxcnc.JOG_INCREMENT, False, 2, 4, 2.0) # Z +2 at 4 mm/s wait(lambda: near(pos(), (p[0], p[1], p[2] + 2))) c.auto(linuxcnc.AUTO_RESUME) -c.wait_complete() +t0 = time.time() +wait(lambda: s.pause_offset[2] == 0, 5) +dt = time.time() - t0 +check('the return goes at the speed of the jog', 0.45 < dt < 1.0, round(dt, 2)) check('M0: back and finished', wait(lambda: idle() and near(pos(), (0, p[1], p[2])), 10), pos()) msgs = errors() From df3b3ac6495a95c8a346d53c637017919dab3b28 Mon Sep 17 00:00:00 2001 From: Rene Hopf Date: Fri, 16 Oct 2026 21:42:43 +0200 Subject: [PATCH 20/21] Revert "motion: return from jogs while paused at the speed of the jogs" This reverts commit 67861e26f96eef7ef2f0bb21667cea519a35fac1. --- docs/src/config/ini-config.adoc | 2 +- docs/src/config/python-interface.adoc | 4 +-- .../getting-started/updating-linuxcnc.adoc | 2 +- src/emc/motion/axis.c | 25 +++---------------- tests/jog-while-paused/test-ui.py | 7 ++---- 5 files changed, 9 insertions(+), 31 deletions(-) diff --git a/docs/src/config/ini-config.adoc b/docs/src/config/ini-config.adoc index 34adcb97837..9fe0aeb6fa5 100644 --- a/docs/src/config/ini-config.adoc +++ b/docs/src/config/ini-config.adoc @@ -952,7 +952,7 @@ Finally, no amount of tweaking will speed up a tool path with lots of small, tig * `MAX_LINEAR_ACCELERATION = 20.0` - (((MAX ACCELERATION))) The maximum acceleration for any axis or coordinated axis move, in 'machine units' per second per second. * `PAUSE_RETURN_LAST = Z` - (((PAUSE RETURN LAST))) The axes that return last when a paused program or MDI command resumes after jogs while paused. The other axes return to the paused position first, together in a straight line, then these, so by default the tool comes down onto the point last. - Empty: all axes return in one straight line. Each group returns no faster along its line than the fastest jog of its axes went, within the axis limits. + Empty: all axes return in one straight line. The return runs at the axis velocity and acceleration limits. * `PLANNER_TYPE = 0` - (((PLANNER TYPE))) Selects the trajectory planner type: 0 = trapezoidal (default), 1 = S-curve with jerk limiting. S-curve planning is only active when `PLANNER_TYPE = 1` AND `MAX_LINEAR_JERK` is 1.0 or above; a smaller value falls back to trapezoidal, with an operator message. diff --git a/docs/src/config/python-interface.adoc b/docs/src/config/python-interface.adoc index 39c6bedd057..aa33bd3c575 100644 --- a/docs/src/config/python-interface.adoc +++ b/docs/src/config/python-interface.adoc @@ -295,8 +295,8 @@ see <> for an example. how far jogs while paused have moved each axis off the paused position. Resume (or step) brings them back to zero first: the spindles and the coolant as they were at the pause, the spindles at speed, the axes other - than `[TRAJ]PAUSE_RETURN_LAST` in a straight line, then those, as fast - as they were jogged, then the program goes on. An abort keeps the machine where it was jogged to. + than `[TRAJ]PAUSE_RETURN_LAST` in a straight line, then those, then the + program goes on. An abort keeps the machine where it was jogged to. *pause_returning*:: '(returns boolean)' - resuming after a pause: spindles, back to the paused position, then on. diff --git a/docs/src/getting-started/updating-linuxcnc.adoc b/docs/src/getting-started/updating-linuxcnc.adoc index b84feb4444b..06ec22bbbbb 100644 --- a/docs/src/getting-started/updating-linuxcnc.adoc +++ b/docs/src/getting-started/updating-linuxcnc.adoc @@ -295,7 +295,7 @@ has stopped the motion. Joints cannot. On resume (or step) LinuxCNC first: waits for the spindles to be at speed; . returns the axes to the paused position: the axes other than `[TRAJ]PAUSE_RETURN_LAST` (default `Z`) together in a straight line, - then those, as fast as they were jogged; + then those, at the axis limits; . goes on with the program. Pausing again during the return stops it; the axes can be jogged again diff --git a/src/emc/motion/axis.c b/src/emc/motion/axis.c index 061ecd68b2c..59fba57f4b2 100644 --- a/src/emc/motion/axis.c +++ b/src/emc/motion/axis.c @@ -39,7 +39,6 @@ typedef struct { simple_tp_t pause_tp; /* planner for jogs while paused, see axis_pause_update() */ double pause_base; /* paused program position plus external offset */ - double pause_peak_vel; /* fastest the jogs while paused moved this axis */ int kb_pjog_active; /* non-zero during a keyboard jog while paused */ int wheel_pjog_active; /* non-zero during a wheel jog while paused */ } emcmot_axis_t; @@ -821,8 +820,7 @@ int axis_calc_motion(double servo_period) ** the external offsets are. On resume the offsets run back to zero first ** (axis_pause_return_start()), so the machine is back where it paused ** before the program continues: the other axes together in a straight -** line, then the [TRAJ]PAUSE_RETURN_LAST ones, each group no faster along -** its line than the fastest of its axes was jogged, within the axis limits. +** line, then the [TRAJ]PAUSE_RETURN_LAST ones, at the axis limits. */ void axis_set_pause_return_last(unsigned mask) @@ -922,9 +920,6 @@ void axis_pause_update(double *pcmd_p[], double servo_period) } } simple_tp_update(&axis->pause_tp, servo_period); - if (!pause_return_phase && fabs(axis->pause_tp.curr_vel) > axis->pause_peak_vel) { - axis->pause_peak_vel = fabs(axis->pause_tp.curr_vel); - } // stay within the soft limits, as update_teleop_with_check() does; // a return only moves back toward the paused position @@ -949,11 +944,10 @@ void axis_pause_update(double *pcmd_p[], double servo_period) /* Send the axes in mask back to zero offset in a straight line: the same ** profile for all, scaled by each one's distance, as fast as the slowest -** axis allows and no faster along the line than the fastest jog of these -** axes went. Returns whether any axis has to move. */ +** axis allows. Returns whether any axis has to move. */ static bool pause_return_plan(unsigned mask) { - double v = 1e99, a = 1e99, j = 1e99, len2 = 0, peak = 0; + double v = 1e99, a = 1e99, j = 1e99; bool jerk = true, any = false; int n; @@ -963,8 +957,6 @@ static bool pause_return_plan(unsigned mask) if (!(mask & (1u << n))) { continue; } if (d < 1e-12) { continue; } any = true; - len2 += d * d; - if (axis->pause_peak_vel > peak) { peak = axis->pause_peak_vel; } if (axis->vel_limit / d < v) { v = axis->vel_limit / d; } if (axis->acc_limit / d < a) { a = axis->acc_limit / d; } if (axis->jerk_limit > 0) { @@ -973,10 +965,6 @@ static bool pause_return_plan(unsigned mask) jerk = false; } } - // v is in line lengths per second - if (any && peak > 0 && peak / sqrt(len2) < v) { - v = peak / sqrt(len2); - } for (n = 0; n < EMCMOT_MAX_AXIS; n++) { emcmot_axis_t *axis = &axis_array[n]; double d = fabs(axis->pause_tp.curr_pos); @@ -1041,12 +1029,6 @@ bool axis_pause_return_update(void) } else if (pause_return_phase == 2 && pause_return_settled(pause_return_last_mask)) { pause_return_phase = 0; } - if (pause_return_phase == 0) { - int n; - for (n = 0; n < EMCMOT_MAX_AXIS; n++) { - axis_array[n].pause_peak_vel = 0; - } - } return pause_return_phase == 0; } @@ -1101,7 +1083,6 @@ void axis_pause_clear(void) tp->active = 0; axis_array[n].kb_pjog_active = 0; axis_array[n].wheel_pjog_active = 0; - axis_array[n].pause_peak_vel = 0; } } diff --git a/tests/jog-while-paused/test-ui.py b/tests/jog-while-paused/test-ui.py index 1b135a86936..545527f7d5e 100755 --- a/tests/jog-while-paused/test-ui.py +++ b/tests/jog-while-paused/test-ui.py @@ -212,13 +212,10 @@ def run_and_pause(prog, at_x): c.auto(linuxcnc.AUTO_RUN, 0) check('stopped at M0', wait(lambda: s.paused and s.pause_jog_ok, 10), pos()) p = pos() -c.jog(linuxcnc.JOG_INCREMENT, False, 2, 4, 2.0) # Z +2 at 4 mm/s +c.jog(linuxcnc.JOG_INCREMENT, False, 2, 20, 2.0) wait(lambda: near(pos(), (p[0], p[1], p[2] + 2))) c.auto(linuxcnc.AUTO_RESUME) -t0 = time.time() -wait(lambda: s.pause_offset[2] == 0, 5) -dt = time.time() - t0 -check('the return goes at the speed of the jog', 0.45 < dt < 1.0, round(dt, 2)) +c.wait_complete() check('M0: back and finished', wait(lambda: idle() and near(pos(), (0, p[1], p[2])), 10), pos()) msgs = errors() From 992da4dab8779d5763bd89133e8b24f2837939d3 Mon Sep 17 00:00:00 2001 From: Rene Hopf Date: Fri, 16 Oct 2026 22:44:13 +0200 Subject: [PATCH 21/21] task: DONE only once a run has ended and motion is back When the last MDI command finished, task reported DONE in the cycle before the run ended, and again before motion was back in joint or world mode. A client waiting for DONE could then see coordinated mode, or have an axis jog refused: linuxcncrsh's test read TELEOP_ENABLE OFF after its MDI commands on CI. Task now reports DONE only when no run is on and motion is in the mode the run went back to (with a 1 s timeout should motion not get there). tests/task-modeless checks that motion is in world mode as soon as an MDI command is DONE, and that a jog right after is accepted. --- src/emc/task/emctaskmain.cc | 18 +++++++++++++++++- tests/task-modeless/test-ui.py | 17 +++++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/src/emc/task/emctaskmain.cc b/src/emc/task/emctaskmain.cc index e68a1005035..d91c9d81367 100644 --- a/src/emc/task/emctaskmain.cc +++ b/src/emc/task/emctaskmain.cc @@ -811,6 +811,12 @@ static const double COORD_WAIT_TIMEOUT = 5.0; static EMC_TRAJ_MODE runPriorMode = EMC_TRAJ_MODE::FREE; static bool runPriorHomed = false; static EMC_TRAJ_MODE idleMode = EMC_TRAJ_MODE::FREE; +// Set by taskRunEnd() until motion is in idleMode. Task is not DONE while +// a run is on or before that, so a client that waits for DONE and then +// jogs finds motion ready. +static bool idleModePending = false; +static double idleModeSince = 0.0; +static const double IDLE_MODE_TIMEOUT = 1.0; // Leave idle for a run. Returns -1, with an operator error, if the run may // not start. @@ -847,6 +853,7 @@ static int taskRunStart(TaskRun run) } coordWaiting = true; coordWaitStart = etime(); + idleModePending = false; if (mdi && taskplanopen) { // what a switch to MDI mode did: MDI does not run with the @@ -874,6 +881,8 @@ static void taskRunEnd() } idleMode = mode; emcTrajSetMode(mode); + idleModePending = true; + idleModeSince = etime(); } // End the run once the interpreter is idle: a program that ran to its end, @@ -3523,6 +3532,12 @@ int main(int argc, char *argv[]) emcStatus->echo_serial_number = emcCommand->serial_number; } + if (idleModePending + && (emcStatus->motion.traj.mode == idleMode + || etime() - idleModeSince > IDLE_MODE_TIMEOUT)) { + idleModePending = false; + } + if (taskPlanError || taskExecuteError || emcStatus->task.execState == EMC_TASK_EXEC::ERROR || emcStatus->motion.status == RCS_STATUS::ERROR || @@ -3536,7 +3551,8 @@ int main(int argc, char *argv[]) mdi_execute_queue.len() == 0 && interp_list.len() == 0 && emcTaskCommand == NULL && - emcStatus->task.interpState == EMC_TASK_INTERP::IDLE) { + emcStatus->task.interpState == EMC_TASK_INTERP::IDLE && + taskRun == TaskRun::NONE && !idleModePending) { emcStatus->status = RCS_STATUS::DONE; emcStatus->task.status = RCS_STATUS::DONE; } else { diff --git a/tests/task-modeless/test-ui.py b/tests/task-modeless/test-ui.py index ccda010040c..d59c101ba92 100755 --- a/tests/task-modeless/test-ui.py +++ b/tests/task-modeless/test-ui.py @@ -111,6 +111,23 @@ def modes(): check('halui sees manual', wait(lambda: hal.get_value('halui.mode.is-manual'))) check('no errors from MDI', not errors()) +# --- DONE means ready: right after wait_complete() motion is back in world +# mode and a world jog is accepted +for i in range(5): + c.mdi('G0 X%d' % (i % 2)) + r = c.wait_complete() + s.poll() + if r != linuxcnc.RCS_DONE or s.motion_mode != linuxcnc.TRAJ_MODE_TELEOP: + break +check('world mode as soon as MDI is DONE', r == linuxcnc.RCS_DONE and s.motion_mode == linuxcnc.TRAJ_MODE_TELEOP, (r, modes())) +c.jog(linuxcnc.JOG_INCREMENT, False, 1, 10, 0.1) +c.wait_complete() +check('a jog right after MDI is accepted', wait(lambda: abs(s.actual_position[1] - 0.1) < 1e-6, 2) and not errors(), s.actual_position[1]) +c.jog(linuxcnc.JOG_INCREMENT, False, 1, 10, -0.1) +wait(lambda: abs(s.actual_position[1]) < 1e-6) +c.mdi('G0 X1') +wait(idle) + # --- wheel jog while idle after MDI hal.set_p('axis.x.jog-enable', '1') hal.set_p('axis.x.jog-counts', '100')