Added tests for new EL734 driver
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,5 +1,6 @@
|
||||
# Ignore all .pyc files
|
||||
*.pyc
|
||||
__pycache__
|
||||
|
||||
# Ignore the EPICS environment variables (this file is recreated by ioc/startioc.py via config.yaml)
|
||||
config.cmd
|
||||
|
||||
12
config.yaml
12
config.yaml
@@ -1,7 +1,8 @@
|
||||
pvprefix: DRVTESTS
|
||||
versions:
|
||||
turboPmac: "1.3.1"
|
||||
masterMacs: "1.1"
|
||||
turboPmac: "1.5"
|
||||
masterMacs: "1.4"
|
||||
el734: "mathis_s"
|
||||
controllers:
|
||||
turboPmac1:
|
||||
ip: "172.28.101.24"
|
||||
@@ -11,5 +12,10 @@ controllers:
|
||||
masterMacs1:
|
||||
ip: "172.28.101.66"
|
||||
port: 1912
|
||||
busypoll: 0.05
|
||||
busypoll: 0.10
|
||||
idlepoll: 1
|
||||
el734_1:
|
||||
ip: "sinqtest-ts"
|
||||
port: 3002
|
||||
busypoll: 0.5
|
||||
idlepoll: 0.5
|
||||
|
||||
12
ioc/motors/el734_1.cmd
Normal file
12
ioc/motors/el734_1.cmd
Normal file
@@ -0,0 +1,12 @@
|
||||
epicsEnvSet("NAME","el734_1")
|
||||
epicsEnvSet("ASYN_PORT","p$(NAME)")
|
||||
|
||||
drvAsynIPPortConfigure("$(ASYN_PORT)", "sinqtest-ts:3002")
|
||||
el734Controller("$(NAME)","$(ASYN_PORT)",8,0.5,0.5,10);
|
||||
el734Axis("$(NAME)",1);
|
||||
|
||||
epicsEnvSet("SINQDBPATH","$(el734_DB)/sinqMotor.db")
|
||||
dbLoadTemplate("$(IOCDIR)/motors/$(NAME).substitutions", "INSTR=$(PVPREFIX):$(NAME):,CONTROLLER=$(NAME)")
|
||||
epicsEnvSet("SINQDBPATH","$(el734_DB)/el734.db")
|
||||
dbLoadTemplate("$(IOCDIR)/motors/$(NAME).substitutions", "INSTR=$(PVPREFIX):$(NAME):,CONTROLLER=$(NAME)")
|
||||
# IOC shell does not execute the last line, hence an empty line at the end is needed
|
||||
6
ioc/motors/el734_1.substitutions
Normal file
6
ioc/motors/el734_1.substitutions
Normal file
@@ -0,0 +1,6 @@
|
||||
file $(SINQDBPATH)
|
||||
{
|
||||
pattern
|
||||
{ AXIS, M, EGU, DIR, MRES, ENABLEMOVWATCHDOG, LIMITSOFFSET, CANSETSPEED }
|
||||
{ 1, "ax1", mm, Pos, 0.001, 1, 1.0, 1 }
|
||||
}
|
||||
@@ -1,5 +1,3 @@
|
||||
# Configuration for the "modern" masterMacs-Axes
|
||||
|
||||
epicsEnvSet("NAME","masterMacs1")
|
||||
epicsEnvSet("ASYN_PORT","p$(NAME)")
|
||||
|
||||
@@ -12,3 +10,4 @@ masterMacsAxis("$(NAME)",2);
|
||||
|
||||
epicsEnvSet("SINQDBPATH","$(masterMacs_DB)/sinqMotor.db")
|
||||
dbLoadTemplate("$(IOCDIR)/motors/$(NAME).substitutions", "INSTR=$(PVPREFIX):$(NAME):,CONTROLLER=$(NAME)")
|
||||
# IOC shell does not execute the last line, hence an empty line at the end is needed
|
||||
@@ -17,3 +17,4 @@ epicsEnvSet("SINQDBPATH","$(turboPmac_DB)/sinqMotor.db")
|
||||
dbLoadTemplate("$(IOCDIR)/motors/$(NAME).substitutions", "INSTR=$(PVPREFIX):$(NAME):,CONTROLLER=$(NAME)")
|
||||
epicsEnvSet("SINQDBPATH","$(turboPmac_DB)/turboPmac.db")
|
||||
dbLoadTemplate("$(IOCDIR)/motors/$(NAME).substitutions", "INSTR=$(PVPREFIX):$(NAME):,CONTROLLER=$(NAME)")
|
||||
# IOC shell does not execute the last line, hence an empty line at the end is needed
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
require turboPmac, $(TURBOPMAC_VERSION)
|
||||
require masterMacs, $(MASTERMACS_VERSION)
|
||||
require el734, $(EL734_VERSION)
|
||||
|
||||
################################################################################
|
||||
# Motors
|
||||
@@ -12,6 +13,7 @@ require masterMacs, $(MASTERMACS_VERSION)
|
||||
# Initialize the motors itself
|
||||
< motors/turboPmac1.cmd
|
||||
< motors/masterMacs1.cmd
|
||||
< motors/el734_1.cmd
|
||||
|
||||
# Create the test record which is used to detect if the IOC is running
|
||||
dbLoadRecords("$(IOCDIR)/db/ready.db", "PVPREFIX=$(PVPREFIX)")
|
||||
|
||||
11
ioc/startioc
11
ioc/startioc
@@ -30,6 +30,8 @@ def startioc():
|
||||
f'epicsEnvSet("TURBOPMAC_VERSION", "{config["versions"]["turboPmac"]}")\n')
|
||||
out.write(
|
||||
f'epicsEnvSet("MASTERMACS_VERSION", "{config["versions"]["masterMacs"]}")\n')
|
||||
out.write(
|
||||
f'epicsEnvSet("EL734_VERSION", "{config["versions"]["el734"]}")\n')
|
||||
|
||||
out.write(
|
||||
f'epicsEnvSet("TURBOPMAC1_IP", "{config["controllers"]["turboPmac1"]["ip"]}")\n')
|
||||
@@ -49,6 +51,15 @@ def startioc():
|
||||
out.write(
|
||||
f'epicsEnvSet("MASTERMACS1_IDLEPOLL", "{config["controllers"]["masterMacs1"]["idlepoll"]}")\n')
|
||||
|
||||
out.write(
|
||||
f'epicsEnvSet("EL734_1_IP", "{config["controllers"]["el734_1"]["ip"]}")\n')
|
||||
out.write(
|
||||
f'epicsEnvSet("EL734_1_PORT", "{config["controllers"]["el734_1"]["port"]}")\n')
|
||||
out.write(
|
||||
f'epicsEnvSet("EL734_1_BUSYPOLL", "{config["controllers"]["el734_1"]["busypoll"]}")\n')
|
||||
out.write(
|
||||
f'epicsEnvSet("EL734_1_IDLEPOLL", "{config["controllers"]["el734_1"]["idlepoll"]}")\n')
|
||||
|
||||
# Set environment variables
|
||||
os.environ["EPICS_BASE"] = "/usr/local/epics/base-7.0.7"
|
||||
os.environ["EPICS_HOST_ARCH"] = "RHEL8-x86_64"
|
||||
|
||||
16
runtests
16
runtests
@@ -36,7 +36,7 @@ for arg in sys.argv[1:]:
|
||||
extra_args.append(arg)
|
||||
|
||||
# Find all axes paths (pa) within all controller paths (pc)
|
||||
folders =[]
|
||||
folders = []
|
||||
for pc in Path("tests").glob("*"):
|
||||
if pc.is_dir() and "__pycache__" not in pc.parts:
|
||||
for pa in Path(pc).glob("*"):
|
||||
@@ -51,9 +51,12 @@ if not path_args:
|
||||
enabled_folders = folders
|
||||
else:
|
||||
for folder in folders:
|
||||
if any(Path(arg).resolve().as_posix().startswith(Path(folder).resolve().as_posix()) for arg in path_args):
|
||||
if any(Path(folder).resolve().as_posix().startswith(Path(arg).resolve().as_posix()) for arg in path_args):
|
||||
enabled_folders.append(folder)
|
||||
|
||||
if not enabled_folders:
|
||||
print(f"No tests were found within the specified path {path_args}")
|
||||
|
||||
# Check if the IOC is running and try to start it, if it isn't
|
||||
try:
|
||||
check_ioc_running()
|
||||
@@ -77,14 +80,7 @@ except IocNotRunning:
|
||||
# Run each enabled folder's relevant tests in parallel
|
||||
processes = []
|
||||
for folder in enabled_folders:
|
||||
folder_path_args = (
|
||||
[arg for arg in path_args if Path(arg).resolve().as_posix().startswith(Path(folder).resolve().as_posix())]
|
||||
if path_args else [folder.as_posix()]
|
||||
)
|
||||
|
||||
command = ["pytest"] + folder_path_args + extra_args
|
||||
print(f"Running: {' '.join(command)}")
|
||||
|
||||
command = ["pytest"] + [str(folder)] + extra_args
|
||||
proc = subprocess.Popen(command)
|
||||
processes.append(proc)
|
||||
|
||||
|
||||
@@ -285,3 +285,7 @@ class TurboPMAC(SinqMotor):
|
||||
|
||||
class MasterMACS(SinqMotor):
|
||||
pass
|
||||
|
||||
|
||||
class EL734(SinqMotor):
|
||||
pass
|
||||
|
||||
@@ -6,9 +6,11 @@ def home(motor, forward):
|
||||
|
||||
encoder = motor.get_pv('encoder_type', as_string=True)
|
||||
if encoder == 'absolute':
|
||||
is_absolute = True
|
||||
can_home = False
|
||||
elif encoder == 'incremental':
|
||||
is_absolute = False
|
||||
can_home = True
|
||||
elif encoder == 'none':
|
||||
can_home = False
|
||||
else:
|
||||
raise ValueError(f'Unknown encoder type {encoder}')
|
||||
|
||||
@@ -21,16 +23,7 @@ def home(motor, forward):
|
||||
|
||||
motor.wait_for_start()
|
||||
|
||||
if is_absolute:
|
||||
# EPICS initially assumes the motor is moving and sets it into moving state.
|
||||
# However, after the first poll it should realize that the motor is in fact not moving.
|
||||
time.sleep(2 * motor.busypoll)
|
||||
|
||||
# Motor should not move at all
|
||||
assert motor.get_pv('moving') == 0
|
||||
assert motor.get_pv('donemoving') == 1
|
||||
assert not motor.has_error()
|
||||
else:
|
||||
if can_home:
|
||||
# The controller might take a bit of time to actually start the movement,
|
||||
# therefore we wait a bit.
|
||||
time.sleep(2 * motor.busypoll)
|
||||
@@ -48,6 +41,15 @@ def home(motor, forward):
|
||||
assert motor.get_pv('donemoving') == 1
|
||||
assert not motor.has_error()
|
||||
assert motor.is_homed()
|
||||
else:
|
||||
# EPICS initially assumes the motor is moving and sets it into moving state.
|
||||
# However, after the first poll it should realize that the motor is in fact not moving.
|
||||
time.sleep(3 * motor.busypoll)
|
||||
|
||||
# Motor should not move at all
|
||||
assert motor.get_pv('moving') == 0
|
||||
assert motor.get_pv('donemoving') == 1
|
||||
assert not motor.has_error()
|
||||
|
||||
def start_home_while_moving(motor, target, forward):
|
||||
"""
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import time
|
||||
|
||||
def reset(motor, target):
|
||||
"""
|
||||
Reset the motor for the next test. This means the following things:
|
||||
@@ -7,9 +9,18 @@ def reset(motor, target):
|
||||
4) Moving to zero
|
||||
"""
|
||||
|
||||
# Wait a bit before starting each test so the IOC has some time
|
||||
# to recover from any previous failed tests.
|
||||
time.sleep(0.2)
|
||||
|
||||
if target is None:
|
||||
target = motor.default_position
|
||||
|
||||
motor.put_pv('stop', 1)
|
||||
motor.wait_for_done()
|
||||
motor.put_pv('reseterrorpv', 1)
|
||||
motor.put_pv('enable', 1)
|
||||
motor.wait_disabled()
|
||||
motor.enable_and_wait()
|
||||
motor.move_and_wait(target)
|
||||
assert motor.at_target(target)
|
||||
assert not motor.has_error()
|
||||
|
||||
@@ -21,7 +21,7 @@ def check_ioc_running():
|
||||
return
|
||||
except TimeoutError:
|
||||
# IOC startup failed in the given time -> Raise an error
|
||||
path = Path.cwd() / 'startioc'
|
||||
path = Path.cwd() / 'ioc' / 'startioc'
|
||||
raise IocNotRunning(f'Start the test IOC first by running {path}')
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
|
||||
0
tests/masterMacs1/_ax1/__init__.py → tests/el734_1/__init__.py
Executable file → Normal file
0
tests/masterMacs1/_ax1/__init__.py → tests/el734_1/__init__.py
Executable file → Normal file
0
tests/el734_1/ax1/__init__.py
Normal file
0
tests/el734_1/ax1/__init__.py
Normal file
19
tests/el734_1/ax1/conftest.py
Normal file
19
tests/el734_1/ax1/conftest.py
Normal file
@@ -0,0 +1,19 @@
|
||||
# This module defines fixtures which are shared for all tests of motor "lin1".
|
||||
import time
|
||||
|
||||
import pytest
|
||||
from setup.classes import EL734
|
||||
|
||||
# Prepare the motor at the start of the test by resetting and homing it.
|
||||
@pytest.fixture(scope="session", autouse=True)
|
||||
def reset_and_home():
|
||||
mot = EL734('el734_1', 'ax1')
|
||||
mot.put_pv('stop', 1)
|
||||
mot.put_pv('reseterrorpv', 1)
|
||||
mot.put_pv('homeforward', 1)
|
||||
time.sleep(1)
|
||||
mot.wait_for_done()
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def motor():
|
||||
return EL734('el734_1', 'ax1')
|
||||
123
tests/el734_1/ax1/test_common.py
Normal file
123
tests/el734_1/ax1/test_common.py
Normal file
@@ -0,0 +1,123 @@
|
||||
# Run a selection of common tests
|
||||
|
||||
import pytest
|
||||
|
||||
from setup.move import *
|
||||
from setup.home import *
|
||||
from setup.sinqMotor.limits import *
|
||||
from setup.sinqMotor.speed import *
|
||||
|
||||
|
||||
def test_move_to_low_limit_switch(motor):
|
||||
motor.put_pv('stop', 1)
|
||||
motor.wait_for_done()
|
||||
move_to_low_limit_switch(motor)
|
||||
|
||||
|
||||
def test_move_to_high_limit_switch(motor):
|
||||
motor.put_pv('stop', 1)
|
||||
motor.wait_for_done()
|
||||
move_to_high_limit_switch(motor)
|
||||
|
||||
|
||||
def test_move_while_move_same_direction(motor):
|
||||
motor.put_pv('stop', 1)
|
||||
motor.wait_for_done()
|
||||
move_while_move(motor, -30, -10, 2)
|
||||
|
||||
|
||||
def test_move_while_move_opposite_direction(motor):
|
||||
motor.put_pv('stop', 1)
|
||||
motor.wait_for_done()
|
||||
move_while_move(motor, 10, -10, 2)
|
||||
|
||||
|
||||
def test_stop(motor):
|
||||
stop(motor, -60)
|
||||
|
||||
|
||||
def test_stop_then_move(motor):
|
||||
motor.put_pv('stop', 1)
|
||||
motor.wait_for_done()
|
||||
stop_then_move(motor, 10)
|
||||
|
||||
@pytest.mark.stresstest
|
||||
def test_stop_then_move_stress(motor):
|
||||
motor.put_pv('stop', 1)
|
||||
motor.wait_for_done()
|
||||
for _ in range(50):
|
||||
stop_then_move(motor, 5)
|
||||
stop_then_move(motor, 0)
|
||||
|
||||
|
||||
def test_speed_fields_valid(motor):
|
||||
motor.put_pv('stop', 1)
|
||||
motor.wait_for_done()
|
||||
speed_fields_valid(motor)
|
||||
|
||||
|
||||
def test_set_minspeed_maxspeed_meanspeed(motor):
|
||||
motor.put_pv('stop', 1)
|
||||
motor.wait_for_done()
|
||||
set_minspeed_maxspeed_meanspeed(motor)
|
||||
|
||||
|
||||
def test_set_invalid_speed_above_min_below_max(motor):
|
||||
motor.put_pv('stop', 1)
|
||||
motor.wait_for_done()
|
||||
set_invalid_speed_above_min_below_max(motor)
|
||||
|
||||
|
||||
def test_set_speed_and_move(motor):
|
||||
motor.put_pv('stop', 1)
|
||||
motor.wait_for_done()
|
||||
set_speed_and_move(motor, motor.get_pv('maxspeed'), 5)
|
||||
set_speed_and_move(motor, 0.5*motor.get_pv('maxspeed'), 0)
|
||||
|
||||
|
||||
@pytest.mark.stresstest
|
||||
def test_set_speed_and_move_stress(motor):
|
||||
motor.put_pv('stop', 1)
|
||||
motor.wait_for_done()
|
||||
for _ in range(50):
|
||||
set_speed_and_move(motor, motor.get_pv('maxspeed'), 5)
|
||||
set_speed_and_move(motor, 0.5*motor.get_pv('maxspeed'), 0)
|
||||
|
||||
|
||||
def test_targets_outside_limits(motor):
|
||||
motor.put_pv('stop', 1)
|
||||
motor.wait_for_done()
|
||||
targets_outside_limits(motor)
|
||||
|
||||
|
||||
def test_home(motor):
|
||||
motor.put_pv('stop', 1)
|
||||
motor.wait_for_done()
|
||||
home(motor, True)
|
||||
|
||||
|
||||
def test_start_home_while_moving(motor):
|
||||
motor.put_pv('stop', 1)
|
||||
motor.wait_for_done()
|
||||
start_home_while_moving(motor, 15, True)
|
||||
|
||||
|
||||
def test_start_home_while_moving(motor):
|
||||
motor.put_pv('stop', 1)
|
||||
motor.wait_for_done()
|
||||
start_home_while_moving(motor, 15, True)
|
||||
|
||||
|
||||
def test_move_then_home(motor):
|
||||
motor.put_pv('stop', 1)
|
||||
motor.wait_for_done()
|
||||
move_then_home(motor, 15, True)
|
||||
|
||||
|
||||
def test_home_then_move(motor):
|
||||
motor.put_pv('stop', 1)
|
||||
motor.wait_for_done()
|
||||
home_then_move(motor, 15, True)
|
||||
|
||||
# def test_reread_limits_from_hw(motor):
|
||||
# reread_limits_from_hw(motor)
|
||||
@@ -1,9 +0,0 @@
|
||||
# This module defines fixtures which are shared for all tests of motor "lin1".
|
||||
|
||||
import pytest
|
||||
from setup.classes import MasterMACS
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def motor():
|
||||
return MasterMACS('masterMacs1', 'ax1')
|
||||
@@ -1,50 +0,0 @@
|
||||
# Run a selection of common tests
|
||||
|
||||
from setup.move import *
|
||||
from setup.sinqMotor.limits import *
|
||||
from setup.home import *
|
||||
from setup.sinqMotor.masterMacs.reset import reset
|
||||
|
||||
|
||||
def test_reset(motor):
|
||||
reset(motor, 4)
|
||||
reset(motor, 2)
|
||||
|
||||
|
||||
def test_move_to_low_limit_switch(motor):
|
||||
reset(motor, 1)
|
||||
move_to_low_limit_switch(motor)
|
||||
|
||||
|
||||
def test_move_to_high_limit_switch(motor):
|
||||
reset(motor, 1)
|
||||
move_to_high_limit_switch(motor)
|
||||
|
||||
|
||||
def test_move_while_move(motor):
|
||||
reset(motor, 1)
|
||||
move_while_move(motor, -60, -20)
|
||||
|
||||
|
||||
def test_stop(motor):
|
||||
reset(motor, 1)
|
||||
stop(motor, 18)
|
||||
|
||||
|
||||
def test_home(motor):
|
||||
reset(motor, 1)
|
||||
home(motor, True)
|
||||
|
||||
|
||||
def test_start_home_while_moving(motor):
|
||||
reset(motor, 1)
|
||||
start_home_while_moving(motor, 10, True)
|
||||
|
||||
|
||||
def test_start_home_while_moving(motor):
|
||||
reset(motor, 1)
|
||||
start_home_while_moving(motor, 10, True)
|
||||
|
||||
|
||||
# def test_reread_limits_from_hw(motor):
|
||||
# reread_limits_from_hw(motor)
|
||||
0
tests/masterMacs1/ax1/__init__.py
Executable file
0
tests/masterMacs1/ax1/__init__.py
Executable file
21
tests/masterMacs1/ax1/conftest.py
Executable file
21
tests/masterMacs1/ax1/conftest.py
Executable file
@@ -0,0 +1,21 @@
|
||||
# This module defines fixtures which are shared for all tests of motor "ax1".
|
||||
import time
|
||||
|
||||
import pytest
|
||||
from setup.classes import MasterMACS
|
||||
|
||||
# Prepare the motor at the start of the test by resetting and homing it.
|
||||
@pytest.fixture(scope="session", autouse=True)
|
||||
def reset_and_home():
|
||||
mot = MasterMACS('masterMacs1', 'ax1')
|
||||
mot.put_pv('stop', 1)
|
||||
mot.put_pv('reseterrorpv', 1)
|
||||
mot.wait_disabled()
|
||||
mot.enable_and_wait()
|
||||
mot.put_pv('homeforward', 1)
|
||||
time.sleep(1)
|
||||
mot.wait_for_done()
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def motor():
|
||||
return MasterMACS('masterMacs1', 'ax1')
|
||||
50
tests/masterMacs1/ax1/test_common.py
Executable file
50
tests/masterMacs1/ax1/test_common.py
Executable file
@@ -0,0 +1,50 @@
|
||||
# Run a selection of common tests
|
||||
|
||||
from setup.move import *
|
||||
from setup.sinqMotor.limits import *
|
||||
from setup.home import *
|
||||
from setup.sinqMotor.masterMacs.reset import reset
|
||||
|
||||
|
||||
def test_reset(motor):
|
||||
reset(motor, 4)
|
||||
reset(motor, 2)
|
||||
|
||||
|
||||
# def test_move_to_low_limit_switch(motor):
|
||||
# reset(motor, 1)
|
||||
# move_to_low_limit_switch(motor)
|
||||
|
||||
|
||||
# def test_move_to_high_limit_switch(motor):
|
||||
# reset(motor, 1)
|
||||
# move_to_high_limit_switch(motor)
|
||||
|
||||
|
||||
# def test_move_while_move(motor):
|
||||
# reset(motor, 1)
|
||||
# move_while_move(motor, -60, -20)
|
||||
|
||||
|
||||
# def test_stop(motor):
|
||||
# reset(motor, 1)
|
||||
# stop(motor, 18)
|
||||
|
||||
|
||||
# def test_home(motor):
|
||||
# reset(motor, 1)
|
||||
# home(motor, True)
|
||||
|
||||
|
||||
# def test_start_home_while_moving(motor):
|
||||
# reset(motor, 1)
|
||||
# start_home_while_moving(motor, 10, True)
|
||||
|
||||
|
||||
# def test_start_home_while_moving(motor):
|
||||
# reset(motor, 1)
|
||||
# start_home_while_moving(motor, 10, True)
|
||||
|
||||
|
||||
# def test_reread_limits_from_hw(motor):
|
||||
# reread_limits_from_hw(motor)
|
||||
Reference in New Issue
Block a user