diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index d3e1af4caa4484884062e49285fb5c9b1e0975b0..b26126fc1a602a04d495d9657505e82d08acea0e 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -12,7 +12,17 @@ include: ref: master file: - 'edl-gitlab-ci.yml' - - local: 'hdl/syn/.gitlab-ci.yml' + +python-style: + variables: + FF_KUBERNETES_HONOR_ENTRYPOINT: 1 # Make Gitlab K8s executors to respect entrypoint in Acc-Py images, https://cern.service-now.com/service-portal?id=ticket&table=incident&n=INC3570437 + stage: analyse + image: + name: gitlab-registry.cern.ch/acc-co/devops/python/distribution-images/acc-py_cc7:pro + before_script: + - pip install pycodestyle + script: + - pycodestyle --ignore=E501 pytest/ software/lib/PyFmcTdc/ cppcheck: stage: analyse @@ -40,3 +50,12 @@ kernel_build_validation: echo "Checking Dependencies" if [ "$FMC_BUILDS" != "0" ]; then echo 'FMC did not build successfully. Exiting'; exit 1; fi if [ "$ZIO_BUILDS" != "0" ]; then echo 'ZIO did not build successfully. Exiting'; exit 1; fi + +fpga_synthesis: + extends: .synthesis-ise-14-7 + interruptible: true + parallel: + matrix: + - EDL_CI_SYN_SRC_PATH: + - hdl/syn/spec + - hdl/syn/svec diff --git a/hdl/syn/.gitlab-ci.yml b/hdl/syn/.gitlab-ci.yml deleted file mode 100644 index ad6d1fff07676a747ebbd405a9a8cde5225bf02f..0000000000000000000000000000000000000000 --- a/hdl/syn/.gitlab-ci.yml +++ /dev/null @@ -1,42 +0,0 @@ -# SPDX-FileCopyrightText: 2022 CERN (home.cern) -# -# SPDX-License-Identifier: LGPL-2.1-or-later - -variables: - _FMC_TDC_BITSTREAM_DEST: $CI_PROJECT_DIR/$EDL_CI_EOS_OUTPUT_DIR/bitstreams - -.syn_template: &syn_template - interruptible: true - stage: build - needs: [] - tags: - - xilinx_ise - - "14.7" - script: - - git submodule init && git submodule update - - cd hdl/syn/"$SYN_NAME"/ - - hdlmake - - make - - | - if [[ $(cat *.par | grep -c "All constraints were met") = 0 ]] - then - echo -e "\e[31mTiming errors detected in PAR report. Aborting...\e[0m" - exit 1 - fi - - tar -cJf $SYN_NAME.tar.xz *.syr *.par *.twr *.bit *.bin - - mkdir -p $_FMC_TDC_BITSTREAM_DEST - - cp $SYN_NAME.tar.xz $_FMC_TDC_BITSTREAM_DEST - artifacts: - name: "$SYN_NAME-synthesis-$CI_JOB_NAME-$CI_COMMIT_REF_NAME" - paths: - - $_FMC_TDC_BITSTREAM_DEST/* - -SPEC synthesis: - variables: - SYN_NAME: "spec" - <<: *syn_template - -SVEC synthesis: - variables: - SYN_NAME: "svec" - <<: *syn_template diff --git a/pytest/conftest.py b/pytest/conftest.py index 2dc64bebe03846a924caceb3329898353642aad8..c5336b6f6c587f0dfc5e1460341339acfdb3f3f0 100644 --- a/pytest/conftest.py +++ b/pytest/conftest.py @@ -2,7 +2,7 @@ SPDX-License-Identifier: LGPL-2.1-or-later SPDX-FileCopyrightText: 2020 CERN """ - +from pathlib import Path import pytest import subprocess import time @@ -10,6 +10,48 @@ import re import os from PyFmcTdc import FmcTdc + +def valid_slot_type(slot): + if re.search(r"(VME|PCI)\.[0-9]+-FMC\.[0-9]+", slot) is None: + raise ValueError() + return slot + + +def id_from_slot(slot, name): + carrier, mezzanine = slot.split("-") + carrier_bus, carrier_slot = carrier.split(".") + carrier_slot = int(carrier_slot) + mezzanine_bus, mezzanine_slot = mezzanine.split(".") + mezzanine_slot = int(mezzanine_slot) + if carrier_bus == "PCI": + with open("/run/dynpci") as f: + for line in f.readlines(): + dynslot, pciid = line.strip().split(" ") + if int(dynslot) == carrier_slot: + break + pciid = f"0000:{pciid}" + pathfmc = list(Path("/sys/bus/pci/devices").joinpath(pciid) + .glob(f"spec-*/id:*/{name}.*.auto/fmc-slot-*.{mezzanine_slot}")) + elif carrier_bus == "VME": + + pathfmc = list(Path("/sys/bus/vme/devices").joinpath(f"slot.{carrier_slot:02d}") + .joinpath(f"vme.{carrier_slot:02d}") + .glob(f"svec-*/svec-*/id:*/{name}.*.auto/fmc-slot-*.{mezzanine_slot}")) + else: + raise ValueError() + assert len(pathfmc) == 1 + devname = list(Path(pathfmc[0]).parent.glob("hw-*/*-????/devname")) + assert len(devname) == 1 + with open(devname[0]) as f: + fd_id = int(f.read().strip().split("-")[-1], 16) + return fd_id + + +def pytest_generate_tests(metafunc): + if "fd_tdc_id" in metafunc.fixturenames: + metafunc.parametrize("fd_tdc_id", pytest.fd_tdc_id) + + class PulseGenerator(object): def __init__(self, id): self.id = id @@ -20,13 +62,14 @@ class PulseGenerator(object): period_ns, count, sync): pass + class SCPI(PulseGenerator): def __init__(self, scpi_id): super(SCPI, self).__init__(scpi_id) import pyvisa self.mgr = pyvisa.ResourceManager() self.instr = self.mgr.open_resource(self.id) - self.instr.query_delay=0 + self.instr.query_delay = 0 self.instr.timeout = 10000 self.instr.read_termination = '\n' self.instr.write_termination = '\n' @@ -55,7 +98,7 @@ class SCPI(PulseGenerator): # START Custom Agilent 33600A commands self.instr.write("TRIGGER:DELAY {:d}e-6".format(rel_time_us)) - burst_period_ns = int(count/(1/period_ns)) + 500 + burst_period_ns = int(count / (1 / period_ns)) + 500 self.instr.write("SOURCE:BURST:INTERNAL:PERIOD {:d}ns".format(burst_period_ns)) self.instr.write("SOURCE:BURST:NCYCLES {:d}".format(count)) self.instr.write("SOURCE:BURST:STATE ON") @@ -67,6 +110,7 @@ class SCPI(PulseGenerator): if sync: self.instr.query_ascii_values("*OPC?") + class FmcFineDelay(PulseGenerator): CHANNEL_NUMBER = 4 @@ -74,7 +118,7 @@ class FmcFineDelay(PulseGenerator): super(FmcFineDelay, self).__init__(fd_id) def disable(self, ch): - cmd = ["/usr/local/bin/fmc-fdelay-pulse", + cmd = ["fmc-fdelay-pulse", "-d", "0x{:x}".format(self.id), "-o", str(ch), "-m", "disable", @@ -84,13 +128,13 @@ class FmcFineDelay(PulseGenerator): def generate_pulse(self, ch, rel_time_us, period_ns, count, sync): - cmd = ["/usr/local/bin/fmc-fdelay-pulse", + cmd = ["fmc-fdelay-pulse", "-d", "0x{:x}".format(self.id), "-o", str(ch), "-m", "pulse", "-r", "{:d}u".format(rel_time_us), "-T", "{:d}n".format(period_ns), - "-w", "{:d}n".format(int(period_ns/2)), + "-w", "{:d}n".format(int(period_ns / 2)), "-c", str(count), "-t" ] @@ -99,38 +143,51 @@ class FmcFineDelay(PulseGenerator): if sync: time.sleep(1 + 2 * (period_ns * count) / 1000000000.0) -@pytest.fixture(scope="module") -def fmcfd(): - if pytest.fd_id is not None: - gen = FmcFineDelay(pytest.fd_id) - elif pytest.scpi is not None: - gen = SCPI(pytest.scpi) - - yield gen - - if isinstance(gen, FmcFineDelay): - for ch in range(FmcFineDelay.CHANNEL_NUMBER): - gen.disable(ch + 1) - elif isinstance(gen, SCPI): - gen.disable(0) @pytest.fixture(scope="function") -def fmctdc(): - tdc = FmcTdc(pytest.tdc_id) +def tdc_and_gen(fd_tdc_id): + fd_id, tdc_id = fd_tdc_id + gen = FmcFineDelay(fd_id) + for ch in range(FmcFineDelay.CHANNEL_NUMBER): + gen.disable(ch + 1) + + tdc = FmcTdc(tdc_id) for ch in tdc.chan: ch.enable = False ch.termination = False ch.timestamp_mode = "post" ch.flush() + yield (gen, tdc) + for ch in range(FmcFineDelay.CHANNEL_NUMBER): + gen.disable(ch + 1) + for ch in tdc.chan: + ch.enable = False + ch.termination = False + ch.timestamp_mode = "post" + ch.flush() + + +@pytest.fixture(scope="function") +def fmcfd(tdc_and_gen): + fd, tdc = tdc_and_gen + yield fd + + +@pytest.fixture(scope="function") +def fmctdc(tdc_and_gen): + fd, tdc = tdc_and_gen yield tdc + def pytest_addoption(parser): - parser.addoption("--tdc-id", type=lambda x : int(x, 16), - required=True, help="Fmc TDC Linux Identifier") - parser.addoption("--fd-id", type=lambda x : int(x, 16), default=None, - help="Fmc Fine-Delay Linux Identifier") - parser.addoption("--scpi", type=str, default=None, - help="SCPI Connection String") + parser.addoption("--tdc-id", type=lambda x: int(x, 16), action="append", + default=[], help="Fmc TDC Linux Identifier") + parser.addoption("--slot-tdc", type=valid_slot_type, action='append', + default=[], help="Fmc TDC absolute slot (works only for SPEC and SVEC)") + parser.addoption("--fd-id", type=lambda x: int(x, 16), action="append", + default=[], help="Fmc Fine-Delay Linux Identifier") + parser.addoption("--slot-fd", type=valid_slot_type, action='append', + default=[], help="Fmc Fine-Delay absolute slot (works only for SPEC and SVEC)") parser.addoption("--dump-range", type=int, default=10, help="Timestamps to show before and after an error") parser.addoption("--channel", type=int, default=[], @@ -141,33 +198,60 @@ def pytest_addoption(parser): parser.addoption("--usr-acq-period-ns", type=int, default=0, help="Pulses period (ns) during a acquisition test.") + +def id_list_get(config, opt_id, opt_slot, devname): + id_list = config.getoption(opt_id) + if len(id_list) == 0: + slot = config.getoption(opt_slot) + if len(slot) == 0: + print(f"Missing argument {opt_id} or {opt_slot}") + raise Exception() + id_list = [] + for slot in slot: + id_list.append(id_from_slot(slot, devname)) + return id_list + + def pytest_configure(config): - pytest.tdc_id = config.getoption("--tdc-id") - pytest.fd_id = config.getoption("--fd-id") - pytest.scpi = config.getoption("--scpi") - if pytest.scpi is None and pytest.fd_id is None: - raise Exception("You must set --fd-id or --scpi") + pytest.tdc_id = id_list_get(config, "--tdc-id", "--slot-tdc", "fmc-tdc") + pytest.fd_id = id_list_get(config, "--fd-id", "--slot-fd", "fmc-fdelay-tdc") + + if len(pytest.tdc_id) != len(pytest.fd_id): + print("For each --fd-id there must be a --tdc-id") + raise Exception() + + pytest.fd_tdc_id = list(zip(pytest.fd_id, pytest.tdc_id)) pytest.channels = config.getoption("--channel") if len(pytest.channels) == 0: pytest.channels = range(FmcTdc.CHANNEL_NUMBER) - if len(pytest.channels) != 1 and pytest.scpi is not None: - raise Exception("With --scpi we can test only the channel connected to the Waveform generator. Set --channel") pytest.usr_acq = (config.getoption("--usr-acq-period-ns"), config.getoption("--usr-acq-count")) pytest.dump_range = config.getoption("--dump-range") pytest.transfer_mode = None - with open("/sys/bus/zio/devices/tdc-1n5c-{:04x}/transfer-mode".format(pytest.tdc_id)) as f_mode: - mode = int(f_mode.read().rstrip()) - for k, v in FmcTdc.TRANSFER_MODE.items(): - if mode == v: - pytest.transfer_mode = k + modes = [] + for tdc_id in pytest.tdc_id: + with open(f"/sys/bus/zio/devices/tdc-1n5c-{tdc_id:04x}/transfer-mode") as f_mode: + modes.append(int(f_mode.read().rstrip())) + mode = set(modes) + if len(mode) != 1: + print("Inconsistent transfer mode across devices") + raise Exception() + for k, v in FmcTdc.TRANSFER_MODE.items(): + if v in mode: + pytest.transfer_mode = k pytest.carrier = None - full_path = os.readlink("/sys/bus/zio/devices/tdc-1n5c-{:04x}".format(pytest.tdc_id)) - for carr in ["spec", "svec"]: - is_carr = re.search(carr, full_path) - if is_carr is not None: + carrs = [] + for tdc_id in pytest.tdc_id: + full_path = os.readlink("/sys/bus/zio/devices/tdc-1n5c-{:04x}".format(tdc_id)) + for carr in ["spec", "svec"]: + is_carr = re.search(carr, full_path) + if is_carr is None: + continue + if pytest.carrier is not None and pytest.carrier != carr: + print("Inconsistent installation mix of SPEC and SVEC") + raise Exception() pytest.carrier = carr diff --git a/pytest/requirements.txt b/pytest/requirements.txt new file mode 100644 index 0000000000000000000000000000000000000000..23145af1b7e7782ab0ac0ead376c683995572e1c --- /dev/null +++ b/pytest/requirements.txt @@ -0,0 +1,4 @@ +# SPDX-FileCopyrightText: 2023 CERN (home.cern) +# +# SPDX-License-Identifier: LGPL-2.1-or-later +pytest diff --git a/pytest/test-00-basic/test_fmctdc_getter_setter.py b/pytest/test-00-basic/test_fmctdc_getter_setter.py index 76452bc503e7ebf763d906a669089d891cf7d5b5..49b311a43082120ee1fc7c3f21d5321fea2246a5 100644 --- a/pytest/test-00-basic/test_fmctdc_getter_setter.py +++ b/pytest/test-00-basic/test_fmctdc_getter_setter.py @@ -7,6 +7,7 @@ import pytest import random from PyFmcTdc import FmcTdc + class TestFmctdcGetterSetter(object): @pytest.mark.parametrize("i", range(FmcTdc.CHANNEL_NUMBER)) @@ -16,7 +17,6 @@ class TestFmctdcGetterSetter(object): fmctdc.chan[i].termination = term assert term == fmctdc.chan[i].termination - @pytest.mark.parametrize("i", range(FmcTdc.CHANNEL_NUMBER)) @pytest.mark.parametrize("term", [True, False]) def test_termination(self, fmctdc, i, term): @@ -53,7 +53,7 @@ class TestFmctdcGetterSetter(object): assert fmctdc.chan[i].enable == (i == ch) fmctdc.chan[ch].enable = False for i in range(FmcTdc.CHANNEL_NUMBER): - assert fmctdc.chan[i].enable == False + assert fmctdc.chan[i].enable is False @pytest.mark.parametrize("i", range(FmcTdc.CHANNEL_NUMBER)) @pytest.mark.parametrize("buffer_mode", FmcTdc.FmcTdcChannel.BUFFER_MODE.keys()) diff --git a/pytest/test-01-functionalities/test_fmctdc_acquisition.py b/pytest/test-01-functionalities/test_fmctdc_acquisition.py index c3571519d96c368b6d9deb3f93d3e73ec7f62df4..e551de2a421b0e4657f7c2830090bf4aeb86c60e 100644 --- a/pytest/test-01-functionalities/test_fmctdc_acquisition.py +++ b/pytest/test-01-functionalities/test_fmctdc_acquisition.py @@ -4,19 +4,19 @@ SPDX-FileCopyrightText: 2020 CERN """ import pytest -import random import select import time -import sys import os from PyFmcTdc import FmcTdc, FmcTdcTime + TDC_FD_CABLING = [1, 2, 3, 4, 4] -fmctdc_acq_100ns_spec = [(200, 65000), # 5 MHz - (250, 65000), # 4 MHz - (500, 65000), # 2 MHz - (1000, 65000), # 1 Mhz + +fmctdc_acq_100ns_spec = [(200, 65000), # 5 MHz + (250, 65000), # 4 MHz + (500, 65000), # 2 MHz + (1000, 65000), # 1 Mhz (1700, 65000), # 588 kHz # Let's keep the test within 100ms duration # vvvvvvvvvvv @@ -24,23 +24,26 @@ fmctdc_acq_100ns_spec = [(200, 65000), # 5 MHz (2500, 40000), # 400 kHz (5000, 20000), # 200 khz (10000, 10000), # 100 kHz - (12500, 8000), # 80 kHz - (20000, 5000), # 50 kHz - (100000, 1000), # 10 kHz - (1000000, 100), # 1 kHz + (12500, 8000), # 80 kHz + (20000, 5000), # 50 kHz + (100000, 1000), # 10 kHz + (1000000, 100), # 1 kHz (10000000, 10)] # 100 Hz -fmctdc_acq_100ns_svec = [(13333, 8000), # 75 kHz - (20000, 5000), # 50 kHz - (100000, 1000), # 10 kHz - (1000000, 100), # 1 kHz - (10000000, 10)] # 100 Hz + +fmctdc_acq_100ns_svec = [(13333, 8000), # 75 kHz + (20000, 5000), # 50 kHz + (100000, 1000), # 10 kHz + (1000000, 100), # 1 kHz + (10000000, 10)] # 100 Hz + fmctdc_acq_100ns = fmctdc_acq_100ns_svec if pytest.transfer_mode == "fifo" else fmctdc_acq_100ns_spec + @pytest.fixture(scope="function", params=pytest.channels) -def fmctdc_chan(request): - tdc = FmcTdc(pytest.tdc_id) +def fmctdc_chan(request, fmctdc): + tdc = fmctdc for ch in tdc.chan: ch.enable = False tdc.chan[request.param].termination = False @@ -54,6 +57,7 @@ def fmctdc_chan(request): tdc.chan[request.param].enable = False del tdc + class TestFmctdcAcquisition(object): def test_acq_single_channel_disable(self, fmctdc_chan, fmcfd): @@ -69,14 +73,13 @@ class TestFmctdcAcquisition(object): correctly. Test 100 milli-second acquisition at different frequencies""" stats_before = fmctdc_chan.stats - fmctdc_chan.buffer_len = max(count + 1, 64) + fmctdc_chan.buffer_len = max(count + 1, 64) fmcfd.generate_pulse(TDC_FD_CABLING[fmctdc_chan.idx], 1000, period_ns, count, True) stats_after = fmctdc_chan.stats assert stats_before[0] + count == stats_after[0] - @pytest.mark.skipif(pytest.carrier != "spec" or \ - pytest.transfer_mode != "dma", + @pytest.mark.skipif(pytest.carrier != "spec" or pytest.transfer_mode != "dma", reason="Only SPEC with DMA can perform this test") @pytest.mark.parametrize("period_ns", [200, 250, 500, 1000]) @pytest.mark.repeat(100) @@ -86,7 +89,7 @@ class TestFmctdcAcquisition(object): if we missed a timestamp or not. this is a fine-delay limitation""" count = 0xFFFF stats_before = fmctdc_chan.stats - fmctdc_chan.buffer_len = count + 1 + fmctdc_chan.buffer_len = count + 1 fmcfd.generate_pulse(TDC_FD_CABLING[fmctdc_chan.idx], 1000, period_ns, count, True) stats_after = fmctdc_chan.stats @@ -98,32 +101,30 @@ class TestFmctdcAcquisition(object): metadata is valid. Coars and franc within range, and the sequence number increases by 1 Test 100 milli-second acquisition at different frequencies""" - fmctdc_chan.buffer_len = max(count + 1, 64) + fmctdc_chan.buffer_len = max(count + 1, 64) prev = None fmcfd.generate_pulse(TDC_FD_CABLING[fmctdc_chan.idx], 1000, period_ns, count, True) ts = fmctdc_chan.read(count, os.O_NONBLOCK) assert len(ts) == count - for i in range(len(ts)): + for i in range(len(ts)): assert 0 <= ts[i].coarse < 125000000 assert 0 <= ts[i].frac < 4096 - if prev == None: + if prev is None: prev = ts[i] continue assert ts[i].seq_id == (prev.seq_id + 1) & 0xFFFFFFF, \ - "Missed {:d} timestamps (idx: {:d}, max: {:d}, prev: {{ {:s}, curr: {:s} }}, full dump;\n{:s}".format(ts[i].seq_id - prev.seq_id + 1, - i, - len(ts), - str(prev), - str(ts[i]), - "\n".join([str(x) for x in ts[max(0, i - pytest.dump_range):min(i + pytest.dump_range, len(ts) -1)]])) + "Missed {:d} timestamps (idx: {:d}, max: {:d}, prev: {{ {:s}, curr: {:s} }}, full dump;\n{:s}".format(ts[i].seq_id - prev.seq_id + 1, + i, + len(ts), + str(prev), + str(ts[i]), + "\n".join([str(x) for x in ts[max(0, i - pytest.dump_range):min(i + pytest.dump_range, len(ts) - 1)]])) prev = ts[i] @pytest.mark.skipif(0 in pytest.usr_acq, reason="Missing user acquisition option") - @pytest.mark.skipif(pytest.carrier == "spec" and \ - pytest.transfer_mode == "fifo" and \ - pytest.usr_acq[0] < 7000, + @pytest.mark.skipif(pytest.carrier == "spec" and pytest.transfer_mode == "fifo" and pytest.usr_acq[0] < 7000, reason="On SPEC with FIFO acquisition we can't do more than 100kHz") @pytest.mark.parametrize("period_ns,count", [pytest.usr_acq]) def test_acq_timestamp_single_channel(self, capsys, fmctdc_chan, fmcfd, @@ -141,7 +142,7 @@ class TestFmctdcAcquisition(object): pending = count prev = None # be able to buffer for 1 second - fmctdc_chan.buffer_len = int(1/(period_ns/1000000000.0)) + 1 + fmctdc_chan.buffer_len = int(1 / (period_ns / 1000000000.0)) + 1 stats_o = fmctdc_chan.stats trans_b = stats_o[1] fmcfd.generate_pulse(TDC_FD_CABLING[fmctdc_chan.idx], 1000, @@ -157,16 +158,16 @@ class TestFmctdcAcquisition(object): ts = fmctdc_chan.read(1000, os.O_NONBLOCK) assert len(ts) <= 1000 for i in range(len(ts)): - if prev == None: + if prev is None: prev = ts[i] continue assert ts[i].seq_id == (prev.seq_id + 1) & 0xFFFFFFF, \ - "Missed {:d} timestamps (idx: {:d}, max: {:d}, prev: {{ {:s}, curr: {:s} }}, full dump;\n{:s}".format(ts[i].seq_id - prev.seq_id + 1, - i, - len(ts), - str(prev), - str(ts[i]), - "\n".join([str(x) for x in ts[max(0, i - pytest.dump_range):min(i + pytest.dump_range, len(ts) -1)]])) + "Missed {:d} timestamps (idx: {:d}, max: {:d}, prev: {{ {:s}, curr: {:s} }}, full dump;\n{:s}".format(ts[i].seq_id - prev.seq_id + 1, + i, + len(ts), + str(prev), + str(ts[i]), + "\n".join([str(x) for x in ts[max(0, i - pytest.dump_range):min(i + pytest.dump_range, len(ts) - 1)]])) prev = ts[i] pending -= len(ts) poll.unregister(fmctdc_chan.fileno) diff --git a/pytest/test-01-functionalities/test_fmctdc_temperature.py b/pytest/test-01-functionalities/test_fmctdc_temperature.py index f280a2354fa4587621f1d5c055b22bdafad6d997..23e5fcc2dd48cf6841ddaf4c81b87d9ddb76973b 100644 --- a/pytest/test-01-functionalities/test_fmctdc_temperature.py +++ b/pytest/test-01-functionalities/test_fmctdc_temperature.py @@ -5,6 +5,7 @@ SPDX-FileCopyrightText: 2020 CERN import pytest + class TestFmctdcTemperature(object): def test_temperature_read(self, fmctdc): diff --git a/pytest/test-01-functionalities/test_fmctdc_time.py b/pytest/test-01-functionalities/test_fmctdc_time.py index 41b0bd3e89dd47cf2339b27daa076ef8aece9e9b..248471a4bb6c2c31d58fe41e05e63b76d6112ef4 100644 --- a/pytest/test-01-functionalities/test_fmctdc_time.py +++ b/pytest/test-01-functionalities/test_fmctdc_time.py @@ -8,14 +8,15 @@ import random import time from PyFmcTdc import FmcTdcTime + class TestFmctdcTime(object): def test_whiterabbit_mode(self, fmctdc): """It must be possible to toggle the White-Rabbit status""" fmctdc.whiterabbit_mode = True - assert fmctdc.whiterabbit_mode == True + assert fmctdc.whiterabbit_mode is True fmctdc.whiterabbit_mode = False - assert fmctdc.whiterabbit_mode == False + assert fmctdc.whiterabbit_mode is False def test_time_set_fail_wr(self, fmctdc): """Time can't be changed when White-Rabbit is enabled""" diff --git a/software/kernel/acam.c b/software/kernel/acam.c index 8ab885c77a484730145d99ac3af6c369864984f1..a67a64e5f4c865ff9983218c0ec9574945db7cae 100644 --- a/software/kernel/acam.c +++ b/software/kernel/acam.c @@ -1,10 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * ACAM TDC-GPX routines support for fmc-tdc driver. * * Copyright (C) 2013 CERN (http://www.cern.ch) * Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch> - * - * SPDX-License-Identifier: GPL-2.0-or-later */ #include <linux/kernel.h> diff --git a/software/kernel/calibration.c b/software/kernel/calibration.c index 14ddf0e189ea015597ffbbe8c919d7c5f6fa11cf..6f03ea0b67cc742787c9debc93049417189ab2c2 100644 --- a/software/kernel/calibration.c +++ b/software/kernel/calibration.c @@ -1,11 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * EEPROM calibration block retreival code for fmc-tdc. * * Copyright (C) 2013 CERN (www.cern.ch) * Author: Tomasz WÅ‚ostowski <tomasz.wlostowski@cern.ch> * Author: Alessandro Rubini <rubini@gnudd.com> - * - * SPDX-License-Identifier: GPL-2.0-or-later */ #include <linux/moduleparam.h> diff --git a/software/kernel/ft-buf.c b/software/kernel/ft-buf.c index 0caf058a36d0b3a715214b267bd242903d775732..1b3668ece6ccd4bf41d751cb1c0b70acd1480906 100644 --- a/software/kernel/ft-buf.c +++ b/software/kernel/ft-buf.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * fmc-tdc (a.k.a) FmcTdc1ns5cha main header. * @@ -5,8 +6,6 @@ * Author: Federico Vaga <federico.vaga@cern.ch> * Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch> * Author: Alessandro Rubini <rubini@gnudd.com> - * - * SPDX-License-Identifier: GPL-2.0-or-later */ #include <linux/kernel.h> #include <linux/init.h> @@ -286,63 +285,60 @@ static int ft_zio_block_nr_pages(struct zio_block *block) } static int sg_alloc_table_from_block(struct device *dev, - struct sg_table *sgt, - struct zio_block *block) + struct sg_table *sgt, + struct zio_block *block) { - struct page **pages; - unsigned int nr_pages; - size_t max_segment_size; - void *data; - int i; -#if LINUX_VERSION_CODE < KERNEL_VERSION(5,9,0) - int err; -#else - struct scatterlist *sg; + struct page **pages; + unsigned int nr_pages; + size_t max_segment_size; + void *data; + int i; + int err = 0; +#if KERNEL_VERSION(5, 9, 0) <= LINUX_VERSION_CODE + struct scatterlist *sg; #endif - if (!block) - return -EINVAL; - - nr_pages = ft_zio_block_nr_pages(block); - pages = kcalloc(nr_pages, sizeof(struct page *), GFP_KERNEL); - if (!pages) - return -ENOMEM; - - data = (void *) block->data; - if (is_vmalloc_addr(data)) { - for (i = 0; i < nr_pages; ++i) { - pages[i] = vmalloc_to_page(data + PAGE_SIZE * i); - } - } else { - for (i = 0; i < nr_pages; ++i) - pages[i] = virt_to_page(data + PAGE_SIZE * i); - } - - max_segment_size = dma_get_max_seg_size(dev); - max_segment_size &= PAGE_MASK; /* to make alloc_table happy */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(5,9,0) - err = __sg_alloc_table_from_pages(sgt, pages, nr_pages, + if (!block) + return -EINVAL; + + nr_pages = ft_zio_block_nr_pages(block); + pages = kcalloc(nr_pages, sizeof(struct page *), GFP_KERNEL); + if (!pages) + return -ENOMEM; + + data = (void *) block->data; + if (is_vmalloc_addr(data)) { + for (i = 0; i < nr_pages; ++i) + pages[i] = vmalloc_to_page(data + PAGE_SIZE * i); + } else { + for (i = 0; i < nr_pages; ++i) + pages[i] = virt_to_page(data + PAGE_SIZE * i); + } + + max_segment_size = dma_get_max_seg_size(dev); + max_segment_size &= PAGE_MASK; /* to make alloc_table happy */ +#if KERNEL_VERSION(5, 9, 0) > LINUX_VERSION_CODE + err = __sg_alloc_table_from_pages(sgt, pages, nr_pages, offset_in_page(data), block->datalen, max_segment_size, GFP_KERNEL); - if (err) - sg_free_table(sgt); - kfree(pages); - return err; #else - sg = __sg_alloc_table_from_pages(sgt, pages, nr_pages, + sg = __sg_alloc_table_from_pages(sgt, pages, nr_pages, offset_in_page(data), block->datalen, max_segment_size, NULL, 0, GFP_KERNEL); - if (IS_ERR(sg)) - sg_free_table(sgt); - kfree(pages); - return PTR_ERR(sg); + if (IS_ERR(sg)) + err = PTR_ERR(sg); #endif + if (err) + sg_free_table(sgt); + + kfree(pages); + return err; } static int ft_zio_block_dma_map_sg(struct fmctdc_dev *ft, unsigned int ch, diff --git a/software/kernel/ft-core.c b/software/kernel/ft-core.c index 42f36240d1f4682f91c45d0ef3c30f562d1b2bd0..56b8805a03393db41aaa7f40f6408e29516d5a2c 100644 --- a/software/kernel/ft-core.c +++ b/software/kernel/ft-core.c @@ -1,11 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Main fmc-tdc driver module. * * Copyright (C) 2012-2013 CERN (www.cern.ch) * Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch> * Author: Alessandro Rubini <rubini@gnudd.com> - * - * SPDX-License-Identifier: GPL-2.0-or-later */ #include <linux/kernel.h> @@ -34,7 +33,7 @@ int irq_timeout_ms_default = 10; module_param_named(irq_timeout_ms, irq_timeout_ms_default, int, 0444); MODULE_PARM_DESC(irq_timeout_ms, "IRQ coalesing timeout (default: 10ms)."); -static int test_data_period = 0; +static int test_data_period; module_param_named(test_data_period, test_data_period, int, 0444); MODULE_PARM_DESC(test_data_period, "It sets how many fake timestamps to generate every seconds on the first channel, 0 to disable (default: 0)"); @@ -209,6 +208,7 @@ static int ft_channels_init(struct fmctdc_dev *ft) for (i = FT_CH_1; i <= FT_NUM_CHANNELS; i++) { int ret = ft_init_channel(ft, i); + if (ret < 0) return ret; /* termination is off by default */ @@ -450,7 +450,7 @@ int ft_probe(struct platform_device *pdev) } } - if(!ft_fmc_slot_is_valid(ft)) + if (!ft_fmc_slot_is_valid(ft)) goto out_fmc_err; err = sysfs_create_link(&ft->pdev->dev.kobj, &ft->slot->dev.kobj, @@ -461,7 +461,7 @@ int ft_probe(struct platform_device *pdev) goto err_fmc_link; } - ret = ft_calib_init(ft); + ret = ft_calib_init(ft); if (ret < 0) goto err_calib; @@ -492,9 +492,9 @@ int ft_probe(struct platform_device *pdev) platform_set_drvdata(pdev, ft); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) +#if KERNEL_VERSION(5, 10, 0) <= LINUX_VERSION_CODE ret = ft_hwmon_init(ft); - if(ret != 0) + if (ret != 0) dev_err(dev, "Could not create HWMON device: %d", ret); #endif @@ -546,6 +546,7 @@ int ft_remove(struct platform_device *pdev) i = ARRAY_SIZE(init_subsystems); while (--i >= 0) { struct ft_modlist *m = init_subsystems + i; + if (m->exit) m->exit(ft); } diff --git a/software/kernel/ft-fifo.c b/software/kernel/ft-fifo.c index 4ae40f28327f10b5646c8231740c8e8665b93769..d493eacad4c1755271ee037f062abf954cfe61b7 100644 --- a/software/kernel/ft-fifo.c +++ b/software/kernel/ft-fifo.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * fmc-tdc (a.k.a) FmcTdc1ns5cha main header. * @@ -5,8 +6,6 @@ * Author: Federico Vaga <federico.vaga@cern.ch> * Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch> * Author: Alessandro Rubini <rubini@gnudd.com> - * - * SPDX-License-Identifier: GPL-2.0-or-later */ #include <linux/kernel.h> #include <linux/init.h> @@ -147,7 +146,7 @@ static irqreturn_t ft_irq_handler_ts_fifo(int irq, void *dev_id) redo--; } } - } while(irq_stat && redo); + } while (irq_stat && redo); ft_iowrite(ft, irq_stat_orig, ft->ft_irq_base + TDC_EIC_REG_EIC_ISR); return IRQ_HANDLED; diff --git a/software/kernel/ft-hwmon.c b/software/kernel/ft-hwmon.c index bf0874f58fc09c9ed668b463fc7e99dd675806ae..2cd9aaee88fa29e9b8a5cb5fcdcb78d75bb98854 100644 --- a/software/kernel/ft-hwmon.c +++ b/software/kernel/ft-hwmon.c @@ -10,7 +10,7 @@ #include <linux/hwmon.h> #include "fmc-tdc.h" -#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) +#if KERNEL_VERSION(5, 10, 0) <= LINUX_VERSION_CODE static umode_t ft_hwmon_temp_is_visible(const void *_data, enum hwmon_sensor_types type, u32 attr, @@ -25,23 +25,23 @@ static int ft_hwmon_temp_read(struct device *dev, enum hwmon_sensor_types type, int value, ret; struct fmctdc_dev *ft = dev_get_drvdata(dev); - switch(attr) { - case hwmon_temp_min: - *val = -25*1000; - return 0; + switch (attr) { + case hwmon_temp_min: + *val = -25*1000; + return 0; - case hwmon_temp_max: - *val = 60*1000; - return 0; + case hwmon_temp_max: + *val = 60*1000; + return 0; - case hwmon_temp_crit: - *val = 65*1000; - return 0; + case hwmon_temp_crit: + *val = 65*1000; + return 0; } ret = ft_temperature_get(ft, &value); - if(ret < 0) { + if (ret < 0) { dev_err(dev, "Could not read temperature: %d", ret); return ret; } @@ -88,12 +88,12 @@ int ft_hwmon_init(struct fmctdc_dev *ft) ft, &ft_hwmon_temp_chip_info, NULL); - if(!IS_ERR(ft->hwmon_dev)) { + if (!IS_ERR(ft->hwmon_dev)) { ft->hwmon_temp_sensor_id = devm_kasprintf(ft->hwmon_dev, GFP_KERNEL, "Temperature [%s]", dev_name(&ft->slot->dev)); - if(!ft->hwmon_temp_sensor_id) { + if (!ft->hwmon_temp_sensor_id) { devm_hwmon_device_unregister(dev); return -ENOMEM; } diff --git a/software/kernel/ft-time.c b/software/kernel/ft-time.c index 3da6e5301fdad73c6ef0c76c7e7f8c505bbf81bd..6e4acfc981665182d050ecea413530a3221c19f4 100644 --- a/software/kernel/ft-time.c +++ b/software/kernel/ft-time.c @@ -1,10 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// SPDX-FileCopyrightText: 2023 CERN (home.cern) + /* * Time-related routines for fmc-tdc driver. * - * Copyright (C) 2013 CERN (http://www.cern.ch) * Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch> - * - * SPDX-License-Identifier: GPL-2.0-or-later */ #include <linux/kernel.h> diff --git a/software/kernel/ft-zio.c b/software/kernel/ft-zio.c index fca6428b058e6ca3bb0564526ee7bf893f9361f9..cc0187f9e4843b922131ee92e463aae2e4d46edc 100644 --- a/software/kernel/ft-zio.c +++ b/software/kernel/ft-zio.c @@ -1,11 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * ZIO interface for the fmc-tdc driver. * * Copyright (C) 2012-2013 CERN (www.cern.ch) * Author: Tomasz WÅ‚ostowski <tomasz.wlostowski@cern.ch> * Author: Alessandro Rubini <rubini@gnudd.com> - * - * SPDX-License-Identifier: GPL-2.0-or-later */ #include <linux/kernel.h> @@ -138,10 +137,10 @@ int ft_temperature_get(struct fmctdc_dev *ft, int *temp) static int ft_unique_id_get(struct fmctdc_dev *ft, uint64_t *id) { - int stat = ft_ioread( ft, ft->ft_owregs_base + TDC_OW_REG_CSR); + int stat = ft_ioread(ft, ft->ft_owregs_base + TDC_OW_REG_CSR); uint32_t tmp_l, tmp_h; - if( !( stat & TDC_OW_CSR_VALID ) ) + if (!(stat & TDC_OW_CSR_VALID)) return -EIO; tmp_l = ft_ioread(ft, ft->ft_owregs_base + TDC_OW_REG_ID_L); @@ -487,10 +486,10 @@ static struct zio_driver ft_zdrv = { .probe = ft_zio_probe, .remove = ft_zio_remove, /* Take the version from ZIO git sub-module */ + /* Change it if you use new features from a specific patch */ .min_version = ZIO_VERSION(__ZIO_MIN_MAJOR_VERSION, __ZIO_MIN_MINOR_VERSION, - 0), /* Change it if you use new features from - a specific patch */ + 0), }; #define FT_TRIG_POST_DEFAULT 1 @@ -590,11 +589,11 @@ static int ft_trig_data_done(struct zio_cset *cset) goto out; ts = cset->chan->active_block->data; - for(i = 0; i < cset->ti->nsamples; ++i) { + for (i = 0; i < cset->ti->nsamples; ++i) { dev_dbg(&cset->head.dev, "%s TS = {ts-num: %d, ts-num-max: %d, sec: 0x%x, coarse: 0x%x frac: 0x%x, meta: 0x%x}\n", __func__, i, cset->ti->nsamples, - ts[i].seconds,ts[i].coarse, + ts[i].seconds, ts[i].coarse, ts[i].frac, ts[i].metadata); } ft_zio_update_ctrl(cset, &ts[0]); @@ -678,7 +677,7 @@ int ft_zio_init(struct fmctdc_dev *ft) if (err) goto err_dev_reg; - for(i = 0; i < FT_NUM_CHANNELS; i++) { + for (i = 0; i < FT_NUM_CHANNELS; i++) { ft_raw_mode_set(ft, i, 0); ft_update_offsets(ft, i); } diff --git a/software/lib/PyFmcTdc/PyFmcTdc/PyFmcTdc.py b/software/lib/PyFmcTdc/PyFmcTdc/PyFmcTdc.py index 97269fbfb6398bc81f91ab5ed05ecb1a4b7ec3ce..b13a2eb38b62615cd283e9668e1cebf8e56117b1 100644 --- a/software/lib/PyFmcTdc/PyFmcTdc/PyFmcTdc.py +++ b/software/lib/PyFmcTdc/PyFmcTdc/PyFmcTdc.py @@ -6,20 +6,19 @@ SPDX-License-Identifier: LGPL-2.1-or-later SPDX-FileCopyrightText: 2020 CERN (home.cern) """ -import threading import ctypes import errno import time -import os + class FmcTdcTime(ctypes.Structure): _fields_ = [ - ("seconds", ctypes.c_uint64), - ("coarse", ctypes.c_uint32), - ("frac", ctypes.c_uint32), - ("seq_id", ctypes.c_uint32), - ("debug", ctypes.c_uint32), - ] + ("seconds", ctypes.c_uint64), + ("coarse", ctypes.c_uint32), + ("frac", ctypes.c_uint32), + ("seq_id", ctypes.c_uint32), + ("debug", ctypes.c_uint32), + ] def __str__(self): return "seq: {:d} timestamp: {:f} raw: {:08x}:{:08x}:{:08x}, debug: {:08x}".format(self.seq_id, float(self), self.seconds, self.coarse, self.frac, self.debug) @@ -31,7 +30,6 @@ class FmcTdcTime(ctypes.Structure): return ts - def libfmctdc_create(): """ Initialize the libfmctdc C library @@ -102,12 +100,12 @@ def libfmctdc_create(): libfmctdc.fmctdc_get_time.restype = ctypes.c_int libfmctdc.fmctdc_get_time.errcheck = error_check_int - libfmctdc.fmctdc_wr_mode.argtypes =[ctypes.c_void_p, - ctypes.c_int] + libfmctdc.fmctdc_wr_mode.argtypes = [ctypes.c_void_p, + ctypes.c_int] libfmctdc.fmctdc_wr_mode.restype = ctypes.c_int libfmctdc.fmctdc_wr_mode.errcheck = error_check_int - libfmctdc.fmctdc_check_wr_mode.argtypes =[ctypes.c_void_p] + libfmctdc.fmctdc_check_wr_mode.argtypes = [ctypes.c_void_p] libfmctdc.fmctdc_check_wr_mode.restype = ctypes.c_int # Channel @@ -230,8 +228,10 @@ def libfmctdc_create(): return libfmctdc + libfmctdc = libfmctdc_create() + def fmctdc_strerror(err): """ Return FMC-TDC errors @@ -241,6 +241,7 @@ def fmctdc_strerror(err): """ return libfmctdc.fmctdc_strerror(err) + class FmcTdc(object): """ It is a Python class that represent an FMC TDC device @@ -361,12 +362,12 @@ class FmcTdc(object): def read(self, n=1, flags=0): ts = (FmcTdcTime * n)() - ret = libfmctdc.fmctdc_read(self.tkn, self.idx, ts ,n ,flags) + ret = libfmctdc.fmctdc_read(self.tkn, self.idx, ts, n, flags) return list(ts)[:ret] def fread(self, n=1, flags=0): ts = (FmcTdcTime * n)() - libfmctdc.fmctdc_fread(self.tkn, self.idx, ts, n ,flags) + libfmctdc.fmctdc_fread(self.tkn, self.idx, ts, n, flags) return list(ts) def flush(self): diff --git a/software/lib/PyFmcTdc/setup.py b/software/lib/PyFmcTdc/setup.py index 65e0ec285b1950441f8798384fdb46e773f163c3..8ea9b5bed7caaead87c390e170197141f0c65b06 100644 --- a/software/lib/PyFmcTdc/setup.py +++ b/software/lib/PyFmcTdc/setup.py @@ -17,4 +17,4 @@ setup(name='PyFmcTdc', url='http://www.ohwr.org/projects/fmc-tdc', packages=['PyFmcTdc'], license='LGPL-2.1-or-later', - ) + )