mirror of
https://github.com/slsdetectorgroup/slsDetectorPackage.git
synced 2025-12-17 01:51:20 +01:00
Compare commits
30 Commits
MH02_debug
...
developer
| Author | SHA1 | Date | |
|---|---|---|---|
| 497b3ed00e | |||
| 300a296c20 | |||
| 01e392b112 | |||
| 5409cec73e | |||
|
|
1c31a85a43 | ||
| 134137ead0 | |||
| 6d3922f487 | |||
| f14cfb0b31 | |||
| cf4e6b65c1 | |||
| 0da80cd898 | |||
| 8e7921ae45 | |||
| b90851a855 | |||
| 683accd914 | |||
| 30e82e4740 | |||
| 08486b9812 | |||
| a5c661ce22 | |||
| 50448cefb4 | |||
| c1e5cfa101 | |||
| ae8c9175bf | |||
| e7f5a2aa11 | |||
| cad44943c3 | |||
| d4f8049623 | |||
| 925cd55b1c | |||
| ec11ba5a54 | |||
| eea4dca449 | |||
| 3285221e8a | |||
|
|
f32fcf1e88 | ||
| 3ff199822d | |||
| 0ba9a269a1 | |||
| afc51c9771 |
33
.gitea/workflows/rh8-local.yml
Normal file
33
.gitea/workflows/rh8-local.yml
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
name: Build on local RHEL8
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- developer
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: "detectors-software-RH8"
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Build library
|
||||||
|
run: |
|
||||||
|
source /home/gitea_runner/.bashrc
|
||||||
|
conda activate det
|
||||||
|
mkdir build && cd build
|
||||||
|
conda activate det
|
||||||
|
cmake .. -DSLS_USE_PYTHON=ON
|
||||||
|
make -j 2
|
||||||
|
cd ../pyctbgui
|
||||||
|
make
|
||||||
|
|
||||||
|
- name: Deploy to NFS update server
|
||||||
|
if: gitea.ref == 'refs/heads/developer'
|
||||||
|
run: |
|
||||||
|
sftp -r gitea_runner@mpc2935:/slsDetectorSoftware/RH8 <<< $'put build/bin'
|
||||||
|
sftp -r gitea_runner@mpc2935:/slsDetectorSoftware/RH8 <<< $'put pyctbgui'
|
||||||
30
.gitea/workflows/rh9-local.yml
Normal file
30
.gitea/workflows/rh9-local.yml
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
name: Build on local RHEL9
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- developer
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: "detectors-software-RH9"
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Build library
|
||||||
|
run: |
|
||||||
|
mkdir build && cd build
|
||||||
|
cmake -DSLS_USE_PYTHON=ON -DPython_EXECUTABLE=/usr/bin/python3.13 -DPython_INCLUDE_DIR=/usr/include/python3.13 -DPython_LIBRARY=/usr/lib64/libpython3.13.so ..
|
||||||
|
make -j 2
|
||||||
|
cd ../pyctbgui
|
||||||
|
make
|
||||||
|
|
||||||
|
- name: Deploy to NFS update server
|
||||||
|
if: gitea.ref == 'refs/heads/developer'
|
||||||
|
run: |
|
||||||
|
sftp -r gitea_runner@mpc2935:/slsDetectorSoftware/RH9 <<< $'put build/bin'
|
||||||
|
sftp -r gitea_runner@mpc2935:/slsDetectorSoftware/RH9 <<< $'put pyctbgui'
|
||||||
2
.github/workflows/build_wheel.yml
vendored
2
.github/workflows/build_wheel.yml
vendored
@@ -23,7 +23,7 @@ jobs:
|
|||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Build wheels
|
- name: Build wheels
|
||||||
run: pipx run cibuildwheel==2.23.0
|
run: pipx run cibuildwheel==3.2.1
|
||||||
|
|
||||||
- uses: actions/upload-artifact@v4
|
- uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
|
|||||||
2
.github/workflows/cmake.yaml
vendored
2
.github/workflows/cmake.yaml
vendored
@@ -19,7 +19,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
python-version: 3.12
|
python-version: 3.12
|
||||||
cache: 'pip'
|
cache: 'pip'
|
||||||
- run: pip install pytest numpy
|
- run: pip install pytest numpy colorama
|
||||||
|
|
||||||
- uses: awalsh128/cache-apt-pkgs-action@latest
|
- uses: awalsh128/cache-apt-pkgs-action@latest
|
||||||
with:
|
with:
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
SLS Detector Package Major Release x.x.x released on xx.xx.202x
|
SLS Detector Package Major Release x.x.x released on xx.xx.202x
|
||||||
===============================================================
|
===============================================================
|
||||||
|
|
||||||
This document describes the differences between vx.x.x and vx.0.2
|
This document describes the differences between vx.x.x and v10.0.0
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -35,6 +35,8 @@ instead of the one included in our repo.
|
|||||||
|
|
||||||
Experimental support for building the detector client (including python bindings) on macOS
|
Experimental support for building the detector client (including python bindings) on macOS
|
||||||
|
|
||||||
|
``rx_dbitlist`` keeps the order of the passed bit list
|
||||||
|
|
||||||
2 On-board Detector Server Compatibility
|
2 On-board Detector Server Compatibility
|
||||||
==========================================
|
==========================================
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ python:
|
|||||||
- 3.11
|
- 3.11
|
||||||
- 3.12
|
- 3.12
|
||||||
- 3.13
|
- 3.13
|
||||||
|
- 3.14
|
||||||
|
|
||||||
|
|
||||||
c_compiler:
|
c_compiler:
|
||||||
- gcc # [linux]
|
- gcc # [linux]
|
||||||
@@ -13,4 +15,4 @@ cxx_compiler:
|
|||||||
- gxx # [linux]
|
- gxx # [linux]
|
||||||
|
|
||||||
c_stdlib_version: # [linux]
|
c_stdlib_version: # [linux]
|
||||||
- 2.17 # [linux]
|
- 2.17 # [linux]
|
||||||
|
|||||||
@@ -9,11 +9,11 @@ package:
|
|||||||
build:
|
build:
|
||||||
number: 0
|
number: 0
|
||||||
script:
|
script:
|
||||||
- unset CMAKE_GENERATOR && {{ PYTHON }} -m pip install . -vv # [not win]
|
- unset CMAKE_GENERATOR && {{ PYTHON }} -m pip install . -vv --config-settings=cmake.define.SLS_USE_SYSTEM_ZMQ=ON # [not win]
|
||||||
|
|
||||||
requirements:
|
requirements:
|
||||||
build:
|
build:
|
||||||
- python {{python}}
|
- python
|
||||||
- {{ compiler('c') }}
|
- {{ compiler('c') }}
|
||||||
- {{ stdlib("c") }}
|
- {{ stdlib("c") }}
|
||||||
- {{ compiler('cxx') }}
|
- {{ compiler('cxx') }}
|
||||||
@@ -21,7 +21,7 @@ requirements:
|
|||||||
host:
|
host:
|
||||||
- cmake
|
- cmake
|
||||||
- ninja
|
- ninja
|
||||||
- python {{python}}
|
- python
|
||||||
- pip
|
- pip
|
||||||
- scikit-build-core
|
- scikit-build-core
|
||||||
- pybind11 >=2.13.0
|
- pybind11 >=2.13.0
|
||||||
@@ -31,7 +31,7 @@ requirements:
|
|||||||
- catch2
|
- catch2
|
||||||
|
|
||||||
run:
|
run:
|
||||||
- python {{python}}
|
- python
|
||||||
- numpy
|
- numpy
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ dependencies = [
|
|||||||
|
|
||||||
[tool.cibuildwheel]
|
[tool.cibuildwheel]
|
||||||
before-all = "uname -a"
|
before-all = "uname -a"
|
||||||
build = "cp{311,312,313}-manylinux_x86_64"
|
build = "cp{311,312,313,314}-manylinux_x86_64"
|
||||||
|
|
||||||
[tool.scikit-build.build]
|
[tool.scikit-build.build]
|
||||||
verbose = true
|
verbose = true
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import datetime as dt
|
|||||||
|
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
|
from collections.abc import Sequence
|
||||||
import socket
|
import socket
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
@@ -301,6 +302,46 @@ class Detector(CppDetectorApi):
|
|||||||
def rx_arping(self, value):
|
def rx_arping(self, value):
|
||||||
ut.set_using_dict(self.setRxArping, value)
|
ut.set_using_dict(self.setRxArping, value)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def rx_roi(self):
|
||||||
|
"""Gets the list of ROIs configured in the receiver.
|
||||||
|
|
||||||
|
Note
|
||||||
|
-----
|
||||||
|
Each ROI is represented as a tuple of (x_start, y_start, x_end, y_end). \n
|
||||||
|
If no ROIs are configured, returns [[-1,-1,-1,-1]].
|
||||||
|
"""
|
||||||
|
return self.getRxROI() #vector of Roi structs how represented?
|
||||||
|
|
||||||
|
@rx_roi.setter
|
||||||
|
def rx_roi(self, rois):
|
||||||
|
"""
|
||||||
|
Sets the list of ROIs in the receiver.
|
||||||
|
Can only set multiple ROIs at multi module level without gap pixels. If more than 1 ROI per
|
||||||
|
UDP port, it will throw. Setting number of udp interfaces will clear the
|
||||||
|
roi. Cannot be set for CTB or Xilinx CTB.
|
||||||
|
|
||||||
|
Note
|
||||||
|
-----
|
||||||
|
Each ROI should be represented as a sequence of 4 ints (x_start, y_start, x_end, y_end). \n
|
||||||
|
For mythen3 or gotthard2 pass a sequence of 2 ints (x_start, x_end) \n
|
||||||
|
For multiple ROI's pass a sequence of sequence \n
|
||||||
|
Example: [[0, 100, 50, 100], [260, 270, 50,100]] \n
|
||||||
|
"""
|
||||||
|
# TODO: maybe better to accept py::object in setRxROI and handle there?
|
||||||
|
if not isinstance(rois, Sequence):
|
||||||
|
raise TypeError(
|
||||||
|
"setRxROI failed: expected a tuple/list of ints x_min, x_max, y_min, y_max "
|
||||||
|
"or a sequence of such."
|
||||||
|
)
|
||||||
|
if(not isinstance(rois[0], Sequence)):
|
||||||
|
self.setRxROI([rois])
|
||||||
|
else:
|
||||||
|
self.setRxROI(rois)
|
||||||
|
|
||||||
|
def rx_clearroi(self):
|
||||||
|
"""Clears all the ROIs configured in the receiver."""
|
||||||
|
self.clearRxROI()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@element
|
@element
|
||||||
|
|||||||
@@ -942,6 +942,7 @@ void init_det(py::module &m) {
|
|||||||
(void (Detector::*)(const std::vector<defs::ROI> &)) &
|
(void (Detector::*)(const std::vector<defs::ROI> &)) &
|
||||||
Detector::setRxROI,
|
Detector::setRxROI,
|
||||||
py::arg());
|
py::arg());
|
||||||
|
|
||||||
CppDetectorApi.def("clearRxROI",
|
CppDetectorApi.def("clearRxROI",
|
||||||
(void (Detector::*)()) & Detector::clearRxROI);
|
(void (Detector::*)()) & Detector::clearRxROI);
|
||||||
CppDetectorApi.def(
|
CppDetectorApi.def(
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
// SPDX-License-Identifier: LGPL-3.0-or-other
|
// SPDX-License-Identifier: LGPL-3.0-or-other
|
||||||
// Copyright (C) 2021 Contributors to the SLS Detector Package
|
// Copyright (C) 2021 Contributors to the SLS Detector Package
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <pybind11/pybind11.h>
|
|
||||||
#include <datetime.h>
|
#include <datetime.h>
|
||||||
|
#include <pybind11/pybind11.h>
|
||||||
|
|
||||||
#include "sls/Result.h"
|
|
||||||
#include "DurationWrapper.h"
|
#include "DurationWrapper.h"
|
||||||
|
#include "sls/Result.h"
|
||||||
|
#include "sls/sls_detector_defs.h"
|
||||||
|
|
||||||
namespace py = pybind11;
|
namespace py = pybind11;
|
||||||
namespace pybind11 {
|
namespace pybind11 {
|
||||||
@@ -14,84 +15,130 @@ template <typename Type, typename Alloc>
|
|||||||
struct type_caster<sls::Result<Type, Alloc>>
|
struct type_caster<sls::Result<Type, Alloc>>
|
||||||
: list_caster<sls::Result<Type, Alloc>, Type> {};
|
: list_caster<sls::Result<Type, Alloc>, Type> {};
|
||||||
|
|
||||||
|
|
||||||
// Based on the typecaster in pybind11/chrono.h
|
// Based on the typecaster in pybind11/chrono.h
|
||||||
template <> struct type_caster<std::chrono::nanoseconds> {
|
template <> struct type_caster<std::chrono::nanoseconds> {
|
||||||
public:
|
public:
|
||||||
PYBIND11_TYPE_CASTER(std::chrono::nanoseconds, const_name("DurationWrapper"));
|
PYBIND11_TYPE_CASTER(std::chrono::nanoseconds,
|
||||||
|
const_name("DurationWrapper"));
|
||||||
|
|
||||||
// signed 25 bits required by the standard.
|
// signed 25 bits required by the standard.
|
||||||
using days = std::chrono::duration<int_least32_t, std::ratio<86400>>;
|
using days = std::chrono::duration<int_least32_t, std::ratio<86400>>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Conversion part 1 (Python->C++): convert a PyObject into std::chrono::nanoseconds
|
* Conversion part 1 (Python->C++): convert a PyObject into
|
||||||
* try datetime.timedelta, floats and our DurationWrapper wrapper
|
* std::chrono::nanoseconds try datetime.timedelta, floats and our
|
||||||
*/
|
* DurationWrapper wrapper
|
||||||
|
*/
|
||||||
|
|
||||||
bool load(handle src, bool) {
|
bool load(handle src, bool) {
|
||||||
using namespace std::chrono;
|
using namespace std::chrono;
|
||||||
|
|
||||||
// Lazy initialise the PyDateTime import
|
// Lazy initialise the PyDateTime import
|
||||||
if (!PyDateTimeAPI) {
|
if (!PyDateTimeAPI) {
|
||||||
PyDateTime_IMPORT;
|
PyDateTime_IMPORT;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!src) {
|
if (!src) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// If invoked with datetime.delta object, same as in chrono.h
|
||||||
|
if (PyDelta_Check(src.ptr())) {
|
||||||
|
value = duration_cast<nanoseconds>(
|
||||||
|
days(PyDateTime_DELTA_GET_DAYS(src.ptr())) +
|
||||||
|
seconds(PyDateTime_DELTA_GET_SECONDS(src.ptr())) +
|
||||||
|
microseconds(PyDateTime_DELTA_GET_MICROSECONDS(src.ptr()))
|
||||||
|
|
||||||
|
);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// If invoked with a float we assume it is seconds and convert, same as
|
||||||
|
// in chrono.h
|
||||||
|
if (PyFloat_Check(src.ptr())) {
|
||||||
|
value = duration_cast<nanoseconds>(
|
||||||
|
duration<double>(PyFloat_AsDouble(src.ptr())));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// If invoked with an int we assume it is nanoseconds and convert, same
|
||||||
|
// as in chrono.h
|
||||||
|
if (PyLong_Check(src.ptr())) {
|
||||||
|
value = duration_cast<nanoseconds>(
|
||||||
|
duration<int64_t>(PyLong_AsLongLong(src.ptr())));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lastly if we were actually called with a DurationWrapper object we
|
||||||
|
// get the number of nanoseconds and create a std::chrono::nanoseconds
|
||||||
|
// from it
|
||||||
|
py::object py_cls =
|
||||||
|
py::module::import("slsdet._slsdet").attr("DurationWrapper");
|
||||||
|
if (py::isinstance(src, py_cls)) {
|
||||||
|
sls::DurationWrapper *cls = src.cast<sls::DurationWrapper *>();
|
||||||
|
value = nanoseconds(cls->count());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Conversion part 2 (C++ -> Python)
|
||||||
|
* import the module to get a handle to the wrapped class
|
||||||
|
* Default construct an object of (wrapped) DurationWrapper
|
||||||
|
* set the count from chrono::nanoseconds and return
|
||||||
|
*/
|
||||||
|
static handle cast(std::chrono::nanoseconds src,
|
||||||
|
return_value_policy /* policy */, handle /* parent */) {
|
||||||
|
py::object py_cls =
|
||||||
|
py::module::import("slsdet._slsdet").attr("DurationWrapper");
|
||||||
|
py::object *obj = new py::object;
|
||||||
|
*obj = py_cls();
|
||||||
|
sls::DurationWrapper *dur = obj->cast<sls::DurationWrapper *>();
|
||||||
|
dur->set_count(src.count());
|
||||||
|
return *obj;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Type caster for sls::defs::ROI from tuple
|
||||||
|
template <> struct type_caster<sls::defs::ROI> {
|
||||||
|
PYBIND11_TYPE_CASTER(sls::defs::ROI, _("Sequence[int, int, int, int] or "
|
||||||
|
"Sequence[int, int]"));
|
||||||
|
|
||||||
|
// convert c++ ROI to python tuple
|
||||||
|
static handle cast(const sls::defs::ROI &roi, return_value_policy, handle) {
|
||||||
|
return py::make_tuple(roi.xmin, roi.xmax, roi.ymin, roi.ymax).release();
|
||||||
|
}
|
||||||
|
|
||||||
|
// convert from python to c++ ROI
|
||||||
|
bool load(handle roi, bool /*allow implicit conversion*/) {
|
||||||
|
|
||||||
|
// accept tuple, list, numpy array any sequence
|
||||||
|
py::sequence seq;
|
||||||
|
try {
|
||||||
|
seq = py::reinterpret_borrow<py::sequence>(roi);
|
||||||
|
} catch (...) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (seq.size() != 4 && seq.size() != 2)
|
||||||
|
return false;
|
||||||
|
// Check if each element is an int
|
||||||
|
for (auto item : seq) {
|
||||||
|
if (!py::isinstance<py::int_>(item)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// If invoked with datetime.delta object, same as in chrono.h
|
|
||||||
if (PyDelta_Check(src.ptr())) {
|
|
||||||
value = duration_cast<nanoseconds>(
|
|
||||||
days(PyDateTime_DELTA_GET_DAYS(src.ptr())) +
|
|
||||||
seconds(PyDateTime_DELTA_GET_SECONDS(src.ptr())) +
|
|
||||||
microseconds(PyDateTime_DELTA_GET_MICROSECONDS(src.ptr()))
|
|
||||||
|
|
||||||
);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
// If invoked with a float we assume it is seconds and convert, same as in chrono.h
|
|
||||||
if (PyFloat_Check(src.ptr())) {
|
|
||||||
value = duration_cast<nanoseconds>(duration<double>(PyFloat_AsDouble(src.ptr())));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
// If invoked with an int we assume it is nanoseconds and convert, same as in chrono.h
|
|
||||||
if (PyLong_Check(src.ptr())) {
|
|
||||||
value = duration_cast<nanoseconds>(duration<int64_t>(PyLong_AsLongLong(src.ptr())));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Lastly if we were actually called with a DurationWrapper object we get
|
|
||||||
// the number of nanoseconds and create a std::chrono::nanoseconds from it
|
|
||||||
py::object py_cls = py::module::import("slsdet._slsdet").attr("DurationWrapper");
|
|
||||||
if (py::isinstance(src, py_cls)){
|
|
||||||
sls::DurationWrapper *cls = src.cast<sls::DurationWrapper *>();
|
|
||||||
value = nanoseconds(cls->count());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
return false;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
value.xmin = seq[0].cast<int>();
|
||||||
* Conversion part 2 (C++ -> Python)
|
value.xmax = seq[1].cast<int>();
|
||||||
* import the module to get a handle to the wrapped class
|
|
||||||
* Default construct an object of (wrapped) DurationWrapper
|
if (seq.size() == 4) {
|
||||||
* set the count from chrono::nanoseconds and return
|
value.ymin = seq[2].cast<int>();
|
||||||
*/
|
value.ymax = seq[3].cast<int>();
|
||||||
static handle cast(std::chrono::nanoseconds src, return_value_policy /* policy */, handle /* parent */) {
|
|
||||||
py::object py_cls = py::module::import("slsdet._slsdet").attr("DurationWrapper");
|
|
||||||
py::object* obj = new py::object;
|
|
||||||
*obj = py_cls();
|
|
||||||
sls::DurationWrapper *dur = obj->cast<sls::DurationWrapper *>();
|
|
||||||
dur->set_count(src.count());
|
|
||||||
return *obj;
|
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
} // namespace pybind11
|
} // namespace pybind11
|
||||||
85
python/tests/conftest.py
Normal file
85
python/tests/conftest.py
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
import pytest
|
||||||
|
import sys
|
||||||
|
import traceback
|
||||||
|
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
current_dir = Path(__file__).resolve().parents[2]
|
||||||
|
|
||||||
|
scripts_dir = current_dir / "tests" / "scripts"
|
||||||
|
|
||||||
|
sys.path.append(str(scripts_dir))
|
||||||
|
|
||||||
|
print(sys.path)
|
||||||
|
|
||||||
|
from utils_for_test import (
|
||||||
|
Log,
|
||||||
|
LogLevel,
|
||||||
|
cleanup,
|
||||||
|
startReceiver,
|
||||||
|
startDetectorVirtualServer,
|
||||||
|
loadConfig,
|
||||||
|
loadBasicSettings,
|
||||||
|
)
|
||||||
|
|
||||||
|
def pytest_addoption(parser):
|
||||||
|
parser.addoption(
|
||||||
|
"--with-detector-simulators", action="store_true", default=False, help="Run tests that require detector simulators"
|
||||||
|
)
|
||||||
|
|
||||||
|
def pytest_configure(config):
|
||||||
|
config.addinivalue_line("markers", "withdetectorsimulators: mark test as needing detector simulators to run")
|
||||||
|
|
||||||
|
def pytest_collection_modifyitems(config, items):
|
||||||
|
if config.getoption("--with-detector-simulators"):
|
||||||
|
return
|
||||||
|
skip = pytest.mark.skip(reason="need --with-detector-simulators option to run")
|
||||||
|
for item in items:
|
||||||
|
if "withdetectorsimulators" in item.keywords:
|
||||||
|
item.add_marker(skip)
|
||||||
|
|
||||||
|
#helper fixture for servers
|
||||||
|
@pytest.fixture
|
||||||
|
def servers(request):
|
||||||
|
try:
|
||||||
|
return request.param # comes from @pytest.mark.parametrize(..., indirect=True)
|
||||||
|
except AttributeError:
|
||||||
|
# fallback default if the test did not parametrize
|
||||||
|
return ['eiger', 'jungfrau', 'mythen3', 'gotthard2', 'ctb', 'moench', 'xilinx_ctb']
|
||||||
|
return request.param
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def test_with_simulators(servers):
|
||||||
|
""" Fixture to automatically setup virtual detector servers for testing. """
|
||||||
|
|
||||||
|
LOG_PREFIX_FNAME = '/tmp/slsDetectorPackage_virtual_PythonAPI_test'
|
||||||
|
MAIN_LOG_FNAME = LOG_PREFIX_FNAME + '_log.txt'
|
||||||
|
|
||||||
|
with open(MAIN_LOG_FNAME, 'w') as fp:
|
||||||
|
try:
|
||||||
|
nmods = 2
|
||||||
|
for server in servers:
|
||||||
|
for ninterfaces in range(1,2):
|
||||||
|
if ninterfaces == 2 and server != 'jungfrau' and server != 'moench':
|
||||||
|
continue
|
||||||
|
|
||||||
|
msg = f'Starting Python API Tests for {server}'
|
||||||
|
|
||||||
|
if server == 'jungfrau' or server == 'moench':
|
||||||
|
msg += f' with {ninterfaces} interfaces'
|
||||||
|
|
||||||
|
Log(LogLevel.INFOBLUE, msg, fp)
|
||||||
|
cleanup(fp)
|
||||||
|
startDetectorVirtualServer(server, nmods, fp)
|
||||||
|
startReceiver(nmods, fp)
|
||||||
|
d = loadConfig(name=server, log_file_fp=fp, num_mods=nmods, num_frames=1, num_interfaces=ninterfaces)
|
||||||
|
loadBasicSettings(name=server, d=d, fp=fp)
|
||||||
|
yield # run test
|
||||||
|
cleanup(fp) # teardown
|
||||||
|
except Exception as e:
|
||||||
|
with open(MAIN_LOG_FNAME, 'a') as fp_error:
|
||||||
|
traceback.print_exc(file=fp_error)
|
||||||
|
Log(LogLevel.ERROR, f'Tests Failed.', fp)
|
||||||
|
cleanup(fp)
|
||||||
|
|
||||||
|
|
||||||
48
python/tests/test_pythonAPI.py
Normal file
48
python/tests/test_pythonAPI.py
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
import pytest
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from conftest import test_with_simulators
|
||||||
|
|
||||||
|
from slsdet import Detector
|
||||||
|
|
||||||
|
@pytest.mark.withdetectorsimulators
|
||||||
|
@pytest.mark.parametrize("servers", [["moench"]], indirect=True)
|
||||||
|
def test_rx_ROI_moench(test_with_simulators, servers):
|
||||||
|
""" Test setting and getting rx_ROI property of Detector class for moench. """
|
||||||
|
|
||||||
|
d = Detector()
|
||||||
|
d.rx_roi = (0, 10, 10, 20)
|
||||||
|
roi = d.rx_roi
|
||||||
|
assert roi == [(0, 10, 10, 20)]
|
||||||
|
|
||||||
|
d.rx_roi = [5,15,15,25]
|
||||||
|
|
||||||
|
assert d.rx_roi == [(5,15,15,25)]
|
||||||
|
|
||||||
|
d.rx_roi = [[0,10,0,20], [5,20,410,420]]
|
||||||
|
|
||||||
|
roi = d.rx_roi
|
||||||
|
assert roi == [(0,10,0,20), (5,20,410,420)]
|
||||||
|
|
||||||
|
d.rx_clearroi()
|
||||||
|
roi = d.rx_roi
|
||||||
|
assert roi == [(-1,-1,-1,-1)]
|
||||||
|
|
||||||
|
@pytest.mark.withdetectorsimulators
|
||||||
|
@pytest.mark.parametrize("servers", [["mythen3"]], indirect=True)
|
||||||
|
def test_rx_ROI_mythen(test_with_simulators, servers):
|
||||||
|
""" Test setting and getting rx_ROI property of Detector class for mythen. """
|
||||||
|
|
||||||
|
d = Detector()
|
||||||
|
d.rx_roi = (0, 10)
|
||||||
|
roi = d.rx_roi
|
||||||
|
assert roi == [(0, 10, -1, -1)]
|
||||||
|
|
||||||
|
#d.rx_roi = [[5,15, 0, 1]] # not allowed for mythen3
|
||||||
|
|
||||||
|
d.rx_roi = [0,10, -1, -1]
|
||||||
|
|
||||||
|
assert d.rx_roi == [(0,10,-1,-1)]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
// SPDX-License-Identifier: LGPL-3.0-or-other
|
|
||||||
// Copyright (C) 2021 Contributors to the SLS Detector Package
|
|
||||||
|
|
||||||
void XILINX_FMC_enable_all();
|
|
||||||
void XILINX_FMC_disable_all();
|
|
||||||
@@ -1,64 +0,0 @@
|
|||||||
// SPDX-License-Identifier: LGPL-3.0-or-other
|
|
||||||
// Copyright (C) 2021 Contributors to the SLS Detector Package
|
|
||||||
#include "XILINX_FMC.h"
|
|
||||||
#include "arm64.h"
|
|
||||||
#include "clogger.h"
|
|
||||||
#include <math.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
// clang-format off
|
|
||||||
#define FMC_BASE_PATH "/root/fmc/"
|
|
||||||
#define FMC_VADJ_EN "FMC_VADJ_EN"
|
|
||||||
#define FMCP_VADJ_EN "FMCP_VADJ_EN"
|
|
||||||
#define FMCP_3V3_EN "FMCP_3V3_EN"
|
|
||||||
#define FMC_3V3_EN "FMC_3V3_EN"
|
|
||||||
#define FMC_12V_EN "FMC_12V_EN"
|
|
||||||
#define FMCP_12V_EN "FMCP_12V_EN"
|
|
||||||
|
|
||||||
static const char *fmc_files[] = {
|
|
||||||
FMC_VADJ_EN,
|
|
||||||
FMCP_VADJ_EN,
|
|
||||||
FMCP_3V3_EN,
|
|
||||||
FMC_3V3_EN,
|
|
||||||
FMC_12V_EN,
|
|
||||||
FMCP_12V_EN
|
|
||||||
};
|
|
||||||
// clang-format on
|
|
||||||
|
|
||||||
void XILINX_FMC_enable_all() {
|
|
||||||
LOG(logINFOBLUE, ("enable FMC power\n"));
|
|
||||||
#ifdef VIRTUAL
|
|
||||||
return;
|
|
||||||
#endif
|
|
||||||
char full_path[64];
|
|
||||||
for (size_t i = 0; i < sizeof(fmc_files) / sizeof(fmc_files[0]); ++i) {
|
|
||||||
snprintf(full_path, sizeof(full_path), "%s%s", FMC_BASE_PATH, fmc_files[i]);
|
|
||||||
FILE *fp = fopen(full_path, "w");
|
|
||||||
if (fp == NULL) {
|
|
||||||
LOG(logERROR,("XILINX_FMC: enable Error\n"));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf(fp, "1\n");
|
|
||||||
fclose(fp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void XILINX_FMC_disable_all() {
|
|
||||||
LOG(logINFOBLUE, ("disable FMC power\n"));
|
|
||||||
#ifdef VIRTUAL
|
|
||||||
return;
|
|
||||||
#endif
|
|
||||||
char full_path[64];
|
|
||||||
for (size_t i = 0; i < sizeof(fmc_files) / sizeof(fmc_files[0]); ++i) {
|
|
||||||
snprintf(full_path, sizeof(full_path), "%s%s", FMC_BASE_PATH, fmc_files[i]);
|
|
||||||
FILE *fp = fopen(full_path, "w");
|
|
||||||
if (fp == NULL) {
|
|
||||||
LOG(logERROR,("XILINX_FMC: disable Error\n"));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
fprintf(fp, "0\n");
|
|
||||||
fclose(fp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -7,7 +7,6 @@ add_executable(xilinx_ctbDetectorServer_virtual
|
|||||||
../slsDetectorServer/src/communication_funcs.c
|
../slsDetectorServer/src/communication_funcs.c
|
||||||
../slsDetectorServer/src/arm64.c
|
../slsDetectorServer/src/arm64.c
|
||||||
../slsDetectorServer/src/XILINX_PLL.c
|
../slsDetectorServer/src/XILINX_PLL.c
|
||||||
../slsDetectorServer/src/XILINX_FMC.c
|
|
||||||
../slsDetectorServer/src/common.c
|
../slsDetectorServer/src/common.c
|
||||||
../slsDetectorServer/src/sharedMemory.c
|
../slsDetectorServer/src/sharedMemory.c
|
||||||
../slsDetectorServer/src/loadPattern.c
|
../slsDetectorServer/src/loadPattern.c
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ DESTDIR ?= bin
|
|||||||
INSTMODE = 0777
|
INSTMODE = 0777
|
||||||
|
|
||||||
SRCS = slsDetectorFunctionList.c
|
SRCS = slsDetectorFunctionList.c
|
||||||
SRCS += $(main_src)slsDetectorServer.c $(main_src)slsDetectorServer_funcs.c $(main_src)communication_funcs.c $(main_src)arm64.c $(main_src)XILINX_PLL.c $(main_src)XILINX_FMC.c $(main_src)common.c $(main_src)/sharedMemory.c $(main_src)/loadPattern.c $(md5_dir)md5.c $(main_src)programViaArm.c $(main_src)LTC2620_Driver.c
|
SRCS += $(main_src)slsDetectorServer.c $(main_src)slsDetectorServer_funcs.c $(main_src)communication_funcs.c $(main_src)arm64.c $(main_src)XILINX_PLL.c $(main_src)common.c $(main_src)/sharedMemory.c $(main_src)/loadPattern.c $(md5_dir)md5.c $(main_src)programViaArm.c $(main_src)LTC2620_Driver.c
|
||||||
|
|
||||||
OBJS = $(SRCS:.c=.o)
|
OBJS = $(SRCS:.c=.o)
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
@@ -10,7 +10,6 @@
|
|||||||
|
|
||||||
#include "LTC2620_Driver.h"
|
#include "LTC2620_Driver.h"
|
||||||
#include "XILINX_PLL.h"
|
#include "XILINX_PLL.h"
|
||||||
#include "XILINX_FMC.h"
|
|
||||||
|
|
||||||
#include "loadPattern.h"
|
#include "loadPattern.h"
|
||||||
#ifdef VIRTUAL
|
#ifdef VIRTUAL
|
||||||
@@ -406,10 +405,6 @@ void setupDetector() {
|
|||||||
|
|
||||||
LTC2620_D_SetDefines(DAC_MIN_MV, DAC_MAX_MV, DAC_DRIVER_FILE_NAME, NDAC,
|
LTC2620_D_SetDefines(DAC_MIN_MV, DAC_MAX_MV, DAC_DRIVER_FILE_NAME, NDAC,
|
||||||
NPWR, DAC_POWERDOWN_DRIVER_FILE_NAME);
|
NPWR, DAC_POWERDOWN_DRIVER_FILE_NAME);
|
||||||
|
|
||||||
// power LTC2620 before talking to it:
|
|
||||||
XILINX_FMC_enable_all();
|
|
||||||
|
|
||||||
LOG(logINFOBLUE, ("Powering down all dacs\n"));
|
LOG(logINFOBLUE, ("Powering down all dacs\n"));
|
||||||
for (int idac = 0; idac < NDAC; ++idac) {
|
for (int idac = 0; idac < NDAC; ++idac) {
|
||||||
setDAC(idac, LTC2620_D_GetPowerDownValue(), 0);
|
setDAC(idac, LTC2620_D_GetPowerDownValue(), 0);
|
||||||
@@ -584,7 +579,6 @@ int powerChip(int on, char *mess) {
|
|||||||
} else {
|
} else {
|
||||||
LOG(logINFOBLUE, ("Powering chip: off\n"));
|
LOG(logINFOBLUE, ("Powering chip: off\n"));
|
||||||
bus_w(addr, bus_r(addr) & ~mask);
|
bus_w(addr, bus_r(addr) & ~mask);
|
||||||
XILINX_FMC_disable_all();
|
|
||||||
|
|
||||||
chipConfigured = 0;
|
chipConfigured = 0;
|
||||||
|
|
||||||
|
|||||||
@@ -2568,17 +2568,15 @@ std::vector<int> Module::getReceiverDbitList() const {
|
|||||||
|
|
||||||
void Module::setReceiverDbitList(std::vector<int> list) {
|
void Module::setReceiverDbitList(std::vector<int> list) {
|
||||||
LOG(logDEBUG1) << "Setting Receiver Dbit List";
|
LOG(logDEBUG1) << "Setting Receiver Dbit List";
|
||||||
if (list.size() > 64) {
|
|
||||||
throw RuntimeError("Dbit list size cannot be greater than 64\n");
|
|
||||||
}
|
|
||||||
for (auto &it : list) {
|
for (auto &it : list) {
|
||||||
if (it < 0 || it > 63) {
|
if (it < 0 || it > 63) {
|
||||||
throw RuntimeError("Dbit list value must be between 0 and 63\n");
|
throw RuntimeError("Dbit list value must be between 0 and 63\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
std::sort(begin(list), end(list));
|
auto r = stableRemoveDuplicates(list);
|
||||||
auto last = std::unique(begin(list), end(list));
|
if(r)
|
||||||
list.erase(last, list.end());
|
LOG(logWARNING) << "Removed duplicated from receiver dbit list";
|
||||||
|
|
||||||
StaticVector<int, MAX_RX_DBIT> arg = list;
|
StaticVector<int, MAX_RX_DBIT> arg = list;
|
||||||
sendToReceiver(F_SET_RECEIVER_DBIT_LIST, arg, nullptr);
|
sendToReceiver(F_SET_RECEIVER_DBIT_LIST, arg, nullptr);
|
||||||
|
|||||||
@@ -138,7 +138,8 @@ TEST_CASE("Parse version and help", "[detector]") {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("Parse port and uid", "[detector]") {
|
// TODO: fails on gitea CI due to uid issue, fix later
|
||||||
|
TEST_CASE("Parse port and uid", "[.failsongitea][detector]") {
|
||||||
uid_t uid = getuid();
|
uid_t uid = getuid();
|
||||||
std::string uidStr = std::to_string(uid);
|
std::string uidStr = std::to_string(uid);
|
||||||
uid_t invalidUid = uid + 1000;
|
uid_t invalidUid = uid + 1000;
|
||||||
|
|||||||
@@ -64,7 +64,8 @@ class DataProcessorTest : public DataProcessor {
|
|||||||
* num_transceiver_bytes = 2 both bytes have a value of 125
|
* num_transceiver_bytes = 2 both bytes have a value of 125
|
||||||
* num_digital_bytes is variable and is defined by number of samples
|
* num_digital_bytes is variable and is defined by number of samples
|
||||||
* default num sample is 5
|
* default num sample is 5
|
||||||
* all bytes in digital data take a value of 255
|
* all bytes in digital data take a value of 0xFF (alternating bits between 0,
|
||||||
|
* 1)
|
||||||
*/
|
*/
|
||||||
class DataProcessorTestFixture {
|
class DataProcessorTestFixture {
|
||||||
public:
|
public:
|
||||||
@@ -106,7 +107,7 @@ class DataProcessorTestFixture {
|
|||||||
num_random_offset_bytes);
|
num_random_offset_bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_data() {
|
void set_data(const std::bitset<8> pattern = 0xFF) {
|
||||||
delete[] data;
|
delete[] data;
|
||||||
uint64_t max_bytes_per_bit =
|
uint64_t max_bytes_per_bit =
|
||||||
num_samples % 8 == 0 ? num_samples / 8 : num_samples / 8 + 1;
|
num_samples % 8 == 0 ? num_samples / 8 : num_samples / 8 + 1;
|
||||||
@@ -118,7 +119,8 @@ class DataProcessorTestFixture {
|
|||||||
memset(data, dummy_value, num_analog_bytes); // set to dummy value
|
memset(data, dummy_value, num_analog_bytes); // set to dummy value
|
||||||
memset(data + num_analog_bytes, 0,
|
memset(data + num_analog_bytes, 0,
|
||||||
num_random_offset_bytes); // set to zero
|
num_random_offset_bytes); // set to zero
|
||||||
memset(data + num_analog_bytes + num_random_offset_bytes, 0xFF,
|
memset(data + num_analog_bytes + num_random_offset_bytes,
|
||||||
|
static_cast<uint8_t>(pattern.to_ulong()),
|
||||||
num_digital_bytes); // all digital bits are one
|
num_digital_bytes); // all digital bits are one
|
||||||
memset(data + num_digital_bytes + num_analog_bytes +
|
memset(data + num_digital_bytes + num_analog_bytes +
|
||||||
num_random_offset_bytes,
|
num_random_offset_bytes,
|
||||||
@@ -170,7 +172,7 @@ TEST_CASE_METHOD(DataProcessorTestFixture, "Remove Trailing Bits",
|
|||||||
TEST_CASE_METHOD(DataProcessorTestFixture, "Reorder all",
|
TEST_CASE_METHOD(DataProcessorTestFixture, "Reorder all",
|
||||||
"[.dataprocessor][.reorder]") {
|
"[.dataprocessor][.reorder]") {
|
||||||
// parameters: num_samples, expected_num_digital_bytes,
|
// parameters: num_samples, expected_num_digital_bytes,
|
||||||
// expected_digital_part
|
// expected_digital_part_for_each_bit
|
||||||
auto parameters = GENERATE(
|
auto parameters = GENERATE(
|
||||||
std::make_tuple(5, 64, std::vector<uint8_t>{0b00011111}),
|
std::make_tuple(5, 64, std::vector<uint8_t>{0b00011111}),
|
||||||
std::make_tuple(10, 2 * 64, std::vector<uint8_t>{0xFF, 0b00000011}),
|
std::make_tuple(10, 2 * 64, std::vector<uint8_t>{0xFF, 0b00000011}),
|
||||||
@@ -264,11 +266,13 @@ TEST_CASE_METHOD(DataProcessorTestFixture, "Arrange bitlist with reorder false",
|
|||||||
// expected_digital_part
|
// expected_digital_part
|
||||||
auto parameters = GENERATE(
|
auto parameters = GENERATE(
|
||||||
std::make_tuple(5, std::vector<int>{1, 4, 5}, 5,
|
std::make_tuple(5, std::vector<int>{1, 4, 5}, 5,
|
||||||
std::vector<uint8_t>{0b00000111}),
|
std::vector<uint8_t>{0b00000010}),
|
||||||
|
std::make_tuple(5, std::vector<int>{1, 5, 4}, 5,
|
||||||
|
std::vector<uint8_t>{0b00000100}),
|
||||||
std::make_tuple(5, std::vector<int>{1, 5, 3, 7, 8, 50, 42, 60, 39}, 10,
|
std::make_tuple(5, std::vector<int>{1, 5, 3, 7, 8, 50, 42, 60, 39}, 10,
|
||||||
std::vector<uint8_t>{0xFF, 0b00000001}),
|
std::vector<uint8_t>{0b11110000, 0b00000000}),
|
||||||
std::make_tuple(5, std::vector<int>{1, 5, 3, 7, 8, 50, 42, 60}, 5,
|
std::make_tuple(5, std::vector<int>{1, 5, 3, 7, 8, 50, 42, 60}, 5,
|
||||||
std::vector<uint8_t>{0xFF}));
|
std::vector<uint8_t>{0b11110000}));
|
||||||
|
|
||||||
size_t num_samples, expected_num_digital_bytes;
|
size_t num_samples, expected_num_digital_bytes;
|
||||||
std::vector<uint8_t> expected_digital_part;
|
std::vector<uint8_t> expected_digital_part;
|
||||||
@@ -281,7 +285,7 @@ TEST_CASE_METHOD(DataProcessorTestFixture, "Arrange bitlist with reorder false",
|
|||||||
generaldata->SetCtbDbitReorder(false);
|
generaldata->SetCtbDbitReorder(false);
|
||||||
|
|
||||||
set_num_samples(num_samples);
|
set_num_samples(num_samples);
|
||||||
set_data();
|
set_data(0b01010101); // set digital data to 0x55 to have alternating bits
|
||||||
|
|
||||||
size_t expected_size =
|
size_t expected_size =
|
||||||
num_analog_bytes + num_transceiver_bytes + expected_num_digital_bytes;
|
num_analog_bytes + num_transceiver_bytes + expected_num_digital_bytes;
|
||||||
@@ -316,11 +320,15 @@ TEST_CASE_METHOD(DataProcessorTestFixture, "Arrange bitlist with reorder true",
|
|||||||
// expected_digital_part
|
// expected_digital_part
|
||||||
auto parameters = GENERATE(
|
auto parameters = GENERATE(
|
||||||
std::make_tuple(5, std::vector<int>{1, 4, 5}, 3,
|
std::make_tuple(5, std::vector<int>{1, 4, 5}, 3,
|
||||||
std::vector<uint8_t>{0b00011111}),
|
std::vector<uint8_t>{0x00, 0b00011111, 0x00}),
|
||||||
|
std::make_tuple(5, std::vector<int>{1, 5, 4}, 3,
|
||||||
|
std::vector<uint8_t>{0x00, 0x00, 0b00011111}),
|
||||||
std::make_tuple(10, std::vector<int>{1, 4, 5}, 6,
|
std::make_tuple(10, std::vector<int>{1, 4, 5}, 6,
|
||||||
std::vector<uint8_t>{0xFF, 0b00000011}),
|
std::vector<uint8_t>{0x00, 0x00, 0b11111111, 0b00000011,
|
||||||
|
0x00, 0x00}),
|
||||||
std::make_tuple(8, std::vector<int>{1, 5, 3, 7, 8, 50, 42, 60, 39}, 9,
|
std::make_tuple(8, std::vector<int>{1, 5, 3, 7, 8, 50, 42, 60, 39}, 9,
|
||||||
std::vector<uint8_t>{0xFF}));
|
std::vector<uint8_t>{0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF,
|
||||||
|
0xFF, 0xFF, 0x00}));
|
||||||
|
|
||||||
size_t num_samples, expected_num_digital_bytes;
|
size_t num_samples, expected_num_digital_bytes;
|
||||||
std::vector<uint8_t> expected_digital_part;
|
std::vector<uint8_t> expected_digital_part;
|
||||||
@@ -333,7 +341,7 @@ TEST_CASE_METHOD(DataProcessorTestFixture, "Arrange bitlist with reorder true",
|
|||||||
generaldata->SetCtbDbitReorder(true);
|
generaldata->SetCtbDbitReorder(true);
|
||||||
|
|
||||||
set_num_samples(num_samples);
|
set_num_samples(num_samples);
|
||||||
set_data();
|
set_data(0b01010101);
|
||||||
|
|
||||||
size_t expected_size =
|
size_t expected_size =
|
||||||
num_analog_bytes + num_transceiver_bytes + expected_num_digital_bytes;
|
num_analog_bytes + num_transceiver_bytes + expected_num_digital_bytes;
|
||||||
@@ -343,11 +351,8 @@ TEST_CASE_METHOD(DataProcessorTestFixture, "Arrange bitlist with reorder true",
|
|||||||
|
|
||||||
memset(expected_data, dummy_value, num_analog_bytes);
|
memset(expected_data, dummy_value, num_analog_bytes);
|
||||||
|
|
||||||
for (size_t sample = 0; sample < bitlist.size(); ++sample) {
|
memcpy(expected_data + num_analog_bytes, expected_digital_part.data(),
|
||||||
memcpy(expected_data + num_analog_bytes +
|
expected_digital_part.size());
|
||||||
expected_digital_part.size() * sample,
|
|
||||||
expected_digital_part.data(), expected_digital_part.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
memset(expected_data + expected_num_digital_bytes + num_analog_bytes,
|
memset(expected_data + expected_num_digital_bytes + num_analog_bytes,
|
||||||
dummy_value, num_transceiver_bytes);
|
dummy_value, num_transceiver_bytes);
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <numeric>
|
#include <numeric>
|
||||||
|
#include <set>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
@@ -155,6 +156,10 @@ template <typename Container> bool hasDuplicates(Container c) {
|
|||||||
return pos != c.end(); // if we found something there are duplicates
|
return pos != c.end(); // if we found something there are duplicates
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sorts the container and removes duplicated elements
|
||||||
|
* returns true if elements were removed otherwiese false
|
||||||
|
*/
|
||||||
template <typename T>
|
template <typename T>
|
||||||
typename std::enable_if<is_container<T>::value, bool>::type
|
typename std::enable_if<is_container<T>::value, bool>::type
|
||||||
removeDuplicates(T &c) {
|
removeDuplicates(T &c) {
|
||||||
@@ -167,6 +172,29 @@ removeDuplicates(T &c) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Removed duplicated entries while preserving the oder
|
||||||
|
* returns true if elements were removed otherwiese false
|
||||||
|
*/
|
||||||
|
template <typename T>
|
||||||
|
typename std::enable_if<is_container<T>::value, bool>::type
|
||||||
|
stableRemoveDuplicates(T &c) {
|
||||||
|
auto containerSize = c.size();
|
||||||
|
std::set<typename T::value_type> seen;
|
||||||
|
c.erase(
|
||||||
|
std::remove_if(c.begin(), c.end(),
|
||||||
|
[&](const typename T::value_type& val) {
|
||||||
|
return !seen.insert(val).second; // erase if already seen
|
||||||
|
}),
|
||||||
|
c.end()
|
||||||
|
);
|
||||||
|
if (c.size() != containerSize) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
} // namespace sls
|
} // namespace sls
|
||||||
|
|
||||||
#endif // CONTAINER_UTILS_H
|
#endif // CONTAINER_UTILS_H
|
||||||
|
|||||||
@@ -153,13 +153,35 @@ TEST_CASE("check for duplicates in vector of pairs") {
|
|||||||
REQUIRE(hasDuplicates(vec) == true);
|
REQUIRE(hasDuplicates(vec) == true);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("remove duplicates from vector") {
|
TEST_CASE("sorts the vector and remove duplicates") {
|
||||||
std::vector<int> v{5, 6, 5, 3};
|
std::vector<int> v{5, 6, 5, 3};
|
||||||
auto r = removeDuplicates(v);
|
auto r = removeDuplicates(v);
|
||||||
CHECK(r == true); // did indeed remove elements
|
CHECK(r == true); // did indeed remove elements
|
||||||
CHECK(v == std::vector<int>{3, 5, 6});
|
CHECK(v == std::vector<int>{3, 5, 6});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("remove duplicates but keep order") {
|
||||||
|
std::vector<int> v{5, 6, 5, 3};
|
||||||
|
auto r = stableRemoveDuplicates(v);
|
||||||
|
CHECK(r == true); // did indeed remove elements
|
||||||
|
CHECK(v == std::vector<int>{5, 6, 3});
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("remove duplicates but keep order, all elements the same ") {
|
||||||
|
std::vector<char> v{'c', 'c', 'c', 'c', 'c', 'c'};
|
||||||
|
auto r = stableRemoveDuplicates(v);
|
||||||
|
CHECK(r == true); // did indeed remove elements
|
||||||
|
CHECK(v == std::vector<char>{'c'});
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("remove duplicates but keep order, pattern ") {
|
||||||
|
std::vector<int> v{8,1,2,8,8,3,2};
|
||||||
|
auto r = stableRemoveDuplicates(v);
|
||||||
|
CHECK(r == true); // did indeed remove elements
|
||||||
|
CHECK(v == std::vector<int>{8,1,2,3});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
TEST_CASE("remove duplicated empty vector") {
|
TEST_CASE("remove duplicated empty vector") {
|
||||||
std::vector<int> v;
|
std::vector<int> v;
|
||||||
auto r = removeDuplicates(v);
|
auto r = removeDuplicates(v);
|
||||||
@@ -167,4 +189,11 @@ TEST_CASE("remove duplicated empty vector") {
|
|||||||
CHECK(v == std::vector<int>{});
|
CHECK(v == std::vector<int>{});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("remove duplicated empty vector using stable version") {
|
||||||
|
std::vector<int> v;
|
||||||
|
auto r = stableRemoveDuplicates(v);
|
||||||
|
CHECK(r == false); // no elements to remove
|
||||||
|
CHECK(v == std::vector<int>{});
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace sls
|
} // namespace sls
|
||||||
|
|||||||
@@ -113,7 +113,7 @@ def startTestsForAll(args, fp):
|
|||||||
startDetectorVirtualServer(server, args.num_mods, fp)
|
startDetectorVirtualServer(server, args.num_mods, fp)
|
||||||
startFrameSynchronizerPullSocket(server, fp)
|
startFrameSynchronizerPullSocket(server, fp)
|
||||||
startFrameSynchronizer(args.num_mods, fp)
|
startFrameSynchronizer(args.num_mods, fp)
|
||||||
d = loadConfig(name=server, rx_hostname=args.rx_hostname, settingsdir=args.settingspath, fp=fp, num_mods=args.num_mods, num_frames=args.num_frames)
|
d = loadConfig(name=server, rx_hostname=args.rx_hostname, settingsdir=args.settingspath, log_file_fp=fp, num_mods=args.num_mods, num_frames=args.num_frames)
|
||||||
loadBasicSettings(name=server, d=d, fp=fp)
|
loadBasicSettings(name=server, d=d, fp=fp)
|
||||||
acquire(fp, d)
|
acquire(fp, d)
|
||||||
testFramesCaught(server, d, args.num_frames)
|
testFramesCaught(server, d, args.num_frames)
|
||||||
|
|||||||
@@ -18,9 +18,11 @@ from utils_for_test import (
|
|||||||
RuntimeException,
|
RuntimeException,
|
||||||
cleanup,
|
cleanup,
|
||||||
startProcessInBackground,
|
startProcessInBackground,
|
||||||
|
startReceiver,
|
||||||
startDetectorVirtualServer,
|
startDetectorVirtualServer,
|
||||||
connectToVirtualServers,
|
connectToVirtualServers,
|
||||||
loadBasicSettings,
|
loadBasicSettings,
|
||||||
|
loadConfig,
|
||||||
runProcessWithLogFile
|
runProcessWithLogFile
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -28,45 +30,6 @@ LOG_PREFIX_FNAME = '/tmp/slsDetectorPackage_virtual_roi_test'
|
|||||||
MAIN_LOG_FNAME = LOG_PREFIX_FNAME + '_log.txt'
|
MAIN_LOG_FNAME = LOG_PREFIX_FNAME + '_log.txt'
|
||||||
ROI_TEST_FNAME = LOG_PREFIX_FNAME + '_results_'
|
ROI_TEST_FNAME = LOG_PREFIX_FNAME + '_results_'
|
||||||
|
|
||||||
def startReceiver(num_mods, fp):
|
|
||||||
if num_mods == 1:
|
|
||||||
cmd = ['slsReceiver']
|
|
||||||
else:
|
|
||||||
cmd = ['slsMultiReceiver', str(DEFAULT_TCP_RX_PORTNO), str(num_mods)]
|
|
||||||
# in 10.0.0
|
|
||||||
#cmd = ['slsMultiReceiver', '-p', str(DEFAULT_TCP_RX_PORTNO), '-n', str(num_mods)]
|
|
||||||
startProcessInBackground(cmd, fp)
|
|
||||||
time.sleep(1)
|
|
||||||
|
|
||||||
|
|
||||||
def loadConfigForRoi(name, fp, num_mods = 1, num_interfaces = 1):
|
|
||||||
Log(LogLevel.INFO, 'Loading config')
|
|
||||||
Log(LogLevel.INFO, 'Loading config', fp)
|
|
||||||
try:
|
|
||||||
d = connectToVirtualServers(name, num_mods)
|
|
||||||
|
|
||||||
if name == 'jungfrau' or name == 'moench':
|
|
||||||
d.numinterfaces = num_interfaces
|
|
||||||
|
|
||||||
d.udp_dstport = DEFAULT_UDP_DST_PORTNO
|
|
||||||
if name == 'eiger' or name == 'jungfrau' or name == 'moench':
|
|
||||||
d.udp_dstport2 = DEFAULT_UDP_DST_PORTNO + 1
|
|
||||||
|
|
||||||
d.rx_hostname = 'localhost'
|
|
||||||
d.udp_dstip = 'auto'
|
|
||||||
if name != "eiger":
|
|
||||||
d.udp_srcip = 'auto'
|
|
||||||
if name == 'jungfrau' or name == 'moench':
|
|
||||||
d.udp_dstip2 = 'auto'
|
|
||||||
d.powerchip = 1
|
|
||||||
|
|
||||||
d.frames = 5
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
raise RuntimeException(f'Could not load config for {name}. Error: {str(e)}') from e
|
|
||||||
|
|
||||||
return d
|
|
||||||
|
|
||||||
def startTestsForAll(fp):
|
def startTestsForAll(fp):
|
||||||
servers = [
|
servers = [
|
||||||
'eiger',
|
'eiger',
|
||||||
@@ -89,7 +52,7 @@ def startTestsForAll(fp):
|
|||||||
cleanup(fp)
|
cleanup(fp)
|
||||||
startDetectorVirtualServer(server, nmods, fp)
|
startDetectorVirtualServer(server, nmods, fp)
|
||||||
startReceiver(nmods, fp)
|
startReceiver(nmods, fp)
|
||||||
d = loadConfigForRoi(name=server, fp=fp, num_mods=nmods, num_interfaces=ninterfaces)
|
d = loadConfig(name=server, log_file_fp = fp, num_mods=nmods, num_frames=5, num_interfaces=ninterfaces)
|
||||||
loadBasicSettings(name=server, d=d, fp=fp)
|
loadBasicSettings(name=server, d=d, fp=fp)
|
||||||
|
|
||||||
fname = ROI_TEST_FNAME + server + '.txt'
|
fname = ROI_TEST_FNAME + server + '.txt'
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ def startCmdTestsForAll(args, fp):
|
|||||||
cleanup(fp)
|
cleanup(fp)
|
||||||
startDetectorVirtualServer(name=server, num_mods=num_mods, fp=fp)
|
startDetectorVirtualServer(name=server, num_mods=num_mods, fp=fp)
|
||||||
startReceiver(num_mods, fp)
|
startReceiver(num_mods, fp)
|
||||||
d = loadConfig(name=server, rx_hostname=args.rx_hostname, settingsdir=args.settingspath, fp=fp, num_mods=num_mods)
|
d = loadConfig(name=server, rx_hostname=args.rx_hostname, settingsdir=args.settingspath, log_file_fp=fp, num_mods=num_mods)
|
||||||
loadBasicSettings(name=server, d=d, fp=fp)
|
loadBasicSettings(name=server, d=d, fp=fp)
|
||||||
runProcessWithLogFile('Cmd Tests (' + args.markers + ') for ' + server, cmd, fp, fname)
|
runProcessWithLogFile('Cmd Tests (' + args.markers + ') for ' + server, cmd, fp, fname)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ SERVER_START_PORTNO=1900
|
|||||||
|
|
||||||
init(autoreset=True)
|
init(autoreset=True)
|
||||||
|
|
||||||
|
|
||||||
class LogLevel(Enum):
|
class LogLevel(Enum):
|
||||||
INFO = 0
|
INFO = 0
|
||||||
INFORED = 1
|
INFORED = 1
|
||||||
@@ -193,32 +192,51 @@ def connectToVirtualServers(name, num_mods, ctb_object=False):
|
|||||||
|
|
||||||
return d
|
return d
|
||||||
|
|
||||||
|
def startReceiver(num_mods, fp):
|
||||||
|
if num_mods == 1:
|
||||||
|
cmd = ['slsReceiver']
|
||||||
|
else:
|
||||||
|
cmd = ['slsMultiReceiver', str(DEFAULT_TCP_RX_PORTNO), str(num_mods)]
|
||||||
|
# in 10.0.0
|
||||||
|
#cmd = ['slsMultiReceiver', '-p', str(DEFAULT_TCP_RX_PORTNO), '-n', str(num_mods)]
|
||||||
|
startProcessInBackground(cmd, fp)
|
||||||
|
time.sleep(1)
|
||||||
|
|
||||||
def loadConfig(name, rx_hostname, settingsdir, fp, num_mods = 1, num_frames = 1):
|
|
||||||
|
def loadConfig(name, rx_hostname = 'localhost', settingsdir = None, log_file_fp = None, num_mods = 1, num_frames = 1, num_interfaces = 1):
|
||||||
Log(LogLevel.INFO, 'Loading config')
|
Log(LogLevel.INFO, 'Loading config')
|
||||||
Log(LogLevel.INFO, 'Loading config', fp)
|
Log(LogLevel.INFO, 'Loading config', log_file_fp)
|
||||||
try:
|
try:
|
||||||
d = connectToVirtualServers(name, num_mods)
|
d = connectToVirtualServers(name, num_mods)
|
||||||
|
|
||||||
|
if name == 'jungfrau' or name == 'moench':
|
||||||
|
d.numinterfaces = num_interfaces
|
||||||
|
|
||||||
d.udp_dstport = DEFAULT_UDP_DST_PORTNO
|
d.udp_dstport = DEFAULT_UDP_DST_PORTNO
|
||||||
if name == 'eiger':
|
if name == 'eiger' or name == 'jungfrau' or name == 'moench':
|
||||||
d.udp_dstport2 = DEFAULT_UDP_DST_PORTNO + 1
|
d.udp_dstport2 = DEFAULT_UDP_DST_PORTNO + 1
|
||||||
|
|
||||||
d.rx_hostname = rx_hostname
|
d.rx_hostname = rx_hostname
|
||||||
|
|
||||||
d.udp_dstip = 'auto'
|
d.udp_dstip = 'auto'
|
||||||
|
|
||||||
if name != "eiger":
|
if name != "eiger":
|
||||||
d.udp_srcip = 'auto'
|
d.udp_srcip = 'auto'
|
||||||
|
|
||||||
|
if name == "jungfrau" or name == "moench":
|
||||||
|
d.udp_dstip2 = 'auto'
|
||||||
|
|
||||||
if name == "jungfrau" or name == "moench" or name == "xilinx_ctb":
|
if name == "jungfrau" or name == "moench" or name == "xilinx_ctb":
|
||||||
d.powerchip = 1
|
d.powerchip = 1
|
||||||
|
|
||||||
if name == "xilinx_ctb":
|
if name == "xilinx_ctb":
|
||||||
d.configureTransceiver()
|
d.configureTransceiver()
|
||||||
|
|
||||||
if name == "eiger":
|
if settingsdir is not None and name in ['eiger', 'mythen3']:
|
||||||
d.trimen = [4500, 5400, 6400]
|
d.settingspath = settingsdir + '/' + name + '/'
|
||||||
d.settingspath = settingsdir + '/eiger/'
|
d.trimen = [4500, 5400, 6400] if name == 'eiger' else [4000, 6000, 8000, 12000]
|
||||||
d.setThresholdEnergy(4500, detectorSettings.STANDARD)
|
d.setThresholdEnergy(4500, detectorSettings.STANDARD)
|
||||||
|
|
||||||
d.frames = num_frames
|
d.frames = num_frames
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|||||||
@@ -1,39 +1,14 @@
|
|||||||
# SPDX-License-Identifier: LGPL-3.0-or-other
|
#!/bin/bash
|
||||||
# Copyright (C) 2021 Contributors to the SLS Detector Package
|
|
||||||
#echo $#
|
|
||||||
#if [ $# = 0 ]; then
|
|
||||||
# f=$0
|
|
||||||
#else
|
|
||||||
# f=$1
|
|
||||||
#fi
|
|
||||||
#echo $f
|
|
||||||
if [ "x${BASH_ARGV[0]}" = "x" ]; then
|
|
||||||
#if [ "x$f" = "x" ]; then
|
|
||||||
if [ ! -f this_build_bin_path.sh ]; then
|
|
||||||
f=$0
|
|
||||||
echo "aaaa"
|
|
||||||
#thispath=$(dirname ${BASH_ARGV[0]})
|
|
||||||
thispath=$(dirname $f)
|
|
||||||
p=$(cd ${thispath};pwd);
|
|
||||||
THIS_PATH="$p/build/bin/"
|
|
||||||
# echo "ERROR: must cd where/this/package/is before calling this_path.sh"
|
|
||||||
# echo "Try sourcing it"
|
|
||||||
else
|
|
||||||
echo "bbb"
|
|
||||||
THIS_PATH="$PWD/build/bin/";
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
thispath=$(dirname ${BASH_ARGV[0]})
|
|
||||||
p=$(cd ${thispath};pwd);
|
|
||||||
THIS_PATH="$p/build/bin/"
|
|
||||||
echo "ccc"
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "this_path="$THIS_PATH
|
# Since this script could be sourced, $0 is not sufficent, BASH_SOURCE[0] is necessary
|
||||||
export PATH=$THIS_PATH:$PATH
|
SCRIPT_LOCATION="$(realpath ${BASH_SOURCE[0]})"
|
||||||
export LD_LIBRARY_PATH=$THIS_PATH:$LD_LIBRARY_PATH
|
SCRIPT_LOCATION="$(dirname ${SCRIPT_LOCATION})"
|
||||||
export PYTHONPATH=$THIS_PATH:$PYTHONPATH
|
BUILDBIN_LOCATION="${SCRIPT_LOCATION}/build/bin"
|
||||||
|
|
||||||
echo "path="$PATH
|
if [ ! -d "${BUILDBIN_LOCATION}" ]; then
|
||||||
echo "ld_library_path="$LD_LIBRARY_PATH
|
echo Cannot find path ${BUILDBIN_LOCATION}
|
||||||
echo "pythonpath="$PYTHON_PATH
|
else
|
||||||
|
echo Adding ${BUILDBIN_LOCATION} to PATH and PYTHONPATH
|
||||||
|
export PATH=${BUILDBIN_LOCATION}:${PATH}
|
||||||
|
export PYTHONPATH=${BUILDBIN_LOCATION}:${PYTHONPATH}
|
||||||
|
fi
|
||||||
|
|||||||
Reference in New Issue
Block a user