Commit db872c3c authored by Federico Vaga's avatar Federico Vaga

tst: add pytest

Signed-off-by: Federico Vaga's avatarFederico Vaga <federico.vaga@cern.ch>
parent 6a9d7654
"""
SPDX-License-Identifier: GPL-3.0-or-later
SPDX-FileCopyrightText: 2020 CERN
"""
import pytest
from PyFmcFineDelay import FmcFineDelay
@pytest.fixture(scope="function")
def fmcfd():
fd = FmcFineDelay(pytest.fd_id)
yield fd
for chan in fd.chan:
chan.disable()
def pytest_addoption(parser):
parser.addoption("--fd-id", type=lambda x : int(x, 16),
required=True, help="Fmc Fine-Delay Linux Identifier")
parser.addoption("--channel", type=int, default=[],
action="append", choices=range(FmcFineDelay.CHANNEL_NUMBER),
help="Channel(s) to be used for acquisition tests. Default all channels")
def pytest_configure(config):
pytest.fd_id = config.getoption("--fd-id")
pytest.channels = config.getoption("--channel")
if len(pytest.channels) == 0:
pytest.channels = range(FmcFineDelay.CHANNEL_NUMBER)
# SPDX-License-Identifier: GPL-3.0-or-later
# SPDX-FileCopyrightText: 2020 CERN
[pytest]
addopts = -v -p no:cacheprovider
\ No newline at end of file
"""
SPDX-License-Identifier: GPL-3.0-or-later
SPDX-FileCopyrightText: 2020 CERN
"""
import pytest
import random
from PyFmcFineDelay import FmcFineDelay, FmcFineDelayTime
@pytest.fixture(scope="function", params=range(0, FmcFineDelay.CHANNEL_NUMBER))
def fmcfd_chan(request):
fd = FmcFineDelay(pytest.fd_id)
yield fd.chan[request.param]
class TestFmcfdGetterSetter(object):
def test_disable(self, fmcfd):
for chan in fmcfd.chan:
chan.disable()
assert chan.disabled == True
@pytest.mark.parametrize("enable", [True, False])
def test_tdc_disable_input(self, fmcfd, enable):
fmcfd.tdc.enable_input = enable
assert fmcfd.tdc.enable_input == enable
@pytest.mark.parametrize("enable", [True, False])
def test_tdc_disable_tstamp(self, fmcfd, enable):
fmcfd.tdc.enable_tstamp = enable
assert fmcfd.tdc.enable_tstamp == enable
@pytest.mark.parametrize("term", [True, False])
def test_tdc_termination(self, fmcfd, term):
"""Set temination and read it back"""
fmcfd.tdc.termination = term
assert term == fmcfd.tdc.termination
@pytest.mark.parametrize("width,period,count", [(FmcFineDelay.FmcFineDelayChannel.OUT_PULSE_DELAY_MIN_WIDTH_PS,
FmcFineDelay.FmcFineDelayChannel.OUT_PULSE_DELAY_MIN_PERIOD_PS,
FmcFineDelay.FmcFineDelayChannel.OUT_PULSE_MAX_COUNT + 1),
(FmcFineDelay.FmcFineDelayChannel.OUT_PULSE_DELAY_MIN_WIDTH_PS - 1,
FmcFineDelay.FmcFineDelayChannel.OUT_PULSE_DELAY_MIN_PERIOD_PS,
1),
(FmcFineDelay.FmcFineDelayChannel.OUT_PULSE_DELAY_MAX_WIDTH_PS + 1,
FmcFineDelay.FmcFineDelayChannel.OUT_PULSE_DELAY_MAX_PERIOD_PS,
1),
(FmcFineDelay.FmcFineDelayChannel.OUT_PULSE_DELAY_MIN_WIDTH_PS,
FmcFineDelay.FmcFineDelayChannel.OUT_PULSE_DELAY_MIN_PERIOD_PS - 1,
1),
(FmcFineDelay.FmcFineDelayChannel.OUT_PULSE_DELAY_MAX_WIDTH_PS,
FmcFineDelay.FmcFineDelayChannel.OUT_PULSE_DELAY_MAX_PERIOD_PS + 1,
1),
])
def test_pulse_delay_invalid(self, fmcfd_chan, width, period, count):
"""The pulse generation can't work with invalid parameters"""
with pytest.raises(OSError):
fmcfd_chan.pulse_delay(FmcFineDelayTime(1, 0, 0),
width, period, count)
@pytest.mark.parametrize("width,period,count", [(FmcFineDelay.FmcFineDelayChannel.OUT_PULSE_DELAY_MIN_WIDTH_PS,
FmcFineDelay.FmcFineDelayChannel.OUT_PULSE_DELAY_MIN_PERIOD_PS,
FmcFineDelay.FmcFineDelayChannel.OUT_PULSE_MAX_COUNT + 1),
(FmcFineDelay.FmcFineDelayChannel.OUT_PULSE_MIN_WIDTH_PS,
FmcFineDelay.FmcFineDelayChannel.OUT_PULSE_MIN_PERIOD_PS,
FmcFineDelay.FmcFineDelayChannel.OUT_PULSE_MAX_COUNT + 1),
(FmcFineDelay.FmcFineDelayChannel.OUT_PULSE_MIN_WIDTH_PS - 1,
FmcFineDelay.FmcFineDelayChannel.OUT_PULSE_MIN_PERIOD_PS,
1),
(FmcFineDelay.FmcFineDelayChannel.OUT_PULSE_MAX_WIDTH_PS + 1,
FmcFineDelay.FmcFineDelayChannel.OUT_PULSE_MAX_PERIOD_PS,
1),
(FmcFineDelay.FmcFineDelayChannel.OUT_PULSE_MIN_WIDTH_PS,
FmcFineDelay.FmcFineDelayChannel.OUT_PULSE_MIN_PERIOD_PS - 1,
1),
(FmcFineDelay.FmcFineDelayChannel.OUT_PULSE_MAX_WIDTH_PS,
FmcFineDelay.FmcFineDelayChannel.OUT_PULSE_MAX_PERIOD_PS + 1,
1),
])
def test_pulse_generate_invalid(self, fmcfd_chan, width, period, count):
"""The pulse generation can't work with invalid parameters"""
with pytest.raises(OSError):
fmcfd_chan.pulse_generate(FmcFineDelayTime(1, 0, 0),
width, period, count)
"""
SPDX-License-Identifier: GPL-3.0-or-later
SPDX-FileCopyrightText: 2020 CERN
"""
import pytest
import select
import time
import os
from PyFmcFineDelay import FmcFineDelay, FmcFineDelayTime
@pytest.fixture(scope="function")
def fmcfd():
fd = FmcFineDelay(pytest.fd_id)
for ch in fd.chan:
ch.disable()
yield fd
for ch in fd.chan:
ch.disable()
@pytest.fixture(scope="function", params=pytest.channels)
def fmcfd_chan(request, fmcfd):
yield fmcfd.chan[request.param]
@pytest.fixture(scope="function")
def fmcfd_tdc(request, fmcfd):
fmcfd.tdc.enable_input = False
fmcfd.tdc.enable_tstamp = False
fmcfd.tdc.termination = False
fmcfd.tdc.flush()
fmcfd.tdc.enable_tstamp = True
fmcfd.tdc.enable_input = True
yield fmcfd.tdc
fmcfd.tdc.enable_input = False
fmcfd.tdc.enable_tstamp = False
class TestFmcfdLoop(object):
"""
The test needs a lemo cable (1ns) that connects all outputs
to the input channel
input
chan o------.
output |
chan 1 o-------+
chan 2 o-------+
chan 3 o-------+
chan 4 o-------`
"""
@pytest.mark.parametrize("count", [1, 2, 3, 5, 7, 10,
100, 1000, 10000, 65535])
def test_output_counter(self, fmcfd, fmcfd_chan, fmcfd_tdc, count):
"""
In pulse mode, the Fine-Delay generates the exact number of
required pulses and we are able to read them all from the input
channel.
"""
period = 1000000000 # 1kHz
poll = select.poll()
poll.register(fmcfd_tdc.fileno, select.POLLIN)
ts = []
fmcfd_chan.pulse_generate(fmcfd.time + FmcFineDelayTime(2, 0, 0),
200000, # 200ns
period, count)
timeout = time.time() + ((count * period)/1000000000000.0) + 10
while len(ts) < count and time.time() < timeout:
if len(poll.poll(1)) == 0:
continue
t = fmcfd_tdc.read(100, os.O_NONBLOCK)
assert len(t) > 0
ts = ts + t
assert len(ts) == count
assert len(poll.poll(int(period / 1000000000.0))) == 0
del ts
def test_input_sequence_number(self, capsys, fmcfd_chan, fmcfd_tdc):
"""
The input channel has time-stamps with increasing sequence number
with step 1.
"""
count = 10000
pending = count
period = 1000000000 # 1kHz
poll = select.poll()
poll.register(fmcfd_tdc.fileno, select.POLLIN)
fmcfd_chan.pulse_generate(fmcfd_chan.dev.time + FmcFineDelayTime(2, 0, 0),
200000, # 200ns
period, count)
timeout = time.time() + ((count * period)/1000000000000.0) + 10
prev_ts = None
while pending > 0 and time.time() < timeout:
if len(poll.poll(1)) == 0:
continue
ts = fmcfd_tdc.read(pending, os.O_NONBLOCK)
assert len(ts) > 0
for i in range(len(ts)):
if prev_ts is not None:
assert ts[i].seq_id == prev_ts.seq_id + 1, "i:{:d}, cur: {:s}, prev: {:s}".format(i, str(ts[i]), str(prev_ts))
prev_ts = ts[i]
pending -= len(ts)
assert pending == 0
@pytest.mark.parametrize("start_rel", [FmcFineDelayTime(0, 78125000, 0), # + 0.0625s
FmcFineDelayTime(0, 15625000, 0), # + 0.125s
FmcFineDelayTime(0, 31250000, 0), # + 0.25s
FmcFineDelayTime(0, 62500000, 0), # + 0.5s
FmcFineDelayTime(1, 0, 0), # + 1s
FmcFineDelayTime(1, 78125000, 0), # + 1.0625s
FmcFineDelayTime(1, 15625000, 0), # + 1.125s
FmcFineDelayTime(1, 31250000, 0), # + 1.25s
FmcFineDelayTime(1, 62500000, 0), # + 1.5s
FmcFineDelayTime(2, 0, 0), # + 2s
FmcFineDelayTime(60, 0, 0), # + 60s
FmcFineDelayTime(120, 0, 0), # + 120s
])
@pytest.mark.parametrize("wr", [False, True])
def test_output_input_start(self, fmcfd_chan, fmcfd_tdc,
wr, start_rel):
"""
The output channel generates a pulse at a given time and the input
channel timestamps it. The two times must be almost the same excluding
the propagation time (cable length).
"""
fmcfd_chan.dev.whiterabbit_mode = wr
poll = select.poll()
poll.register(fmcfd_tdc.fileno, select.POLLIN)
ts = []
start = fmcfd_chan.dev.time + start_rel
print(start)
print(start_rel)
fmcfd_chan.pulse_generate(start, 200000, 400000, 1)
assert len(poll.poll(int(float(start_rel) * 1000) + 2000)) > 0
ts = fmcfd_tdc.read(1, os.O_NONBLOCK)
assert len(ts) == 1
assert start.seconds == ts[0].seconds
assert ts[0].coarse - start.coarse <= 1 # there is a ~1ns cable
@pytest.mark.parametrize("period_ps", [1000000, # 1us 1MHz
10000000, # 10us 100kHz
100000000, # 100us 10kHz
1000000000, # 1ms 1kHz
10000000000, # 10ms 100Hz
100000000000, # 100ms 10Hz
1000000000000, # 1s 1Hz
])
def test_output_period(self, fmcfd_chan, fmcfd_tdc, period_ps):
"""
The test produces pulses on the given channels and catch them using
the on board TDC. The period between two timestamps must be as close
as possible (ideally equal) to the period used to generate them.
"""
poll = select.poll()
poll.register(fmcfd_tdc.fileno, select.POLLIN)
ts = []
start = fmcfd_chan.dev.time + FmcFineDelayTime(2, 0, 0, 0, 0)
fmcfd_chan.pulse_generate(start,
200000, # 200ns
period_ps, 10)
time.sleep(2 + (10 * period_ps) / 1000000000000.0)
assert len(poll.poll(10000)) > 0
ts = fmcfd_tdc.read(10, os.O_NONBLOCK)
assert len(ts) == 10
prev_ts = None
for i in range(len(ts)):
if prev_ts is not None:
assert ts[i].seq_id == prev_ts.seq_id + 1
period_ts = ts[i] - prev_ts
period = FmcFineDelayTime.from_pico(period_ps)
if period > period_ts:
diff = period - period_ts
else:
diff = period_ts - period
assert diff < FmcFineDelayTime(0, 1, 0), \
"period difference {:s}\n\tcurr: {:s}\n\tprev: {:s}\n\tperi: {:s}".format(str(diff),
str(ts[i]),
str(prev_ts),
str(period_ts))
prev_ts = ts[i]
"""
SPDX-License-Identifier: GPL-3.0-or-later
SPDX-FileCopyrightText: 2020 CERN
"""
import pytest
class TestFmcfdTemperature(object):
def test_temperature_read(self, fmcfd):
assert 0 < fmcfd.temperature
"""
SPDX-License-Identifier: GPL-3.0-or-later
SPDX-FileCopyrightText: 2020 CERN
"""
import pytest
import random
import time
from PyFmcFineDelay import FmcFineDelayTime
class TestFmcfdTime(object):
def test_whiterabbit_mode(self, fmcfd):
"""It must be possible to toggle the White-Rabbit status"""
fmcfd.whiterabbit_mode = True
assert fmcfd.whiterabbit_mode == True
fmcfd.whiterabbit_mode = False
assert fmcfd.whiterabbit_mode == False
def test_time_set_fail_wr(self, fmcfd):
"""Time can't be changed when White-Rabbit is enabled"""
fmcfd.whiterabbit_mode = True
with pytest.raises(OSError):
fmcfd.time = FmcFineDelayTime(10, 0, 0, 0, 0)
@pytest.mark.parametrize("t", random.sample(range(1000000), 10))
def test_time_set(self, fmcfd, t):
"""Time can be changed when White-Rabbit is disabled"""
fmcfd.whiterabbit_mode = False
t_base = FmcFineDelayTime(t, 0, 0, 0, 0)
fmcfd.time = t_base
assert t_base.seconds == fmcfd.time.seconds
@pytest.mark.parametrize("whiterabbit", [False, True])
def test_time_flows(self, fmcfd, whiterabbit):
"""Just check that the time flows more or less correctly second by
second for a minute"""
fmcfd.whiterabbit_mode = whiterabbit
for i in range(20):
t_prev = fmcfd.time.seconds
time.sleep(1)
assert t_prev + 1 == fmcfd.time.seconds
"""
SPDX-License-Identifier: GPL-3.0-or-later
SPDX-FileCopyrightText: 2020 CERN
"""
import pytest
import random
import select
import time
import os
from PyFmcFineDelay import FmcFineDelay, FmcFineDelayTime
@pytest.fixture(scope="function", params=pytest.channels)
def fmcfd_tdc(request):
fd = FmcFineDelay(pytest.fd_id)
fd.tdc.enable_input = False
fd.tdc.enable_tstamp = False
fd.tdc.termination = False
for ch in fd.chan:
ch.disable()
yield fd.tdc
fd.tdc.enable_input = False
fd.tdc.enable_tstamp = False
for ch in fd.chan:
ch.disable()
class TestFmcfdInput(object):
@pytest.mark.parametrize("hz", [1, 10, 100, 1000, 10000])
def test_tdc_burst_manual(self, capsys, fmcfd_tdc, hz):
count = 1000
pending = count
prev_ts = None
fmcfd_tdc.enable_tstamp = True
fmcfd_tdc.enable_input = True
poll = select.poll()
poll.register(fmcfd_tdc.fileno, select.POLLIN)
ts = []
with capsys.disabled():
print("")
print("This test needs an external pulse generator that you manually configure according to the following instructions")
print("1. connect a lemo cable from the pulse generator to the fine-delay trigger input;")
print("2. configure the pulse generator to produce a {:d}Hz burst of {:d} pulses;".format(hz, count))
while True:
a = input("Ready to start? [Y/N]").lower()
if a == 'y' or a == 'n':
break
assert a == "y"
print("### Trigger the burst of pulses and wait for the test to complete (timeout 1 minute)###")
timeout = time.time() + 60
while pending > 0:
t = time.time()
if t >= timeout:
break
ret = poll.poll(1)
if len(ret) == 0:
continue
t = fmcfd_tdc.read(pending, os.O_NONBLOCK)
assert len(t) > 0
ts = ts + t
pending -= len(t)
import pdb
pdb.set_trace()
for i in range(len(ts)):
if prev_ts is not None:
assert ts[i].seq_id == prev_ts.seq_id + 1
diff = float(ts[i]) - float(prev_ts)
assert hz == int(1 / diff)
prev_ts = ts[i]
"""
SPDX-License-Identifier: GPL-3.0-or-later
SPDX-FileCopyrightText: 2020 CERN
"""
import pytest
import random
import time
from PyFmcFineDelay import FmcFineDelay, FmcFineDelayTime
@pytest.fixture(scope="function", params=pytest.channels)
def fmcfd_chan(request):
fd = FmcFineDelay(pytest.fd_id)
fd.tdc.enable_input = False
fd.tdc.enable_tstamp = False
fd.tdc.termination = False
fd.chan[request.param].disable()
yield fd.chan[request.param]
fd.chan[request.param].disable()
class TestFmcfdOutput(object):
def __print_configuration(self, chan, delay, width, period, count):
print("configuration")
print(" channel: {:d}".format(chan))
print(" delay : {:d}ps".format(delay))
print(" width : {:d}ps".format(width))
print(" period : {:d}ps".format(period))
print(" count : {:d}".format(count))
@pytest.mark.parametrize("width",[50000, # 50ns
60000, # 60ns
70000, # 70ns
80000, # 80ns
90000, # 90ns
500000, # 500ns
1000000, # 1us
500000000, # 500us
1000000000, # 1ms
500000000000, # 500ms
1000000000000, # 1s
])
@pytest.mark.parametrize("count", [1, 3])
def test_pulse_width(self, capsys, fmcfd_chan, width, count):
with capsys.disabled():
print("")
print("This test needs an external oscilloscope to monitor pulses produced by the fine delay")
print("1. connect a lemo cable from the fine-delay channel {:d} to the oscilloscope;".format(fmcfd_chan.idx + 1))
print("2. set up the oscilloscope to catch the pulse(s)")
input("Press any key to start").lower()
while True:
start = fmcfd_chan.dev.time + FmcFineDelayTime(1, 0, 0)
fmcfd_chan.pulse_generate(start, width, width * 2, count)
ret = self.__process_outcome(fmcfd_chan.idx + 1, 0,
width, width * 2, count)
if ret in ["y", "n", "q"]:
break
if ret == "q":
pytest.skip("Quit test")
assert ret == "y"
@pytest.mark.parametrize("delay", [600000, # 600ns
1000000, # 1us
500000000, # 500us
1000000000, # 1ms
500000000000, # 500ms
1000000000000, # 1s
10000000000000, # 10s
120000000000000 # 120s
])
def test_pulse_delay_start(self, capsys, fmcfd_chan, delay):
fmcfd_chan.dev.tdc.enable_input = True
with capsys.disabled():
print("")
print("For this test you need: a pulse-generator, an oscilloscope")
print("1. connect a lemo cable from the fine-delay channel {:d} to the oscilloscope;".format(fmcfd_chan.idx + 1))
print("2. connect a lemo cable from the pulse generator to the fine-delay trigger input;")
print("3. connect a lemo cable from the pulse generator to the oscilloscope;")
print("4. Configure the pulse generator at 1Hz")
print("5. set up the oscilloscope to catch the pulse(s)")
input("Press any key to start").lower()
while True:
fmcfd_chan.pulse_delay(delay, 250000, 500000, 1)
time.sleep(1 + delay/1000000000000.0)
ret = self.__process_outcome(fmcfd_chan.idx + 1, delay, 250000, 500000, 1)
if ret in ["y", "n", "q"]:
break
if ret == "q":
pytest.skip("Quit test")
assert ret == "y"
@pytest.mark.parametrize("width",[250000, # 250ns
260000, # 260ns
270000, # 270ns
280000, # 280ns
290000, # 290ns
500000, # 500ns
1000000, # 1us
500000000, # 500us
1000000000, # 1ms
500000000000, # 500ms
1000000000000, # 1s
])
@pytest.mark.parametrize("count", [1, 3])
def test_pulse_delay_width(self, capsys, fmcfd_chan, width, count):
fmcfd_chan.dev.tdc.enable_input = True
with capsys.disabled():
print("")
print("For this test you need: a pulse-generator, an oscilloscope")
print("1. connect a lemo cable from the fine-delay channel {:d} to the oscilloscope;".format(fmcfd_chan.idx + 1))
print("2. connect a lemo cable from the pulse generator to the fine-delay trigger input;")
print("3. connect a lemo cable from the pulse generator to the oscilloscope;")
print("4. Configure the pulse generator at 1Hz")
print("5. set up the oscilloscope to catch the pulse(s)")
input("Press any key to start").lower()
while True:
fmcfd_chan.pulse_delay(width, width, 500000, 1)
time.sleep(1 + delay/1000000000000.0)
ret = self.__process_outcome(fmcfd_chan.idx + 1, 600000, width, 500000, 1)
if ret in ["y", "n", "q"]:
break
if ret == "q":
pytest.skip("Quit test")
assert ret == "y"
def __process_outcome(chan, start, width, period, count):
while True:
with capsys.disabled():
self.__print_configuration(chan, start, width, period, count)
a = input("Did you see it on the oscilloscope? [Y/N/R/Q]").lower()[0]
if a in ["y", "n", "r", "q"]:
break
return a
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment