mirror of
https://github.com/slsdetectorgroup/slsDetectorPackage.git
synced 2026-07-16 22:56:03 +02:00
Dev/matterhorn server funcs (#1469)
Build on RHEL9 docker image / build (push) Successful in 4m15s
Build on RHEL8 docker image / build (push) Successful in 5m21s
Build and Deploy on local RHEL9 / build (push) Successful in 2m12s
Build and Deploy on local RHEL8 / build (push) Successful in 5m12s
Run Simulator Tests on local RHEL9 / build (push) Successful in 18m55s
Run Simulator Tests on local RHEL8 / build (push) Successful in 22m19s
Build on RHEL9 docker image / build (push) Successful in 4m15s
Build on RHEL8 docker image / build (push) Successful in 5m21s
Build and Deploy on local RHEL9 / build (push) Successful in 2m12s
Build and Deploy on local RHEL8 / build (push) Successful in 5m12s
Run Simulator Tests on local RHEL9 / build (push) Successful in 18m55s
Run Simulator Tests on local RHEL8 / build (push) Successful in 22m19s
* added fetch fmt server library * added first draft of matterhorn * added cpp TCP Interface to slsDetectorServer * bug: added std::signal for proper handling of ctr+c * added compile option to set log level * WIP * dont use c project settings when building matterhornserver * updated logger * WIP * WIP * linked fmt to slsProjectOptions * solved merge conflict * some refactoring * cleaned up logs * WIP * generated register defs from csv file * oops given in hex * properly added fmt as a dependency * some format changes * WIP * used CRTP for virtual detector * WIP * added udp functions to matterhornserver * fixed build * added Server class usable for all detectors * removed stopserver * added some more functions * wrong overload * porper cleanup of matterhorn app * PR Review * refactored directory structure * added shared memory for aqcuisition status * implemented bus read and write * added Matterhorn data class * modified memory model * added SPI communication * moved memory for Bus communication to BucCommunication class * WIP added HelperFunction for mask conversion * completed HelperFunctions * added tests for MatterHorn Helper Functions * removed shared memory in destructor * fixed SPI communication * moved SharedMemory to slsSupportLib * added toolchain file for cross compilation * fix constructor for HarwareSPICommunication is public * update receiver parameters function * updated mac address * uploaded matterhorn server binary tracked as lfs * small fixes from tests on board * automatically update matterhorn api version when cross compiling binaries * fix bug in SPI read * copy to server_directory/bin when cross compiling * fixed cmake list * update generate_registerdefs.py * fixed copy of server binary * always return error message * add error log when opening dev/mem * code review * fixed eiger, mythen tests for dynamic range * second Review * member function getDerived for better readability * split code into implementation class and actual class doing tcp communication * added slsWarnings and c++17 compiler option * added git lfs to workflow * fix gitea workflows * bug: add extra clock register * implement initial checks * bug: client excpetcs 4 bytes * refactoring directory structure and rename to .hpp * check if detector already set up * missed .h to .hpp * Code Review 3 * use temmplate value for stopserver * use internal CMAKE_CROSSCOMPILING variable * moved boolean stop server flag to DetectorImpl - moving template parameter up * missed a file * replace baseclass:: with this * add Matterhorn server in github workflow * whatever workflow bug- lets see * fixed receiving trim bits changed to int64_t
This commit is contained in:
@@ -15,13 +15,14 @@ jobs:
|
||||
steps:
|
||||
- name: Clone repository
|
||||
run: |
|
||||
git lfs install --skip-smudge
|
||||
echo Cloning ${{ github.ref_name }}
|
||||
git clone https://${{secrets.GITHUB_TOKEN}}@gitea.psi.ch/${{ github.repository }}.git --branch=${{ github.ref_name }} .
|
||||
|
||||
- name: Build library
|
||||
run: |
|
||||
mkdir build && cd build
|
||||
cmake .. -DSLS_USE_PYTHON=ON -DSLS_USE_TESTS=ON -DSLS_USE_SIMULATOR=ON
|
||||
cmake .. -DSLS_USE_PYTHON=ON -DSLS_USE_TESTS=ON -DSLS_USE_SIMULATOR=ON -DSLS_USE_MATTERHORN=ON
|
||||
make -j 2
|
||||
|
||||
- name: C++ unit tests
|
||||
|
||||
@@ -19,7 +19,7 @@ jobs:
|
||||
- name: Build library
|
||||
run: |
|
||||
mkdir build && cd build
|
||||
cmake .. -DSLS_USE_PYTHON=ON -DSLS_USE_TESTS=ON -DSLS_USE_SIMULATOR=ON
|
||||
cmake .. -DSLS_USE_PYTHON=ON -DSLS_USE_TESTS=ON -DSLS_USE_SIMULATOR=ON -DSLS_USE_MATTERHORN=ON
|
||||
make -j 2
|
||||
|
||||
- name: C++ unit tests
|
||||
|
||||
@@ -39,7 +39,8 @@ jobs:
|
||||
-DSLS_USE_HDF5=ON \
|
||||
-DSLS_USE_GUI=ON \
|
||||
-DSLS_USE_MOENCH=ON \
|
||||
-DSLS_TREAT_WARNINGS_AS_ERRORS=ON
|
||||
-DSLS_TREAT_WARNINGS_AS_ERRORS=ON \
|
||||
-DSLS_USE_MATTERHORN=ON
|
||||
|
||||
- name: Build
|
||||
# Build your program with the given configuration
|
||||
|
||||
+17
-4
@@ -250,6 +250,18 @@ if(SLS_BUILD_ONLY_MOENCH)
|
||||
set(SLS_USE_MOENCH ON CACHE BOOL "Enable" FORCE)
|
||||
endif()
|
||||
|
||||
option(SLS_BUILD_ONLY_MATTERHORN "compile only Matterhorn" OFF)
|
||||
if(SLS_BUILD_ONLY_MATTERHORN)
|
||||
message(STATUS "Build MATTERHORN server only!")
|
||||
set(SLS_BUILD_SHARED_LIBRARIES OFF CACHE BOOL "Disabled for MATTERHORN_ONLY" FORCE)
|
||||
set(SLS_USE_TEXTCLIENT OFF CACHE BOOL "Disabled for MATTERHORN_ONLY" FORCE)
|
||||
set(SLS_USE_DETECTOR ON CACHE BOOL "Disabled for MATTERHORN_ONLY" FORCE)
|
||||
set(SLS_USE_RECEIVER OFF CACHE BOOL "Disabled for MATTERHORN_ONLY" FORCE)
|
||||
set(SLS_USE_RECEIVER_BINARIES OFF CACHE BOOL "Disabled for MATTERHORN_ONLY" FORCE)
|
||||
set(SLS_USE_SERVER ON CACHE BOOL "Enable building cpp server" FORCE)
|
||||
set(SLS_USE_MATTERHORN ON CACHE BOOL "Enable Matterhorn" FORCE)
|
||||
endif()
|
||||
|
||||
#Convenience option to switch off defaults when building Jungfrau binaries only
|
||||
option(SLS_BUILD_ONLY_JUNGFRAU "compile only Jungfrau" OFF)
|
||||
if(SLS_BUILD_ONLY_JUNGFRAU)
|
||||
@@ -440,14 +452,15 @@ if (SLS_USE_GUI)
|
||||
add_subdirectory(slsDetectorGui)
|
||||
endif (SLS_USE_GUI)
|
||||
|
||||
if (SLS_USE_MATTERHORN)
|
||||
add_subdirectory(slsDetectorServers/matterhornServer)
|
||||
endif()
|
||||
|
||||
if (SLS_USE_SIMULATOR)
|
||||
add_subdirectory(slsDetectorServers)
|
||||
endif (SLS_USE_SIMULATOR)
|
||||
|
||||
# cant add_subdirectory twice
|
||||
if (SLS_USE_MATTERHORN AND !SLS_USE_SIMULATOR)
|
||||
add_subdirectory(slsDetectorServers/matterhornServer)
|
||||
endif()
|
||||
|
||||
if (SLS_USE_PYTHON)
|
||||
find_package (Python 3.8 COMPONENTS Interpreter Development.Module REQUIRED)
|
||||
set(PYBIND11_FINDPYTHON ON) # Needed for RH8
|
||||
|
||||
@@ -32,23 +32,47 @@ def argument_parser():
|
||||
|
||||
# TODO: should be configurable
|
||||
header = r"""
|
||||
#pragma once
|
||||
// clang-format off
|
||||
#include "RegisterHelperStructs.hpp"
|
||||
|
||||
namespace sls {
|
||||
|
||||
|
||||
|
||||
namespace Reg {
|
||||
|
||||
/// @brief Enum for IP cores, value are adresses
|
||||
enum class IPCore : uint32_t {
|
||||
MH_RO_SM_AXI = 0, // dummy adresses for now
|
||||
FHDR_AXI = 1,
|
||||
AURORA_STATUS = 2,
|
||||
AURORA_STATUS2 = 3,
|
||||
PACKETIZERREG = 4,
|
||||
UNKNOWN = 5
|
||||
MH_RO_SM_AXI = 0xB0010000,
|
||||
FHDR_AXI = 0xB0011000,
|
||||
AURORA_STATUS = 0xB0014000,
|
||||
AURORA_STATUS2 = 0xB0015000,
|
||||
PACKETIZERREG = 0x00000000, // TODO: fill in correct address
|
||||
UNKNOWN = 0x00000000 // dont know yet
|
||||
};
|
||||
|
||||
constexpr size_t IPCORE_REGISTER_BLOCK_SIZE =
|
||||
0x1000; // size of each IP core address space in bytes // TODO: maybe add in
|
||||
// other file definitions
|
||||
|
||||
// clang-format off
|
||||
|
||||
"""
|
||||
|
||||
postpend = r"""
|
||||
constexpr RegisterField ModuleRow{
|
||||
Frame_HDR_ModCoord_LSB_Reg, 0, 0xffff};
|
||||
|
||||
constexpr RegisterField ModuleCol{
|
||||
Frame_HDR_ModCoord_LSB_Reg, 16, 0xffff};
|
||||
|
||||
constexpr RegisterField ModuleCoordz{
|
||||
Frame_HDR_ModCoord_MSB_Reg, 0, 0xffff};
|
||||
|
||||
constexpr RegisterField ModuleIndex{
|
||||
Frame_HDR_ModCoord_MSB_Reg, 16, 0xffff};
|
||||
} // namespace Reg
|
||||
} // namespace sls
|
||||
// clang-format on
|
||||
"""
|
||||
|
||||
+17
-16
@@ -20,8 +20,8 @@ API_FILE = ROOT_DIR / "slsSupportLib/include/sls/versionAPI.h"
|
||||
VERSION_FILE = ROOT_DIR / "VERSION"
|
||||
|
||||
parser = argparse.ArgumentParser(description = 'updates API version')
|
||||
parser.add_argument('api_module_name', choices=["APILIB", "APIRECEIVER", "APICTB", "APIGOTTHARD2", "APIMOENCH", "APIEIGER", "APIXILINXCTB", "APIJUNGFRAU", "APIMYTHEN3"], help = 'module name to change api version options are: ["APILIB", "APIRECEIVER", "APICTB", "APIGOTTHARD2", "APIMOENCH", "APIEIGER", "APIXILINXCTB", "APIJUNGFRAU", "APIMYTHEN3"]')
|
||||
parser.add_argument('api_dir', help = 'Relative or absolute path to the module code')
|
||||
parser.add_argument('api_module_name', choices=["APILIB", "APIRECEIVER", "APICTB", "APIGOTTHARD2", "APIMOENCH", "APIEIGER", "APIXILINXCTB", "APIJUNGFRAU", "APIMYTHEN3", "APIMATTERHORN"], help = 'module name to change api version options are: ["APILIB", "APIRECEIVER", "APICTB", "APIGOTTHARD2", "APIMOENCH", "APIEIGER", "APIXILINXCTB", "APIJUNGFRAU", "APIMYTHEN3", "APIMATTERHORN"]')
|
||||
parser.add_argument('api_dirs', nargs="+", help = 'Relative or absolute paths to the module code')
|
||||
|
||||
def update_api_file(new_api : str, api_module_name : str, api_file_name : str):
|
||||
|
||||
@@ -36,21 +36,22 @@ def update_api_file(new_api : str, api_module_name : str, api_file_name : str):
|
||||
else:
|
||||
api_file.write(line)
|
||||
|
||||
def get_latest_modification_date(directory : str):
|
||||
def get_latest_modification_date(directories : list[str]):
|
||||
latest_time = 0
|
||||
latest_date = None
|
||||
|
||||
for root, dirs, files in os.walk(directory):
|
||||
for file in files:
|
||||
if file.endswith(".o"):
|
||||
continue
|
||||
full_path = os.path.join(root, file)
|
||||
try:
|
||||
mtime = os.path.getmtime(full_path)
|
||||
if mtime > latest_time:
|
||||
latest_time = mtime
|
||||
except FileNotFoundError:
|
||||
continue
|
||||
for directory in directories:
|
||||
for root, dirs, files in os.walk(directory):
|
||||
for file in files:
|
||||
if file.endswith(".o"):
|
||||
continue
|
||||
full_path = os.path.join(root, file)
|
||||
try:
|
||||
mtime = os.path.getmtime(full_path)
|
||||
if mtime > latest_time:
|
||||
latest_time = mtime
|
||||
except FileNotFoundError:
|
||||
continue
|
||||
|
||||
latest_date = datetime.fromtimestamp(latest_time).strftime("%y%m%d")
|
||||
|
||||
@@ -74,9 +75,9 @@ if __name__ == "__main__":
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
api_dir = ROOT_DIR / args.api_dir
|
||||
api_dirs = [ROOT_DIR / api_dir for api_dir in args.api_dirs]
|
||||
|
||||
|
||||
update_api_version(args.api_module_name, api_dir)
|
||||
update_api_version(args.api_module_name, api_dirs)
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
bin/ filter=lfs diff=lfs merge=lfs -text
|
||||
bin/** filter=lfs diff=lfs merge=lfs -text
|
||||
bin/matterhornDetectorServer filter=lfs diff=lfs merge=lfs -text
|
||||
@@ -2,22 +2,40 @@
|
||||
|
||||
set(MATTERHORN_SOURCES
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/MatterhornApp.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/communication/SPICommunication.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/utils/HelperFunctions.cpp
|
||||
)
|
||||
|
||||
set(MATTERHORN_INCLUDE_DIRS
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/communication
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/utils
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/defs
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../slsSupportLib/include
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../slsDetectorServer_cpp/include
|
||||
)
|
||||
|
||||
if(SLS_USE_SIMULATOR)
|
||||
list(APPEND MATTERHORN_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src/VirtualMatterhornServer.cpp)
|
||||
set(MATTERHORN_SERVER_HEADER "VirtualMatterhornServer.hpp")
|
||||
|
||||
add_executable(matterhornDetectorServer_virtual ${MATTERHORN_SOURCES})
|
||||
|
||||
target_compile_definitions(matterhornDetectorServer_virtual PRIVATE
|
||||
MATTERHORN_SERVER_HEADER=<VirtualMatterhornServer.hpp>
|
||||
MATTERHORN_SERVER_CLASS=VirtualMatterhornServer
|
||||
)
|
||||
|
||||
target_include_directories(matterhornDetectorServer_virtual
|
||||
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../slsSupportLib/include
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../slsDetectorServer_cpp/include)
|
||||
PRIVATE ${MATTERHORN_INCLUDE_DIRS})
|
||||
|
||||
target_link_libraries(matterhornDetectorServer_virtual
|
||||
PUBLIC
|
||||
slsSupportStatic
|
||||
slsServerStatic)
|
||||
slsServerStatic
|
||||
slsProjectOptions
|
||||
PRIVATE
|
||||
slsProjectWarnings
|
||||
)
|
||||
|
||||
set_target_properties(matterhornDetectorServer_virtual PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin
|
||||
@@ -26,37 +44,61 @@ if(SLS_USE_SIMULATOR)
|
||||
install(TARGETS matterhornDetectorServer_virtual
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
)
|
||||
else()
|
||||
list(APPEND MATTERHORN_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src/MatterhornServer.cpp)
|
||||
endif() # maybe better to have a else if build with simulators on one always uses the virtual server in MatterhornApp
|
||||
|
||||
if(SLS_USE_MATTERHORN)
|
||||
|
||||
|
||||
if(CMAKE_CROSSCOMPILING) # only update version if cross compiling binaries
|
||||
find_package(Python3 REQUIRED COMPONENTS Interpreter REQUIRED)
|
||||
add_custom_target(update_server_version ALL
|
||||
COMMAND ${Python3_EXECUTABLE} ${CMAKE_SOURCE_DIR}/etc/updateAPIVersion.py APIMATTERHORN ${CMAKE_SOURCE_DIR}/slsDetectorServers/matterhornServer ${CMAKE_SOURCE_DIR}/slsDetectorServers/slsDetectorServer_cpp
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||
COMMENT "Updating APIMATTERHORN version"
|
||||
VERBATIM)
|
||||
endif()
|
||||
|
||||
add_executable(matterhornDetectorServer ${MATTERHORN_SOURCES})
|
||||
|
||||
if(CMAKE_CROSSCOMPILING) # only update version if cross compiling binaries
|
||||
add_dependencies(matterhornDetectorServer update_server_version)
|
||||
endif()
|
||||
|
||||
target_compile_definitions(matterhornDetectorServer PRIVATE
|
||||
MATTERHORN_SERVER_HEADER=<MatterhornServer.hpp>
|
||||
MATTERHORN_SERVER_CLASS=MatterhornServer
|
||||
)
|
||||
|
||||
target_include_directories(matterhornDetectorServer
|
||||
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../slsSupportLib/include
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../slsDetectorServer_cpp/include)
|
||||
|
||||
PRIVATE ${MATTERHORN_INCLUDE_DIRS})
|
||||
|
||||
target_link_libraries(matterhornDetectorServer
|
||||
PUBLIC
|
||||
slsSupportStatic
|
||||
#slsDetectorStatic
|
||||
slsServerStatic)
|
||||
slsServerStatic
|
||||
slsProjectOptions
|
||||
PRIVATE
|
||||
slsProjectWarnings
|
||||
)
|
||||
|
||||
if(CMAKE_CROSSCOMPILING) # change output directory to stay consitent with c server binaries when cross compiling
|
||||
set(RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/bin)
|
||||
else()
|
||||
set(RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
|
||||
endif()
|
||||
|
||||
set_target_properties(matterhornDetectorServer PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin
|
||||
RUNTIME_OUTPUT_DIRECTORY ${RUNTIME_OUTPUT_DIRECTORY}
|
||||
)
|
||||
|
||||
install(TARGETS matterhornDetectorServer
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
)
|
||||
endif()
|
||||
|
||||
if(SLS_USE_TESTS)
|
||||
add_subdirectory(tests)
|
||||
endif()
|
||||
|
||||
|
||||
#target_compile_definitions(matterhornDetectorServer_virtual
|
||||
# PUBLIC VIRTUAL STOP_SERVER #what is this stop server should we really have a generic ServerAPP and pass compile options to create server e.g. MatterHorn?
|
||||
#)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:4bfbe17a6b0efbdcd3da78eafb1ac6c212eb81434f36267640f75fe743dc0aea
|
||||
size 316776
|
||||
@@ -1,113 +0,0 @@
|
||||
#pragma once
|
||||
#include "DetectorServer.h"
|
||||
#include "TCPInterface.h"
|
||||
// #include "communication_funcs.h"
|
||||
#include "fmt/format.h"
|
||||
#include "sls/logger.h"
|
||||
#include "sls/network_utils.h"
|
||||
#include "sls/sls_detector_defs.h"
|
||||
#include "sls/versionAPI.h"
|
||||
#include <array>
|
||||
#include <cstring>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace sls {
|
||||
|
||||
/// @brief Base class for Matterhorn Server, can be used to implement a virtual
|
||||
/// server for testing and actual server
|
||||
template <typename DerivedServer>
|
||||
class BaseMatterhornServer
|
||||
: public DetectorServer<BaseMatterhornServer<DerivedServer>> {
|
||||
|
||||
public:
|
||||
/**
|
||||
* Constructor
|
||||
* Starts up a Matterhorn server.
|
||||
* Assembles a Matterhorn server using TCP and UDP detector interfaces
|
||||
* throws an exception in case of failure
|
||||
* @param port TCP/IP port number
|
||||
*/
|
||||
explicit BaseMatterhornServer(uint16_t port = DEFAULT_TCP_CNTRL_PORTNO)
|
||||
: DetectorServer<BaseMatterhornServer<DerivedServer>>(port) {}
|
||||
|
||||
~BaseMatterhornServer() = default;
|
||||
|
||||
ReturnCode get_version(ServerInterface &socket);
|
||||
|
||||
ReturnCode get_detector_type(ServerInterface &socket);
|
||||
|
||||
ReturnCode initial_checks(ServerInterface &socket);
|
||||
|
||||
ReturnCode get_num_udp_interfaces(ServerInterface &socket) const;
|
||||
|
||||
/**
|
||||
* @brief call function corresponding to the function ID received from the
|
||||
* client and send back the result
|
||||
* @param function_id the function ID received from the client
|
||||
* @param socket the socket to send the result back to the client
|
||||
*/
|
||||
ReturnCode processFunction(const detFuncs function_id,
|
||||
ServerInterface &socket);
|
||||
|
||||
private:
|
||||
static std::string getMatterhornServerVersion();
|
||||
|
||||
static constexpr uint8_t numUDPInterfaces =
|
||||
1; // only one udp per module for now
|
||||
};
|
||||
|
||||
template <typename DerivedServer>
|
||||
ReturnCode
|
||||
BaseMatterhornServer<DerivedServer>::processFunction(const detFuncs function_id,
|
||||
ServerInterface &socket) {
|
||||
|
||||
switch (function_id) {
|
||||
default:
|
||||
throw RuntimeError(
|
||||
fmt::format("Function {} not implemented",
|
||||
getFunctionNameFromEnum((enum detFuncs)function_id)));
|
||||
}
|
||||
}
|
||||
|
||||
template <typename DerivedServer>
|
||||
ReturnCode BaseMatterhornServer<DerivedServer>::get_num_udp_interfaces(
|
||||
ServerInterface &socket) const {
|
||||
return static_cast<ReturnCode>(
|
||||
socket.sendResult(static_cast<int>(numUDPInterfaces)));
|
||||
}
|
||||
|
||||
template <typename DerivedServer>
|
||||
ReturnCode
|
||||
BaseMatterhornServer<DerivedServer>::get_version(ServerInterface &socket) {
|
||||
|
||||
auto version = getMatterhornServerVersion();
|
||||
char version_cstr[MAX_STR_LENGTH]{};
|
||||
strncpy(version_cstr, version.c_str(), version.size());
|
||||
LOG(TLogLevel::logDEBUG) << "Matterhorn Server Version: " << version;
|
||||
return static_cast<ReturnCode>(socket.sendResult(
|
||||
version_cstr)); // TODO: check what would be possible return codes!!!
|
||||
}
|
||||
|
||||
template <typename DerivedServer>
|
||||
ReturnCode BaseMatterhornServer<DerivedServer>::get_detector_type(
|
||||
ServerInterface &socket) {
|
||||
int detectortype = slsDetectorDefs::detectorType::MATTERHORN;
|
||||
return static_cast<ReturnCode>(socket.sendResult(detectortype));
|
||||
}
|
||||
|
||||
template <typename DerivedServer>
|
||||
std::string BaseMatterhornServer<DerivedServer>::getMatterhornServerVersion() {
|
||||
return APIMATTERHORN;
|
||||
}
|
||||
|
||||
template <typename DerivedServer>
|
||||
ReturnCode
|
||||
BaseMatterhornServer<DerivedServer>::initial_checks(ServerInterface &socket) {
|
||||
|
||||
return static_cast<DerivedServer *>(this)->initial_checks(socket);
|
||||
}
|
||||
|
||||
} // namespace sls
|
||||
@@ -1,27 +0,0 @@
|
||||
#pragma once
|
||||
#include "BaseMatterhornServer.h"
|
||||
#include "TCPInterface.h"
|
||||
#include "sls/sls_detector_defs.h"
|
||||
#include <array>
|
||||
#include <memory>
|
||||
|
||||
namespace sls {
|
||||
|
||||
class MatterhornServer : public BaseMatterhornServer<MatterhornServer> {
|
||||
|
||||
public:
|
||||
/**
|
||||
* Constructor
|
||||
* Starts up a Matterhorn server.
|
||||
* Assembles a Matterhorn server using TCP and UDP detector interfaces
|
||||
* throws an exception in case of failure
|
||||
* @param port TCP/IP port number
|
||||
*/
|
||||
explicit MatterhornServer(uint16_t port = DEFAULT_TCP_CNTRL_PORTNO);
|
||||
|
||||
~MatterhornServer() = default;
|
||||
|
||||
ReturnCode initial_checks(ServerInterface &socket);
|
||||
};
|
||||
|
||||
} // namespace sls
|
||||
@@ -1,29 +0,0 @@
|
||||
#include <cstdint>
|
||||
#include <string_view>
|
||||
|
||||
namespace sls {
|
||||
|
||||
enum class IPCore : uint32_t; // forward declaration of IPCore enum class
|
||||
|
||||
struct Register {
|
||||
/// @brief IP core address space
|
||||
const IPCore ip_core{}; // TODO replace by enum type
|
||||
|
||||
/// @brief Offset of the register in bytes from the base address of the IP
|
||||
/// core
|
||||
const uint32_t offset_in_bytes{};
|
||||
};
|
||||
|
||||
struct RegisterField {
|
||||
/// @brief Register to which the field belongs
|
||||
const Register register_{};
|
||||
|
||||
/// @brief Bit position of the least significant bit of the field in the
|
||||
/// register
|
||||
const uint32_t bit_position{};
|
||||
|
||||
/// @brief Bitmask for the field
|
||||
const uint32_t bitmask{};
|
||||
};
|
||||
|
||||
} // namespace sls
|
||||
@@ -1,24 +0,0 @@
|
||||
|
||||
#include "BaseMatterhornServer.h"
|
||||
|
||||
namespace sls {
|
||||
|
||||
class VirtualMatterhornServer
|
||||
: public BaseMatterhornServer<VirtualMatterhornServer> {
|
||||
|
||||
public:
|
||||
/**
|
||||
* Constructor
|
||||
* Starts up a virtual Matterhorn server.
|
||||
* Assembles a virtual Matterhorn server using TCP and UDP detector
|
||||
* interfaces throws an exception in case of failure
|
||||
* @param port TCP/IP port number
|
||||
*/
|
||||
explicit VirtualMatterhornServer(uint16_t port = DEFAULT_TCP_CNTRL_PORTNO);
|
||||
|
||||
~VirtualMatterhornServer() = default;
|
||||
|
||||
ReturnCode initial_checks(ServerInterface &socket);
|
||||
};
|
||||
|
||||
} // namespace sls
|
||||
@@ -0,0 +1,116 @@
|
||||
#pragma once
|
||||
#include "DetectorServer.hpp"
|
||||
#include "TCPInterface.hpp"
|
||||
#include "fmt/format.h"
|
||||
#include "helpers/type_traits.hpp"
|
||||
#include "sls/logger.h"
|
||||
#include "sls/network_utils.h"
|
||||
#include "sls/sls_detector_defs.h"
|
||||
#include <array>
|
||||
#include <cstring>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace sls {
|
||||
|
||||
/// @brief Base class for Matterhorn Server, can be used to implement a virtual
|
||||
/// server for testing and actual server
|
||||
template <typename DerivedServer>
|
||||
class BaseMatterhornServer
|
||||
: public DetectorServer<BaseMatterhornServer<DerivedServer>> {
|
||||
|
||||
public:
|
||||
/**
|
||||
* Constructor
|
||||
* Starts up a Matterhorn server.
|
||||
* Assembles a Matterhorn server using TCP and UDP detector interfaces
|
||||
* throws an exception in case of failure
|
||||
* @param port TCP/IP port number
|
||||
*/
|
||||
explicit BaseMatterhornServer(
|
||||
std::unique_ptr<
|
||||
DetectorServerImpl<is_stop_server<DerivedServer>::value>>
|
||||
impl,
|
||||
uint16_t port = DEFAULT_TCP_CNTRL_PORTNO)
|
||||
: DetectorServer<BaseMatterhornServer<DerivedServer>>(std::move(impl),
|
||||
port) {}
|
||||
|
||||
~BaseMatterhornServer() = default;
|
||||
|
||||
ProcessedResult set_counter_mask(ServerInterface &socket);
|
||||
|
||||
ProcessedResult get_counter_mask(ServerInterface &socket) const;
|
||||
|
||||
/**
|
||||
* @brief call function corresponding to the function ID received from the
|
||||
* client and send back the result
|
||||
* @param function_id the function ID received from the client
|
||||
* @param socket the socket to send the result back to the client
|
||||
*/
|
||||
ProcessedResult processFunction(const detFuncs function_id,
|
||||
ServerInterface &socket);
|
||||
|
||||
private:
|
||||
DerivedServer *getDerived() { return static_cast<DerivedServer *>(this); }
|
||||
|
||||
const DerivedServer *getDerived() const {
|
||||
return static_cast<const DerivedServer *>(this);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename DerivedServer>
|
||||
ProcessedResult
|
||||
BaseMatterhornServer<DerivedServer>::processFunction(const detFuncs function_id,
|
||||
ServerInterface &socket) {
|
||||
|
||||
switch (function_id) {
|
||||
case detFuncs::F_SET_COUNTER_MASK:
|
||||
return set_counter_mask(socket);
|
||||
case detFuncs::F_GET_COUNTER_MASK:
|
||||
return get_counter_mask(socket);
|
||||
default:
|
||||
throw RuntimeError(
|
||||
fmt::format("Function {} not implemented",
|
||||
getFunctionNameFromEnum((enum detFuncs)function_id)));
|
||||
}
|
||||
}
|
||||
|
||||
template <typename DerivedServer>
|
||||
ProcessedResult
|
||||
BaseMatterhornServer<DerivedServer>::set_counter_mask(ServerInterface &socket) {
|
||||
|
||||
uint32_t counter_mask{};
|
||||
try {
|
||||
(void)socket.Receive(counter_mask);
|
||||
} catch (const SocketError &e) {
|
||||
LOG(logERROR) << "Failed to receive counter mask: " << e.what();
|
||||
return_fail("Failed to receive counter mask: " + std::string(e.what()));
|
||||
}
|
||||
|
||||
try {
|
||||
this->getImpl()->set_counter_mask(counter_mask);
|
||||
} catch (const std::exception &e) {
|
||||
return_fail("Failed to set counter mask: " + std::string(e.what()));
|
||||
}
|
||||
|
||||
return send_ok(socket);
|
||||
}
|
||||
|
||||
template <typename DerivedServer>
|
||||
ProcessedResult BaseMatterhornServer<DerivedServer>::get_counter_mask(
|
||||
ServerInterface &socket) const {
|
||||
|
||||
uint32_t counter_mask{};
|
||||
|
||||
try {
|
||||
counter_mask = this->getImpl()->get_counter_mask();
|
||||
} catch (const std::exception &e) {
|
||||
return_fail("Failed to get counter mask: " + std::string(e.what()));
|
||||
}
|
||||
|
||||
return send_result(socket, counter_mask);
|
||||
}
|
||||
|
||||
} // namespace sls
|
||||
@@ -0,0 +1,358 @@
|
||||
#pragma once
|
||||
#include "ArmBusCommunication.hpp"
|
||||
#include "DetectorServerImpl.hpp"
|
||||
#include "MemoryModel.hpp"
|
||||
#include "communication/SPICommunication.hpp"
|
||||
#include "defs/MatterhornDefs.hpp"
|
||||
#include "defs/RegisterDefs.hpp"
|
||||
#include "helpers/type_traits.hpp"
|
||||
#include "sls/versionAPI.h"
|
||||
#include "utils/HelperFunctions.hpp"
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
namespace sls {
|
||||
|
||||
template <bool isStopServer>
|
||||
class VirtualMatterhornServerImpl; // forward declare
|
||||
|
||||
template <typename DerivedMatterhornServerImpl>
|
||||
class BaseMatterhornServerImpl
|
||||
: public DetectorServerImpl<
|
||||
is_stop_server<DerivedMatterhornServerImpl>::value> {
|
||||
public:
|
||||
BaseMatterhornServerImpl();
|
||||
~BaseMatterhornServerImpl() = default;
|
||||
|
||||
// TODO: probably virtaul server specific details, can be moved to derived
|
||||
// class
|
||||
/// @brief initial setup of detector
|
||||
void setupDetector();
|
||||
|
||||
/// @brief get matterhorn server version
|
||||
std::string get_server_version() const;
|
||||
|
||||
static uint8_t get_detector_type();
|
||||
|
||||
static uint8_t get_num_udp_interfaces();
|
||||
|
||||
uint64_t get_num_frames() const;
|
||||
void set_num_frames(const uint64_t num_frames);
|
||||
|
||||
uint32_t get_num_triggers() const;
|
||||
void set_num_triggers(const uint32_t num_triggers);
|
||||
|
||||
uint32_t get_counter_mask() const;
|
||||
void set_counter_mask(const uint32_t counter_mask);
|
||||
|
||||
void set_module_position(const size_t module_row, const size_t module_col,
|
||||
const size_t module_index);
|
||||
|
||||
slsDetectorDefs::rxParameters get_receiver_parameters() const;
|
||||
|
||||
protected:
|
||||
using MemoryModel = std::conditional_t<
|
||||
std::is_same_v<DerivedMatterhornServerImpl,
|
||||
VirtualMatterhornServerImpl<
|
||||
is_stop_server<DerivedMatterhornServerImpl>::value>>,
|
||||
VirtualMemoryModel<uint32_t>,
|
||||
HardwareMemoryModel>; // 32 bit registers
|
||||
|
||||
// TODO: for now in MatterhornServer and not generic Server but can be
|
||||
// templated on different IPCore types for each detector
|
||||
BusCommunication<MatterhornDefs::MatterHornIPCores, MemoryModel>
|
||||
busCommunication{};
|
||||
|
||||
using SPICommunicationClass = std::conditional_t<
|
||||
std::is_same_v<DerivedMatterhornServerImpl,
|
||||
VirtualMatterhornServerImpl<
|
||||
is_stop_server<DerivedMatterhornServerImpl>::value>>,
|
||||
VirtualSPICommunication<MatterhornDefs::MatterhornSPIRegisters>,
|
||||
HardwareSPICommunication>;
|
||||
|
||||
SPICommunicationClass spiCommunication{};
|
||||
|
||||
private:
|
||||
static constexpr uint8_t numUDPInterfaces =
|
||||
1; // only one udp per module for now
|
||||
};
|
||||
|
||||
template <typename DerivedMatterhornServerImpl>
|
||||
BaseMatterhornServerImpl<
|
||||
DerivedMatterhornServerImpl>::BaseMatterhornServerImpl() {
|
||||
|
||||
// map the IP core base addresses to memory
|
||||
busCommunication.mapToMemory(); // TODO: should this happen in constructor?
|
||||
|
||||
// TODO: need to check if chip is attached
|
||||
spiCommunication.open_spi(); // TODO: should this happen in constructor?
|
||||
}
|
||||
|
||||
template <typename DerivedMatterhornServerImpl>
|
||||
void BaseMatterhornServerImpl<DerivedMatterhornServerImpl>::setupDetector() {
|
||||
// TODO: extend
|
||||
try {
|
||||
// stop server does not talk to the board
|
||||
if constexpr (!this->stop_server) {
|
||||
set_num_frames(1);
|
||||
set_num_triggers(1);
|
||||
set_counter_mask(0xF); // enable counter all counters by default
|
||||
}
|
||||
} catch (const std::exception &e) {
|
||||
LOG(logERROR) << "Failed to setup detector: " << e.what();
|
||||
this->detectorSetupStatus.error_message = std::string(e.what());
|
||||
this->detectorSetupStatus.setup_status =
|
||||
detector_setup_status::SETUP_STATUS::FAILED_SETUP;
|
||||
}
|
||||
|
||||
this->detectorSetupStatus.setup_status =
|
||||
detector_setup_status::SETUP_STATUS::SUCCESSFUL_SETUP;
|
||||
}
|
||||
|
||||
template <typename DerivedMatterhornServerImpl>
|
||||
std::string
|
||||
BaseMatterhornServerImpl<DerivedMatterhornServerImpl>::get_server_version()
|
||||
const {
|
||||
|
||||
return APIMATTERHORN;
|
||||
}
|
||||
|
||||
template <typename DerivedMatterhornServerImpl>
|
||||
uint8_t BaseMatterhornServerImpl<
|
||||
DerivedMatterhornServerImpl>::get_num_udp_interfaces() {
|
||||
return numUDPInterfaces;
|
||||
}
|
||||
|
||||
template <typename DerivedMatterhornServerImpl>
|
||||
uint8_t
|
||||
BaseMatterhornServerImpl<DerivedMatterhornServerImpl>::get_detector_type() {
|
||||
return slsDetectorDefs::detectorType::MATTERHORN;
|
||||
}
|
||||
|
||||
template <typename DerivedMatterhornServerImpl>
|
||||
uint64_t
|
||||
BaseMatterhornServerImpl<DerivedMatterhornServerImpl>::get_num_frames() const {
|
||||
|
||||
try {
|
||||
uint32_t num_frames =
|
||||
busCommunication.readRegister(Reg::MH_SM_Frames_Reg);
|
||||
return static_cast<uint64_t>(num_frames);
|
||||
} catch (const std::exception &e) {
|
||||
LOG(logERROR) << "Failed to read number of frames from register: "
|
||||
<< e.what();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename DerivedMatterhornServerImpl>
|
||||
void BaseMatterhornServerImpl<DerivedMatterhornServerImpl>::set_num_frames(
|
||||
const uint64_t num_frames) {
|
||||
|
||||
try {
|
||||
busCommunication.writeRegister(Reg::MH_SM_Frames_Reg,
|
||||
static_cast<uint32_t>(num_frames));
|
||||
auto written_num_frames = busCommunication.readRegister(
|
||||
Reg::MH_SM_Frames_Reg); // check if write was successful
|
||||
|
||||
if (num_frames != static_cast<uint64_t>(written_num_frames)) {
|
||||
throw std::runtime_error(
|
||||
fmt::format("Requested {} frames, but set {}", num_frames,
|
||||
static_cast<uint64_t>(written_num_frames)));
|
||||
}
|
||||
} catch (const std::exception &e) {
|
||||
LOG(logERROR) << "Failed to set number of frames: " << e.what();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename DerivedMatterhornServerImpl>
|
||||
void BaseMatterhornServerImpl<DerivedMatterhornServerImpl>::set_num_triggers(
|
||||
const uint32_t num_triggers) {
|
||||
|
||||
try {
|
||||
busCommunication.writeRegister(Reg::MH_SM_Triggers_Reg, num_triggers);
|
||||
auto written_num_triggers = busCommunication.readRegister(
|
||||
Reg::MH_SM_Triggers_Reg); // check if write was successful
|
||||
if (num_triggers != written_num_triggers) {
|
||||
throw std::runtime_error(
|
||||
fmt::format("Requested {} triggers, but set {}", num_triggers,
|
||||
written_num_triggers));
|
||||
}
|
||||
} catch (const std::exception &e) {
|
||||
LOG(logERROR) << "Failed to set number of triggers: " << e.what();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename DerivedMatterhornServerImpl>
|
||||
uint32_t
|
||||
BaseMatterhornServerImpl<DerivedMatterhornServerImpl>::get_num_triggers()
|
||||
const {
|
||||
|
||||
try {
|
||||
uint32_t num_triggers =
|
||||
busCommunication.readRegister(Reg::MH_SM_Triggers_Reg);
|
||||
return num_triggers;
|
||||
} catch (const std::exception &e) {
|
||||
LOG(logERROR) << "Failed to read number of triggers from register: "
|
||||
<< e.what();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename DerivedMatterhornServerImpl>
|
||||
void BaseMatterhornServerImpl<DerivedMatterhornServerImpl>::set_counter_mask(
|
||||
const uint32_t counter_mask) {
|
||||
|
||||
// counter mask update to num consecutive counters and starting_counter
|
||||
uint32_t spi_counter_mask{};
|
||||
try {
|
||||
spi_counter_mask = convertCounterMaskToSPICounterMask(counter_mask);
|
||||
} catch (const std::invalid_argument &e) {
|
||||
LOG(logERROR) << "Failed to convert counter mask to SPI counter mask: "
|
||||
<< e.what();
|
||||
|
||||
throw std::invalid_argument(
|
||||
"Failed to convert counter mask to SPI counter mask: " +
|
||||
std::string(e.what()));
|
||||
}
|
||||
|
||||
try {
|
||||
auto reg_value = spiCommunication.SPIread(
|
||||
SPIRegisters::NUM_COUNTERS.register_,
|
||||
0); // TODO: how to handle different chip ids -> e.g. broadcast do
|
||||
// we want it to be configurable for different chip ids? -
|
||||
// Command overload for some of the SPI registers
|
||||
|
||||
setSPIRegisterField(reg_value, SPIRegisters::NUM_COUNTERS,
|
||||
spi_counter_mask);
|
||||
|
||||
spiCommunication.SPIwrite(SPIRegisters::NUM_COUNTERS.register_, 0,
|
||||
reg_value);
|
||||
} catch (const std::exception &e) {
|
||||
throw RuntimeError("Failed to set counter mask: " +
|
||||
std::string(e.what()));
|
||||
}
|
||||
}
|
||||
|
||||
template <typename DerivedMatterhornServerImpl>
|
||||
uint32_t
|
||||
BaseMatterhornServerImpl<DerivedMatterhornServerImpl>::get_counter_mask()
|
||||
const {
|
||||
|
||||
std::vector<std::byte> reg_value{};
|
||||
try {
|
||||
reg_value = spiCommunication.SPIread(
|
||||
SPIRegisters::NUM_COUNTERS.register_,
|
||||
0); // TODO: how to handle different chip ids -
|
||||
} catch (const std::exception &e) {
|
||||
throw sls::RuntimeError(
|
||||
"Failed to read counter mask from SPI register: " +
|
||||
std::string(e.what()));
|
||||
}
|
||||
|
||||
// stores num_counters and starting_counter 0b0000 -> counter 0 enabled,
|
||||
// 0b0001 -> counter 1 enabled, 0b0010
|
||||
uint32_t spi_counter_mask =
|
||||
getSPIRegisterField(reg_value, SPIRegisters::NUM_COUNTERS);
|
||||
|
||||
uint32_t actual_counter_mask =
|
||||
convertSPICounterMaskToCounterMask(spi_counter_mask);
|
||||
|
||||
return actual_counter_mask;
|
||||
}
|
||||
|
||||
template <typename DerivedMatterhornServerImpl>
|
||||
void BaseMatterhornServerImpl<DerivedMatterhornServerImpl>::set_module_position(
|
||||
const size_t module_row, const size_t module_col,
|
||||
const size_t module_index) {
|
||||
|
||||
// write to register
|
||||
uint32_t register_value_LSB{};
|
||||
uint32_t register_value_MSB{};
|
||||
|
||||
try {
|
||||
register_value_LSB =
|
||||
busCommunication.readRegister(Reg::Frame_HDR_ModCoord_LSB_Reg);
|
||||
register_value_MSB =
|
||||
busCommunication.readRegister(Reg::Frame_HDR_ModCoord_MSB_Reg);
|
||||
} catch (const std::exception &e) {
|
||||
LOG(logERROR) << "Failed to read module position register: "
|
||||
<< e.what();
|
||||
throw;
|
||||
}
|
||||
|
||||
try {
|
||||
setRegisterField(register_value_LSB, Reg::ModuleRow, module_row);
|
||||
setRegisterField(register_value_LSB, Reg::ModuleCol, module_col);
|
||||
setRegisterField(register_value_MSB, Reg::ModuleCoordz, 0);
|
||||
setRegisterField(register_value_MSB, Reg::ModuleIndex, module_index);
|
||||
} catch (const std::exception &e) {
|
||||
LOG(logERROR) << "Failed to set module position register fields: "
|
||||
<< e.what();
|
||||
throw;
|
||||
}
|
||||
|
||||
try {
|
||||
busCommunication.writeRegister(Reg::Frame_HDR_ModCoord_LSB_Reg,
|
||||
register_value_LSB);
|
||||
|
||||
auto written_register_value_LSB = busCommunication.readRegister(
|
||||
Reg::Frame_HDR_ModCoord_LSB_Reg); // check if write was successful
|
||||
|
||||
busCommunication.writeRegister(Reg::Frame_HDR_ModCoord_MSB_Reg,
|
||||
register_value_MSB);
|
||||
|
||||
auto written_register_value_MSB = busCommunication.readRegister(
|
||||
Reg::Frame_HDR_ModCoord_MSB_Reg); // check if write was successful
|
||||
|
||||
if (register_value_LSB != written_register_value_LSB ||
|
||||
register_value_MSB != written_register_value_MSB) {
|
||||
throw std::runtime_error(
|
||||
fmt::format("LSB: requested {}, but set {}. "
|
||||
"MSB: requested {}, but set {}",
|
||||
register_value_LSB, written_register_value_LSB,
|
||||
register_value_MSB, written_register_value_MSB));
|
||||
}
|
||||
} catch (const std::exception &e) {
|
||||
LOG(logERROR) << "Failed to write module position register: "
|
||||
<< e.what();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename DerivedMatterhornServerImpl>
|
||||
slsDetectorDefs::rxParameters
|
||||
BaseMatterhornServerImpl<DerivedMatterhornServerImpl>::get_receiver_parameters()
|
||||
const {
|
||||
|
||||
slsDetectorDefs::rxParameters rx_params{};
|
||||
|
||||
rx_params.udpInterfaces = numUDPInterfaces;
|
||||
|
||||
rx_params.udp_dstip = this->udpDetails[0].dstip;
|
||||
|
||||
rx_params.udp_dstport = this->udpDetails[0].dstport;
|
||||
|
||||
rx_params.udp_dstmac = this->udpDetails[0].dstmac;
|
||||
|
||||
rx_params.frames = get_num_frames();
|
||||
|
||||
rx_params.triggers = get_num_triggers();
|
||||
|
||||
// TODO: extend
|
||||
|
||||
// rx_params.expTimeNs = 0;
|
||||
|
||||
// rx_params.periodNs = 0;
|
||||
|
||||
// rx_params.dynamicRange = 0;
|
||||
|
||||
// rx_params.timMode = AUTO_TIMING;
|
||||
|
||||
// rx_params.counterMask = 0;
|
||||
|
||||
return rx_params;
|
||||
}
|
||||
|
||||
} // namespace sls
|
||||
@@ -1,11 +1,13 @@
|
||||
#include "CommandLineOptions.h"
|
||||
#include "VirtualMatterhornServer.h"
|
||||
#include "CommandLineOptions.hpp"
|
||||
#include MATTERHORN_SERVER_HEADER
|
||||
#include "helpers/Helpers.hpp"
|
||||
#include "sls/logger.h"
|
||||
#include "sls/sls_detector_exceptions.h"
|
||||
#include "sls/versionAPI.h"
|
||||
#include <semaphore.h>
|
||||
|
||||
#include <csignal>
|
||||
#include <fmt/format.h>
|
||||
#include <signal.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
@@ -62,6 +64,9 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
LOG(TLogLevel::logINFOMAGENTA) << cli.printOptions();
|
||||
|
||||
// free shared memory from previous run (not removed if detector crashed)
|
||||
freeSharedMemory();
|
||||
|
||||
// Register Ctrl+C handler
|
||||
std::signal(SIGINT, sigInterruptHandler);
|
||||
|
||||
@@ -75,11 +80,12 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
LOG(TLogLevel::logINFOBLUE) << "Stop Server [" << opts.port + 1 << "]";
|
||||
try {
|
||||
VirtualMatterhornServer stopServer(opts.port + 1);
|
||||
MATTERHORN_SERVER_CLASS<true> stopServer(opts.port + 1);
|
||||
while (!interruption) {
|
||||
pause(); // wait for signal to exit
|
||||
}
|
||||
} catch (...) {
|
||||
LOG(logERROR) << "Some Error occured in Stop Server, exiting";
|
||||
kill(getppid(), SIGINT); // tell parent to exit // TODO: should then
|
||||
// also return EXIT_FAILURE
|
||||
}
|
||||
@@ -93,13 +99,14 @@ int main(int argc, char *argv[]) {
|
||||
LOG(TLogLevel::logINFOBLUE) << "Control Server [" << opts.port << "]\n";
|
||||
|
||||
try {
|
||||
VirtualMatterhornServer server(
|
||||
MATTERHORN_SERVER_CLASS server(
|
||||
opts.port); // TODO use virtual if compiled with virtual
|
||||
// simulators on
|
||||
while (!interruption) {
|
||||
pause(); // wait for signal to exit
|
||||
}
|
||||
} catch (...) {
|
||||
LOG(logERROR) << "Some Error occured in Control Server, exiting";
|
||||
LOG(sls::logINFOBLUE)
|
||||
<< "Exiting Control Server [ Tid: " << gettid() << " ]";
|
||||
LOG(sls::logINFO) << "Exiting Detector Server";
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
#include "MatterhornServer.h"
|
||||
|
||||
namespace sls {
|
||||
|
||||
MatterhornServer::MatterhornServer(uint16_t port)
|
||||
: BaseMatterhornServer<MatterhornServer>(port) {
|
||||
|
||||
// TODO: when do i set the udp mac and ip ?
|
||||
|
||||
// should maybe be part of the constructor?
|
||||
tcpInterface->startTCPServer();
|
||||
|
||||
// need a function to setup detector - e.g. set all registers etc.
|
||||
}
|
||||
|
||||
ReturnCode MatterhornServer::initial_checks(ServerInterface &socket) {
|
||||
|
||||
// TODO: add more checks here, for now just return true to be able to test
|
||||
// the should check firmware -client compatibility
|
||||
bool initial_checks_passed = true;
|
||||
return static_cast<ReturnCode>(socket.sendResult(initial_checks_passed));
|
||||
}
|
||||
|
||||
} // namespace sls
|
||||
@@ -0,0 +1,41 @@
|
||||
#pragma once
|
||||
#include "BaseMatterhornServer.hpp"
|
||||
#include "MatterhornServerImpl.hpp"
|
||||
#include "TCPInterface.hpp"
|
||||
#include "sls/sls_detector_defs.h"
|
||||
#include <array>
|
||||
#include <memory>
|
||||
|
||||
namespace sls {
|
||||
|
||||
template <bool isStopServer = false>
|
||||
class MatterhornServer
|
||||
: public BaseMatterhornServer<MatterhornServer<isStopServer>> {
|
||||
|
||||
public:
|
||||
/**
|
||||
* Constructor
|
||||
* Starts up a Matterhorn server.
|
||||
* Assembles a Matterhorn server using TCP and UDP detector interfaces
|
||||
* throws an exception in case of failure
|
||||
* @param port TCP/IP port number
|
||||
*/
|
||||
explicit MatterhornServer(uint16_t port = DEFAULT_TCP_CNTRL_PORTNO);
|
||||
|
||||
~MatterhornServer() = default;
|
||||
};
|
||||
|
||||
template <bool isStopServer>
|
||||
MatterhornServer<isStopServer>::MatterhornServer(uint16_t port)
|
||||
: BaseMatterhornServer<MatterhornServer<isStopServer>>(
|
||||
std::make_unique<MatterhornServerImpl<isStopServer>>(), port) {
|
||||
|
||||
// should maybe be part of the constructor?
|
||||
this->tcpInterface->startTCPServer();
|
||||
|
||||
// TODO: no init_server function for now is it neccessary to set the init
|
||||
// flag
|
||||
this->getImpl()->setupDetector();
|
||||
}
|
||||
|
||||
} // namespace sls
|
||||
@@ -0,0 +1,70 @@
|
||||
#pragma once
|
||||
#include "BaseMatterhornServerImpl.hpp"
|
||||
|
||||
namespace sls {
|
||||
|
||||
template <bool isStopServer = false>
|
||||
class MatterhornServerImpl
|
||||
: public BaseMatterhornServerImpl<MatterhornServerImpl<isStopServer>> {
|
||||
|
||||
public:
|
||||
MatterhornServerImpl() = default;
|
||||
~MatterhornServerImpl() = default;
|
||||
|
||||
slsDetectorDefs::runStatus get_run_status() const; // TODO: impement
|
||||
|
||||
void set_module_position_and_update_srcudpmac(
|
||||
const std::array<int, 2> &position_info);
|
||||
|
||||
void set_source_udp_mac([[maybe_unused]] const uint64_t src_mac);
|
||||
};
|
||||
|
||||
template <bool isStopServer>
|
||||
slsDetectorDefs::runStatus
|
||||
MatterhornServerImpl<isStopServer>::get_run_status() const {
|
||||
|
||||
// TODO: will also have a scanStatus - scanStatus should be in base
|
||||
// implementation and shared between virtual and actual detector - split
|
||||
// this function into two.
|
||||
return slsDetectorDefs::runStatus::IDLE; // TODO: implement
|
||||
}
|
||||
|
||||
template <bool isStopServer>
|
||||
void MatterhornServerImpl<isStopServer>::
|
||||
set_module_position_and_update_srcudpmac(
|
||||
const std::array<int, 2> &position_info) {
|
||||
|
||||
// position_info = [num_modules_in_y, module_index]
|
||||
|
||||
const size_t module_row = position_info[1] % position_info[0];
|
||||
if (position_info[0] <= 0) {
|
||||
throw RuntimeError("Number of modules in y direction cannot be 0.");
|
||||
}
|
||||
const size_t module_col = position_info[1] / position_info[0];
|
||||
|
||||
try {
|
||||
this->set_module_position(module_row, module_col, position_info[1]);
|
||||
} catch (const std::exception &e) {
|
||||
throw RuntimeError("Failed to set module position: " +
|
||||
std::string(e.what()));
|
||||
}
|
||||
|
||||
// TODO: update
|
||||
if (this->udpDetails[0].srcmac ==
|
||||
0) { // only configure if source mac address is not set already
|
||||
uint64_t newSrcMac =
|
||||
0x000000000000; // TODO: vendor address will be on SOM memory/
|
||||
// different for 10G/100G
|
||||
this->updateSrcMacAddress(newSrcMac);
|
||||
}
|
||||
}
|
||||
|
||||
template <bool isStopServer>
|
||||
void MatterhornServerImpl<isStopServer>::set_source_udp_mac(
|
||||
const uint64_t src_mac) {
|
||||
|
||||
throw RuntimeError(
|
||||
"Cannot overwrite vendor specific source UDP MAC address.");
|
||||
}
|
||||
|
||||
} // end namespace sls
|
||||
@@ -1,24 +0,0 @@
|
||||
#include "VirtualMatterhornServer.h"
|
||||
|
||||
namespace sls {
|
||||
|
||||
VirtualMatterhornServer::VirtualMatterhornServer(uint16_t port)
|
||||
: BaseMatterhornServer<VirtualMatterhornServer>(port) {
|
||||
|
||||
udpDetails[0].srcip = LOCALHOSTIP_INT;
|
||||
|
||||
// should maybe be part of the constructor?
|
||||
tcpInterface->startTCPServer();
|
||||
|
||||
// need a function to setup detector - e.g. set all registers etc.
|
||||
}
|
||||
|
||||
ReturnCode VirtualMatterhornServer::initial_checks(ServerInterface &socket) {
|
||||
|
||||
// TODO: add more checks here, for now just return true to be able to test
|
||||
// the should check firmware -client compatibility
|
||||
bool initial_checks_passed = true;
|
||||
return static_cast<ReturnCode>(socket.sendResult(initial_checks_passed));
|
||||
}
|
||||
|
||||
} // namespace sls
|
||||
@@ -0,0 +1,39 @@
|
||||
|
||||
#include "BaseMatterhornServer.hpp"
|
||||
#include "VirtualMatterhornServerImpl.hpp"
|
||||
|
||||
namespace sls {
|
||||
|
||||
template <bool isStopServer = false>
|
||||
class VirtualMatterhornServer
|
||||
: public BaseMatterhornServer<VirtualMatterhornServer<isStopServer>> {
|
||||
|
||||
public:
|
||||
/**
|
||||
* Constructor
|
||||
* Starts up a virtual Matterhorn server.
|
||||
* Assembles a virtual Matterhorn server using TCP and UDP detector
|
||||
* interfaces throws an exception in case of failure
|
||||
* @param port TCP/IP port number
|
||||
*/
|
||||
explicit VirtualMatterhornServer(uint16_t port = DEFAULT_TCP_CNTRL_PORTNO);
|
||||
|
||||
~VirtualMatterhornServer() = default;
|
||||
};
|
||||
|
||||
template <bool isStopServer>
|
||||
VirtualMatterhornServer<isStopServer>::VirtualMatterhornServer(uint16_t port)
|
||||
: BaseMatterhornServer<VirtualMatterhornServer<isStopServer>>(
|
||||
std::make_unique<VirtualMatterhornServerImpl<isStopServer>>(), port) {
|
||||
|
||||
LOG(logDEBUG) << "Initializing virtual Matterhorn server on port " << port;
|
||||
|
||||
// should maybe be part of the constructor?
|
||||
this->tcpInterface->startTCPServer();
|
||||
|
||||
// TODO: no init_server function for now is it neccessary to set the init
|
||||
// flag
|
||||
this->getImpl()->setupDetector();
|
||||
}
|
||||
|
||||
} // namespace sls
|
||||
@@ -0,0 +1,87 @@
|
||||
#pragma once
|
||||
#include "BaseMatterhornServerImpl.hpp"
|
||||
#include "sls/ToString.h"
|
||||
|
||||
namespace sls {
|
||||
|
||||
template <bool isStopServer = false>
|
||||
class VirtualMatterhornServerImpl
|
||||
: public BaseMatterhornServerImpl<
|
||||
VirtualMatterhornServerImpl<isStopServer>> {
|
||||
|
||||
public:
|
||||
VirtualMatterhornServerImpl();
|
||||
~VirtualMatterhornServerImpl() = default;
|
||||
|
||||
slsDetectorDefs::runStatus get_run_status() const;
|
||||
|
||||
void set_module_position_and_update_srcudpmac(
|
||||
const std::array<int, 2> &position_info);
|
||||
|
||||
void set_source_udp_mac(const uint64_t newsrcudpMac);
|
||||
};
|
||||
|
||||
template <bool isStopServer>
|
||||
VirtualMatterhornServerImpl<isStopServer>::VirtualMatterhornServerImpl() {
|
||||
this->set_source_udp_ip(LOCALHOSTIP_INT);
|
||||
}
|
||||
|
||||
template <bool isStopServer>
|
||||
slsDetectorDefs::runStatus
|
||||
VirtualMatterhornServerImpl<isStopServer>::get_run_status() const {
|
||||
|
||||
slsDetectorDefs::runStatus scanstatus{};
|
||||
slsDetectorDefs::runStatus status{};
|
||||
|
||||
scanstatus = this->shm()->scanStatus;
|
||||
status = this->shm()->status;
|
||||
|
||||
// TODO: why only error and running? what about other states?
|
||||
if (scanstatus == slsDetectorDefs::runStatus::ERROR ||
|
||||
scanstatus == slsDetectorDefs::runStatus::RUNNING) {
|
||||
LOG(logINFO) << fmt::format("Scan status: {}\n", ToString(scanstatus));
|
||||
return scanstatus;
|
||||
}
|
||||
|
||||
LOG(logINFO) << fmt::format("Status: {}\n", ToString(status));
|
||||
return status;
|
||||
}
|
||||
|
||||
template <bool isStopServer>
|
||||
void VirtualMatterhornServerImpl<isStopServer>::
|
||||
set_module_position_and_update_srcudpmac(
|
||||
const std::array<int, 2> &position_info) {
|
||||
|
||||
const size_t module_row = position_info[1] % position_info[0];
|
||||
const size_t module_col = position_info[1] / position_info[0];
|
||||
|
||||
try {
|
||||
this->set_module_position(module_row, module_col, position_info[1]);
|
||||
} catch (const std::exception &e) {
|
||||
throw RuntimeError("Failed to set module position: " +
|
||||
std::string(e.what()));
|
||||
}
|
||||
|
||||
// configure mac address based on module position
|
||||
if (this->udpDetails[0].srcmac ==
|
||||
0) { // only configure if source mac address is not set already
|
||||
uint64_t newSrcMac =
|
||||
generateMacAddressfromModulePosition(module_row, module_col);
|
||||
|
||||
this->updateSrcMacAddress(newSrcMac);
|
||||
}
|
||||
}
|
||||
|
||||
template <bool isStopServer>
|
||||
void VirtualMatterhornServerImpl<isStopServer>::set_source_udp_mac(
|
||||
const uint64_t newsrcudpMac) {
|
||||
|
||||
if (!isValidMac(newsrcudpMac)) {
|
||||
throw RuntimeError("Invalid source MAC address: unicast bit or local "
|
||||
"administration bit is not set");
|
||||
}
|
||||
|
||||
this->updateSrcMacAddress(newsrcudpMac);
|
||||
}
|
||||
|
||||
} // namespace sls
|
||||
@@ -0,0 +1,120 @@
|
||||
#include "SPICommunication.hpp"
|
||||
#include <algorithm>
|
||||
#include <fcntl.h>
|
||||
#include <linux/spi/spidev.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
namespace sls {
|
||||
|
||||
void HardwareSPICommunication::open_spi() {
|
||||
|
||||
// TODO device can change
|
||||
spi_filedescriptor = open("/dev/spidev2.0", O_RDWR); // TODO use O_SYNC?
|
||||
|
||||
if (spi_filedescriptor < 0) {
|
||||
throw RuntimeError("Could not open /dev/spidev2.0");
|
||||
}
|
||||
|
||||
LOG(logINFO) << fmt::format("SPI Read: opened spidev2.0 with fd={}",
|
||||
spi_filedescriptor);
|
||||
}
|
||||
|
||||
void HardwareSPICommunication::close_spi() {
|
||||
if (spi_filedescriptor >= 0) {
|
||||
close(spi_filedescriptor);
|
||||
LOG(logINFO) << "SPI Read: closed spidev2.0";
|
||||
spi_filedescriptor = -1;
|
||||
}
|
||||
}
|
||||
|
||||
HardwareSPICommunication::~HardwareSPICommunication() { close_spi(); }
|
||||
|
||||
std::vector<std::byte>
|
||||
HardwareSPICommunication::spi_read(const size_t n_bytes, const uint8_t chip_id,
|
||||
const uint8_t register_id) const {
|
||||
|
||||
// allocate dummy data to shift out the data (first byte is command byte)
|
||||
if (n_bytes == std::numeric_limits<size_t>::max()) {
|
||||
throw RuntimeError("SPI read size overflow");
|
||||
}
|
||||
|
||||
std::vector<std::byte> dummy_data(
|
||||
n_bytes + 1, std::byte{0x00}); // +1 for the command byte
|
||||
|
||||
// First byte of the message is 4 bits chip_id then 4 bits register_id
|
||||
dummy_data[0] =
|
||||
static_cast<std::byte>(((chip_id & 0xF) << 4) | (register_id & 0xF));
|
||||
|
||||
// allocate data buffer to read out data into
|
||||
std::vector<std::byte> read_data_buffer(n_bytes + 1, std::byte{0x00});
|
||||
|
||||
spi_ioc_transfer send_cmd{};
|
||||
send_cmd.len = n_bytes + 1; // +1 for the command byte
|
||||
send_cmd.tx_buf = reinterpret_cast<std::uintptr_t>(dummy_data.data());
|
||||
send_cmd.rx_buf = reinterpret_cast<std::uintptr_t>(read_data_buffer.data());
|
||||
|
||||
// 0 - Normal operation, 1 - CSN remains zero after operation
|
||||
// We use cs_change = 1 to not close the SPI transaction and
|
||||
// allow for shifting the read out data back in to restore the
|
||||
// register
|
||||
send_cmd.cs_change = 1;
|
||||
|
||||
// transfer here
|
||||
if (ioctl(spi_filedescriptor, SPI_IOC_MESSAGE(1), &send_cmd) < 0) {
|
||||
|
||||
throw RuntimeError(
|
||||
fmt::format("SPI write failed with {}:{}", errno, strerror(errno)));
|
||||
}
|
||||
|
||||
// copy data to output buffer
|
||||
std::vector<std::byte> output_data(n_bytes);
|
||||
std::memcpy(output_data.data(), read_data_buffer.data() + 1, n_bytes);
|
||||
|
||||
// copy the read out data back to the dummy data buffer to shift it back in
|
||||
send_cmd.tx_buf = send_cmd.rx_buf;
|
||||
|
||||
send_cmd.cs_change =
|
||||
0; // end the SPI transaction after shifting back in the data
|
||||
|
||||
if (ioctl(spi_filedescriptor, SPI_IOC_MESSAGE(1), &send_cmd) < 0) {
|
||||
throw RuntimeError(
|
||||
fmt::format("SPI write failed with {}:{}", errno, strerror(errno)));
|
||||
}
|
||||
|
||||
return output_data;
|
||||
}
|
||||
|
||||
void HardwareSPICommunication::spi_write(const uint8_t chip_id,
|
||||
const uint8_t register_id,
|
||||
const std::vector<std::byte> &data) {
|
||||
|
||||
const size_t n_bytes = data.size();
|
||||
|
||||
if (n_bytes == std::numeric_limits<size_t>::max()) {
|
||||
throw RuntimeError("SPI read size overflow");
|
||||
}
|
||||
|
||||
// First byte of the message is 4 bits chip_id then 4 bits register_id
|
||||
std::vector<std::byte> write_data(n_bytes + 1); // +1 for the command byte
|
||||
|
||||
write_data[0] =
|
||||
static_cast<std::byte>(((chip_id & 0xF) << 4) | (register_id & 0xF));
|
||||
|
||||
std::memcpy(write_data.data() + 1, data.data(), n_bytes);
|
||||
|
||||
spi_ioc_transfer send_cmd{};
|
||||
send_cmd.len = n_bytes + 1; // +1 for the command byte
|
||||
send_cmd.tx_buf = reinterpret_cast<std::uintptr_t>(write_data.data());
|
||||
|
||||
send_cmd.cs_change =
|
||||
0; // end the SPI transaction after the write (we dont need to shift
|
||||
// back in data here since we are not doing a read)
|
||||
|
||||
if (ioctl(spi_filedescriptor, SPI_IOC_MESSAGE(1), &send_cmd) < 0) {
|
||||
throw RuntimeError(
|
||||
fmt::format("SPI write failed with {}:{}", errno, strerror(errno)));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace sls
|
||||
@@ -0,0 +1,205 @@
|
||||
#include "MemoryModel.hpp"
|
||||
#include "SPIRegisterHelperStructs.hpp"
|
||||
#include "defs/MatterhornDefs.hpp"
|
||||
#include "defs/SPIRegisterDefs.hpp"
|
||||
#include "fmt/format.h"
|
||||
#include "sls/logger.h"
|
||||
#include "sls/sls_detector_exceptions.h"
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
namespace sls {
|
||||
|
||||
/// @brief abstract base class for SPI communication
|
||||
template <typename DerivedSPIModel> class SPICommunication {
|
||||
|
||||
public:
|
||||
SPICommunication() = default;
|
||||
|
||||
~SPICommunication() = default;
|
||||
|
||||
std::vector<std::byte> SPIread(const SPIRegister &spi_reg,
|
||||
const uint8_t chip_id) const;
|
||||
|
||||
void SPIwrite(const SPIRegister &spi_reg, const uint8_t chip_id,
|
||||
const std::vector<std::byte> &data);
|
||||
|
||||
void open_spi();
|
||||
|
||||
private:
|
||||
DerivedSPIModel *getDerived() {
|
||||
return static_cast<DerivedSPIModel *>(this);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename DerivedSPIModel>
|
||||
void SPICommunication<DerivedSPIModel>::open_spi() {
|
||||
getDerived()->open_spi();
|
||||
}
|
||||
|
||||
template <typename DerivedSPIModel>
|
||||
std::vector<std::byte>
|
||||
SPICommunication<DerivedSPIModel>::SPIread(const SPIRegister &spi_reg,
|
||||
const uint8_t chip_id) const {
|
||||
|
||||
if (chip_id >= MatterhornDefs::NUM_CHIPS_PER_MODULE) {
|
||||
throw RuntimeError(
|
||||
fmt::format("Chip id {} is out of range (0-{})", chip_id,
|
||||
MatterhornDefs::NUM_CHIPS_PER_MODULE - 1));
|
||||
}
|
||||
return static_cast<const DerivedSPIModel *>(this)->spi_read(
|
||||
spi_reg.n_bytes, chip_id, spi_reg.spi_register_id);
|
||||
}
|
||||
|
||||
template <typename DerivedSPIModel>
|
||||
void SPICommunication<DerivedSPIModel>::SPIwrite(
|
||||
const SPIRegister &spi_reg, const uint8_t chip_id,
|
||||
const std::vector<std::byte> &data) {
|
||||
|
||||
if (chip_id >= MatterhornDefs::NUM_CHIPS_PER_MODULE) {
|
||||
throw RuntimeError(
|
||||
fmt::format("Chip id {} is out of range (0-{})", chip_id,
|
||||
MatterhornDefs::NUM_CHIPS_PER_MODULE - 1));
|
||||
}
|
||||
|
||||
if (data.size() != spi_reg.n_bytes) {
|
||||
throw RuntimeError(fmt::format("Data size {} does not match number of "
|
||||
"bytes {} for SPI register {}",
|
||||
data.size(), spi_reg.n_bytes,
|
||||
spi_reg.spi_register_id));
|
||||
}
|
||||
|
||||
getDerived()->spi_write(chip_id, spi_reg.spi_register_id, data);
|
||||
|
||||
getDerived()->spi_write(chip_id,
|
||||
SPIRegisters::SPI_REG_ExtraClocks.spi_register_id,
|
||||
std::vector<std::byte>{std::byte{
|
||||
0x00}}); // extra clock trigger to actually load
|
||||
// the new value into the register
|
||||
}
|
||||
|
||||
/**
|
||||
* Non destructive read from SPI register. Read n_bytes by shifting in
|
||||
* dummy data while keeping csn 0 after the operation. Shift the read out
|
||||
* data back in to restore the register.
|
||||
*/
|
||||
class HardwareSPICommunication
|
||||
: public SPICommunication<HardwareSPICommunication> {
|
||||
|
||||
public:
|
||||
HardwareSPICommunication() = default;
|
||||
|
||||
~HardwareSPICommunication();
|
||||
|
||||
void open_spi();
|
||||
|
||||
void spi_write(const uint8_t chip_id, const uint8_t register_id,
|
||||
const std::vector<std::byte> &data);
|
||||
|
||||
std::vector<std::byte> spi_read(const size_t n_bytes, const uint8_t chip_id,
|
||||
const uint8_t register_id) const;
|
||||
|
||||
private:
|
||||
int spi_filedescriptor = -1;
|
||||
|
||||
void close_spi();
|
||||
};
|
||||
|
||||
// template <SPIRegister... SPIRegisters, uint8_t NUM_CHIPS_PER_MODULE> // non
|
||||
// type template parameters only for c++20
|
||||
template <typename SPIRegisters> // TODO add a type trait to ensure it stores
|
||||
// all fields
|
||||
class VirtualSPICommunication
|
||||
: public SPICommunication<VirtualSPICommunication<SPIRegisters>> {
|
||||
|
||||
public:
|
||||
VirtualSPICommunication() {
|
||||
// TODO should it be in the constructor?
|
||||
/*
|
||||
(virtual_registers.emplace(
|
||||
SPIRegisters.spi_register_id,
|
||||
VirtualMemoryModel<std::byte>{SPIRegisters.spi_register_id,
|
||||
SPIRegisters.n_bytes *
|
||||
NUM_CHIPS_PER_MODULE}),
|
||||
...);
|
||||
*/
|
||||
|
||||
LOG(logDEBUG) << fmt::format(
|
||||
"Initializing virtual SPI communication with {} registers for {} "
|
||||
"chips per module",
|
||||
SPIRegisters::spiregisters.size(),
|
||||
SPIRegisters::NUM_CHIPS_PER_MODULE);
|
||||
|
||||
for (const auto ® : SPIRegisters::spiregisters) {
|
||||
virtual_registers.emplace(
|
||||
reg.spi_register_id,
|
||||
VirtualMemoryModel<std::byte>{
|
||||
reg.spi_register_id,
|
||||
reg.n_bytes * SPIRegisters::NUM_CHIPS_PER_MODULE});
|
||||
}
|
||||
|
||||
LOG(logDEBUG) << fmt::format(
|
||||
"Initialized virtual SPI communication with {} registers for {} "
|
||||
"chips per module",
|
||||
virtual_registers.size(), SPIRegisters::NUM_CHIPS_PER_MODULE);
|
||||
|
||||
for (const auto &[register_id, register_memory] : virtual_registers) {
|
||||
LOG(logDEBUG) << fmt::format(
|
||||
"Virtual SPI register with id {} has virtual", register_id);
|
||||
}
|
||||
}
|
||||
|
||||
~VirtualSPICommunication() = default;
|
||||
|
||||
void open_spi() {
|
||||
|
||||
// resize the virtual register memory to the correct size based on
|
||||
// the defined SPI registers
|
||||
for (auto &[register_id, register_memory] : virtual_registers) {
|
||||
LOG(logDEBUG) << fmt::format("Mapping virtual SPI register with id "
|
||||
"{} to virtual memory",
|
||||
register_id);
|
||||
register_memory.mapToMemory();
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::byte> spi_read(const size_t n_bytes, const uint8_t chip_id,
|
||||
const uint8_t register_id) const {
|
||||
|
||||
auto mapped_register =
|
||||
virtual_registers.at(register_id).getMappedMemoryPtr();
|
||||
|
||||
mapped_register +=
|
||||
chip_id * n_bytes; // TODO: how to handle different chip ids ->
|
||||
// e.g. broadcast do we want it to be
|
||||
// configurable for different chip ids?
|
||||
|
||||
// TODO: should I emulate the shifting in of dummy data and shifting
|
||||
// out of the register data here to be more realistic?
|
||||
std::vector<std::byte> output_data(n_bytes);
|
||||
std::memcpy(output_data.data(), mapped_register, n_bytes);
|
||||
|
||||
return output_data;
|
||||
}
|
||||
|
||||
void spi_write(const uint8_t chip_id, const uint8_t register_id,
|
||||
const std::vector<std::byte> &data) {
|
||||
|
||||
auto mapped_register =
|
||||
virtual_registers.at(register_id).getMappedMemoryPtr();
|
||||
|
||||
mapped_register +=
|
||||
chip_id * data.size(); // TODO: how to handle different
|
||||
// chip ids -> e.g. broadcast do
|
||||
|
||||
// TODO: should I emulate the shifting in of dummy data and shifting
|
||||
// out of
|
||||
std::memcpy(mapped_register, data.data(), data.size());
|
||||
}
|
||||
|
||||
private:
|
||||
/// @brief map of register id to virtual memory model for each register
|
||||
std::map<uint16_t, VirtualMemoryModel<std::byte>> virtual_registers{};
|
||||
};
|
||||
|
||||
} // namespace sls
|
||||
@@ -0,0 +1,87 @@
|
||||
#pragma once
|
||||
#include "fmt/format.h"
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
namespace sls {
|
||||
|
||||
struct SPIRegister {
|
||||
/// @brief SPI register ID (0-15)
|
||||
uint16_t spi_register_id{};
|
||||
|
||||
/// @brief number of bytes in the register
|
||||
uint64_t n_bytes{};
|
||||
};
|
||||
|
||||
struct SPIRegisterField {
|
||||
/// @brief SPI register to which teh field belongs
|
||||
SPIRegister register_{};
|
||||
|
||||
/// @brief least significant bit position of the field in the register
|
||||
uint64_t lsb_position{};
|
||||
|
||||
/// @brief number of bits in the field
|
||||
/// TODO: can it be larger?
|
||||
uint32_t num_bits{};
|
||||
};
|
||||
|
||||
// TODO: maybe change uint32_t but max field size is 32 bits so should be fine
|
||||
// for now
|
||||
void inline setSPIRegisterField(std::vector<std::byte> ®ister_value,
|
||||
const SPIRegisterField &field,
|
||||
uint32_t field_value) {
|
||||
|
||||
// check that the field value can fit in the bitmask
|
||||
if ((field_value >> field.num_bits) != 0) {
|
||||
throw std::invalid_argument(fmt::format(
|
||||
"Value {} cannot fit in field {}", field_value, field.num_bits));
|
||||
}
|
||||
|
||||
constexpr uint8_t bits_per_byte = 8;
|
||||
|
||||
// TODO: mmh doesnt feel very modern - maybe better to cast to uint32_t,
|
||||
// alignment issues?
|
||||
for (std::size_t i = 0; i < field.num_bits; ++i) {
|
||||
std::size_t offset = field.lsb_position + i;
|
||||
std::size_t byte_index = offset / bits_per_byte;
|
||||
std::size_t bit_index = offset % bits_per_byte;
|
||||
|
||||
std::byte mask = std::byte(1) << bit_index;
|
||||
|
||||
const bool bit = (field_value >> i) & 0x1;
|
||||
|
||||
if (bit) {
|
||||
register_value[byte_index] |=
|
||||
mask; // set the bit in the register value
|
||||
} else {
|
||||
register_value[byte_index] &=
|
||||
~mask; // clear the bit in the register value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t inline getSPIRegisterField(
|
||||
const std::vector<std::byte> ®ister_value,
|
||||
const SPIRegisterField &field) {
|
||||
|
||||
uint32_t field_value = 0;
|
||||
constexpr uint8_t bits_per_byte = 8;
|
||||
|
||||
for (std::size_t i = 0; i < field.num_bits; ++i) {
|
||||
std::size_t offset = field.lsb_position + i;
|
||||
std::size_t byte_index = offset / bits_per_byte;
|
||||
std::size_t bit_index = offset % bits_per_byte;
|
||||
|
||||
std::byte mask = std::byte(1) << bit_index;
|
||||
|
||||
field_value |=
|
||||
(static_cast<uint32_t>((register_value[byte_index] & mask) >>
|
||||
bit_index)
|
||||
<< i); // extract the field value bit from the register value and
|
||||
// set it in the correct position in the field value
|
||||
}
|
||||
|
||||
return field_value;
|
||||
}
|
||||
|
||||
} // namespace sls
|
||||
@@ -0,0 +1,50 @@
|
||||
#pragma once
|
||||
#include "RegisterDefs.hpp"
|
||||
#include "SPIRegisterDefs.hpp"
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
|
||||
namespace sls {
|
||||
|
||||
namespace MatterhornDefs {
|
||||
|
||||
constexpr uint8_t NUM_CHIPS_PER_MODULE = 8;
|
||||
|
||||
// TODO: should probably be a specialized template struct
|
||||
|
||||
/// @brief list of Matterhorn SPI registers
|
||||
struct MatterhornSPIRegisters {
|
||||
|
||||
constexpr static std::array<SPIRegister, 12> spiregisters{
|
||||
SPIRegisters::SPI_REG_ConfigUnit,
|
||||
SPIRegisters::SPI_REG_ConfigCML,
|
||||
SPIRegisters::SPI_REG_ManualSelector,
|
||||
SPIRegisters::SPI_REG_CoreRSTUnit,
|
||||
SPIRegisters::SPI_REG_StoreRSTUnit,
|
||||
SPIRegisters::SPI_REG_Trimbits,
|
||||
SPIRegisters::SPI_REG_McGyver,
|
||||
SPIRegisters::SPI_REG_McGyver_par_load,
|
||||
SPIRegisters::SPI_REG_ActionReg,
|
||||
SPIRegisters::SPI_REG_InternalDACs,
|
||||
SPIRegisters::SPI_REG_ChecksumReg,
|
||||
SPIRegisters::SPI_REG_ExtraClocks};
|
||||
|
||||
constexpr static uint8_t NUM_CHIPS_PER_MODULE =
|
||||
MatterhornDefs::NUM_CHIPS_PER_MODULE;
|
||||
};
|
||||
|
||||
/// @brief list of Matterhorn IP cores
|
||||
struct MatterHornIPCores {
|
||||
|
||||
using ipcore_enum_type = IPCore;
|
||||
|
||||
constexpr static std::array<IPCore, 5> ipcores{
|
||||
IPCore::MH_RO_SM_AXI, IPCore::FHDR_AXI, IPCore::AURORA_STATUS,
|
||||
IPCore::AURORA_STATUS2, IPCore::PACKETIZERREG};
|
||||
|
||||
constexpr static size_t ip_core_block_size = IPCORE_REGISTER_BLOCK_SIZE;
|
||||
};
|
||||
|
||||
} // namespace MatterhornDefs
|
||||
|
||||
} // namespace sls
|
||||
+52
-9
@@ -1,19 +1,27 @@
|
||||
|
||||
// clang-format off
|
||||
#pragma once
|
||||
#include "RegisterHelperStructs.hpp"
|
||||
|
||||
namespace sls {
|
||||
|
||||
/// @brief Enum for IP cores, value are adresses
|
||||
constexpr enum class IPCore : uint32_t {
|
||||
MH_RO_SM_AXI = 0, // dummy adresses for now
|
||||
FHDR_AXI = 1,
|
||||
AURORA_STATUS = 2,
|
||||
AURORA_STATUS2 = 3,
|
||||
PACKETIZERREG = 4,
|
||||
UNKNOWN = 5
|
||||
enum class IPCore : uint32_t {
|
||||
MH_RO_SM_AXI = 0xB0010000,
|
||||
FHDR_AXI = 0xB0011000,
|
||||
AURORA_STATUS = 0xB0014000,
|
||||
AURORA_STATUS2 = 0xB0015000,
|
||||
PACKETIZERREG = 0x00000000, // TODO: need to update with actual address
|
||||
UNKNOWN = 0x00000000 // dont know yet
|
||||
};
|
||||
|
||||
constexpr size_t IPCORE_REGISTER_BLOCK_SIZE =
|
||||
0x1000; // size of each IP core address space in bytes // TODO: maybe add in
|
||||
// other file definitions
|
||||
|
||||
// clang-format off
|
||||
namespace Reg {
|
||||
|
||||
|
||||
// Register definitions
|
||||
constexpr Register CTRL_Reg{IPCore::UNKNOWN, 0x0};
|
||||
@@ -22,7 +30,7 @@ constexpr Register Status_Reg{IPCore::UNKNOWN, 0x4};
|
||||
|
||||
constexpr Register FPGAVersionReg{IPCore::UNKNOWN, 0x8};
|
||||
|
||||
constexpr Register FPGA_GIT_HEAD{IPCore::UNKNOWN, 0xc};
|
||||
constexpr Register FPGA_GIT_HEADReg{IPCore::UNKNOWN, 0xc};
|
||||
|
||||
constexpr Register FixedPatternReg{IPCore::UNKNOWN, 0x10};
|
||||
|
||||
@@ -42,6 +50,8 @@ constexpr Register MH_SM_StoreLength_Reg{IPCore::MH_RO_SM_AXI, 0x10};
|
||||
|
||||
constexpr Register MH_SM_ResetMHLength_Reg{IPCore::MH_RO_SM_AXI, 0x14};
|
||||
|
||||
constexpr Register MH_SM_Triggers_Reg{IPCore::MH_RO_SM_AXI, 0x18};
|
||||
|
||||
constexpr Register Frame_HDR_Set_Reg{IPCore::FHDR_AXI, 0x0};
|
||||
|
||||
constexpr Register Frame_HDR_FrameNumLSB_Reg{IPCore::FHDR_AXI, 0x4};
|
||||
@@ -116,7 +126,7 @@ constexpr RegisterField FPGADetType{
|
||||
FPGAVersionReg, 24, 0xff};
|
||||
|
||||
constexpr RegisterField FPGA_GIT_HEAD{
|
||||
FPGA_GIT_HEAD, 0, 0xffffffff};
|
||||
FPGA_GIT_HEADReg, 0, 0xffffffff};
|
||||
|
||||
constexpr RegisterField FixedPattern{
|
||||
FixedPatternReg, 0, 0xffffffff};
|
||||
@@ -136,6 +146,24 @@ constexpr RegisterField Start_Acquistion{
|
||||
constexpr RegisterField Stop_Acquistion{
|
||||
MH_SM_Ctrl_Reg, 1, 0x1};
|
||||
|
||||
constexpr RegisterField External_Counter_Enable{
|
||||
MH_SM_Ctrl_Reg, 2, 0x1};
|
||||
|
||||
constexpr RegisterField Parallel_RO{
|
||||
MH_SM_Ctrl_Reg, 3, 0x1};
|
||||
|
||||
constexpr RegisterField Trigger_Mode{
|
||||
MH_SM_Ctrl_Reg, 4, 0x3};
|
||||
|
||||
constexpr RegisterField HW_Trigger_Polarity{
|
||||
MH_SM_Ctrl_Reg, 6, 0x1};
|
||||
|
||||
constexpr RegisterField SW_Trigger{
|
||||
MH_SM_Ctrl_Reg, 7, 0x1};
|
||||
|
||||
constexpr RegisterField Reset_Readout_SM{
|
||||
MH_SM_Ctrl_Reg, 8, 0x1};
|
||||
|
||||
constexpr RegisterField MH_Readout_Exposure_Time{
|
||||
MH_SM_Exposure_Reg, 0, 0xffffffff};
|
||||
|
||||
@@ -151,6 +179,9 @@ constexpr RegisterField MH_SM_StoreLength{
|
||||
constexpr RegisterField MH_SM_ResetMHLength{
|
||||
MH_SM_ResetMHLength_Reg, 0, 0xffffffff};
|
||||
|
||||
constexpr RegisterField MH_SM_Triggers{
|
||||
MH_SM_Triggers_Reg, 0, 0xffffffff};
|
||||
|
||||
constexpr RegisterField Frame_Hdr_Set_Framenumber{
|
||||
Frame_HDR_Set_Reg, 0, 0x1};
|
||||
|
||||
@@ -236,5 +267,17 @@ constexpr RegisterField Coordz{
|
||||
PktCoordReg2, 0, 0xffff};
|
||||
|
||||
|
||||
constexpr RegisterField ModuleRow{
|
||||
Frame_HDR_ModCoord_LSB_Reg, 0, 0xffff};
|
||||
|
||||
constexpr RegisterField ModuleCol{
|
||||
Frame_HDR_ModCoord_LSB_Reg, 16, 0xffff};
|
||||
|
||||
constexpr RegisterField ModuleCoordz{
|
||||
Frame_HDR_ModCoord_MSB_Reg, 0, 0xffff};
|
||||
|
||||
constexpr RegisterField ModuleIndex{
|
||||
Frame_HDR_ModCoord_MSB_Reg, 16, 0xffff};
|
||||
} // namespace Reg
|
||||
} // namespace sls
|
||||
// clang-format on
|
||||
@@ -0,0 +1,51 @@
|
||||
#pragma once
|
||||
#include "SPIRegisterHelperStructs.hpp"
|
||||
#include <cstdint>
|
||||
|
||||
namespace sls {
|
||||
|
||||
namespace SPIRegisters {
|
||||
|
||||
// SPI registers
|
||||
constexpr SPIRegister SPI_REG_ConfigUnit{0, 8};
|
||||
|
||||
constexpr SPIRegister SPI_REG_ConfigCML{1, 1};
|
||||
|
||||
constexpr SPIRegister SPI_REG_ManualSelector{2, 2};
|
||||
|
||||
constexpr SPIRegister SPI_REG_CoreRSTUnit{3, 4};
|
||||
|
||||
constexpr SPIRegister SPI_REG_StoreRSTUnit{4, 2};
|
||||
|
||||
constexpr SPIRegister SPI_REG_Trimbits{5, 256};
|
||||
|
||||
constexpr SPIRegister SPI_REG_McGyver{6, 512};
|
||||
|
||||
constexpr SPIRegister SPI_REG_McGyver_par_load{7, 512};
|
||||
|
||||
constexpr SPIRegister SPI_REG_ActionReg{11, 1};
|
||||
|
||||
constexpr SPIRegister SPI_REG_InternalDACs{13, 4};
|
||||
|
||||
constexpr SPIRegister SPI_REG_ChecksumReg{14, 32};
|
||||
|
||||
// Used to generate extra clocks after writing to trigger the load of the new
|
||||
// value
|
||||
constexpr SPIRegister SPI_REG_ExtraClocks{12,
|
||||
1}; // TODO: dont know what size is
|
||||
|
||||
// SPI register fields
|
||||
constexpr SPIRegisterField OUTPUT_MODE{SPI_REG_ConfigUnit, 4, 3};
|
||||
|
||||
/// @brief first two bits starting counter, second two bits number of counters
|
||||
/// to read e.g. 0b0100 -> read counter 0 and 1, 0b0001 -> read counter 1
|
||||
constexpr SPIRegisterField NUM_COUNTERS{SPI_REG_ConfigUnit, 8, 4};
|
||||
|
||||
/// @brief 00-> 16 bit, 01 -> 8 bit, 10 -> 4 bit, 11 -> reserved 16 bit
|
||||
constexpr SPIRegisterField DYNAMIC_RANGE{SPI_REG_ConfigUnit, 14, 2};
|
||||
|
||||
// TODO: continue defining the rest of the fields as needed
|
||||
|
||||
} // namespace SPIRegisters
|
||||
|
||||
} // namespace sls
|
||||
@@ -0,0 +1,75 @@
|
||||
#include "HelperFunctions.hpp"
|
||||
#include <stdexcept>
|
||||
|
||||
namespace sls {
|
||||
|
||||
uint32_t convertCounterMaskToSPICounterMask(const uint32_t counter_mask) {
|
||||
uint32_t spi_counter_mask = 0;
|
||||
|
||||
switch (counter_mask) {
|
||||
case 0b1:
|
||||
spi_counter_mask = 0b0000; // counter 0 enabled
|
||||
break;
|
||||
case 0b10:
|
||||
spi_counter_mask = 0b0001; // counter 1 enabled
|
||||
break;
|
||||
case 0b100:
|
||||
spi_counter_mask = 0b0010; // counter 2 enabled
|
||||
break;
|
||||
case 0b1000:
|
||||
spi_counter_mask = 0b0011; // counter 3 enabled
|
||||
break;
|
||||
case 0b11:
|
||||
spi_counter_mask = 0b0100; // counter 0 and 1 enabled
|
||||
break;
|
||||
case 0b110:
|
||||
spi_counter_mask = 0b0101; // counter 1 and 2 enabled
|
||||
break;
|
||||
case 0b1100:
|
||||
spi_counter_mask = 0b0110; // counter 2 and 3 enabled
|
||||
break;
|
||||
case 0b1001:
|
||||
spi_counter_mask = 0b0111; // counter 0 and 3 enabled
|
||||
break;
|
||||
case 0b111:
|
||||
spi_counter_mask = 0b1000; // counter 0, 1 and 2 enabled
|
||||
break;
|
||||
case 0b1110:
|
||||
spi_counter_mask = 0b1001; // counter 1, 2 and 3 enabled
|
||||
break;
|
||||
case 0b1101:
|
||||
spi_counter_mask = 0b1010; // counter 0, 2 and 3 enabled
|
||||
break;
|
||||
case 0b1011:
|
||||
spi_counter_mask = 0b1011; // counter 0, 1 and 3 enabled
|
||||
break;
|
||||
case 0b1111:
|
||||
spi_counter_mask = 0b1100; // counter 0, 1, 2 and 3 enabled
|
||||
break;
|
||||
default:
|
||||
throw std::invalid_argument(
|
||||
"Invalid counter mask: Only contiguous counters are enabled "
|
||||
"(including wrap around)");
|
||||
}
|
||||
|
||||
return spi_counter_mask;
|
||||
}
|
||||
|
||||
uint32_t convertSPICounterMaskToCounterMask(const uint32_t spi_counter_mask) {
|
||||
|
||||
uint32_t counter_mask{};
|
||||
|
||||
uint8_t start_counter = spi_counter_mask & 0b11; // extract starting counter
|
||||
uint8_t num_counters =
|
||||
((spi_counter_mask >> 2) & 0b11) + 1; // extract number of counters
|
||||
|
||||
constexpr uint8_t max_counters = 4;
|
||||
|
||||
for (uint8_t i = 0; i < num_counters; ++i) {
|
||||
counter_mask |= (1 << ((start_counter + i) % max_counters));
|
||||
}
|
||||
|
||||
return counter_mask;
|
||||
}
|
||||
|
||||
} // namespace sls
|
||||
@@ -0,0 +1,26 @@
|
||||
/**
|
||||
* @file HelperFunctions.hpp
|
||||
* @short contains helper functions for the Matterhorn server implementation
|
||||
* e.g. for processing of specific commands
|
||||
*/
|
||||
#include <cstdint>
|
||||
|
||||
namespace sls {
|
||||
|
||||
/**
|
||||
* @brief converts the counter mask received from the client to the actual
|
||||
* counter mask to be written to the SPI register based on the starting counter
|
||||
* and number of counters to read
|
||||
* @return actual counter mask to be written to the SPI register
|
||||
*/
|
||||
uint32_t convertCounterMaskToSPICounterMask(const uint32_t counter_mask);
|
||||
|
||||
/**
|
||||
* @brief converts the actual counter mask read from the SPI register to the
|
||||
* counter mask to be sent to the client e.g. bit set to 1 if counter
|
||||
* enabled
|
||||
* @return counter mask to be sent to the client
|
||||
*/
|
||||
uint32_t convertSPICounterMaskToCounterMask(const uint32_t spi_counter_mask);
|
||||
|
||||
} // namespace sls
|
||||
@@ -0,0 +1,9 @@
|
||||
|
||||
target_sources(tests PRIVATE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/test-HelperFunctions.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../src/utils/HelperFunctions.cpp
|
||||
)
|
||||
|
||||
target_include_directories(tests
|
||||
PUBLIC
|
||||
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/../src/utils>")
|
||||
@@ -0,0 +1,48 @@
|
||||
#include "HelperFunctions.hpp"
|
||||
#include "catch.hpp"
|
||||
#include <iostream>
|
||||
|
||||
namespace sls {
|
||||
|
||||
auto get_test_parameters_countermaskspiconversion() {
|
||||
return GENERATE(std::make_tuple(uint32_t{0x1}, uint32_t{0b0000}),
|
||||
std::make_tuple(uint32_t{0x2}, uint32_t{0b0001}),
|
||||
std::make_tuple(uint32_t{0x4}, uint32_t{0b0010}),
|
||||
std::make_tuple(uint32_t{0x3}, uint32_t{0b0100}),
|
||||
std::make_tuple(uint32_t{0x6}, uint32_t{0b0101}),
|
||||
std::make_tuple(uint32_t{0x7}, uint32_t{0b1000}),
|
||||
std::make_tuple(uint32_t{0x8}, uint32_t{0b0011}),
|
||||
std::make_tuple(uint32_t{0x9}, uint32_t{0b0111}),
|
||||
std::make_tuple(uint32_t{0xB}, uint32_t{0b1011}),
|
||||
std::make_tuple(uint32_t{0xC}, uint32_t{0b0110}),
|
||||
std::make_tuple(uint32_t{0xD}, uint32_t{0b1010}),
|
||||
std::make_tuple(uint32_t{0xE}, uint32_t{0b1001}),
|
||||
std::make_tuple(uint32_t{0xF}, uint32_t{0b1100}),
|
||||
std::make_tuple(uint32_t{0xB}, uint32_t{0b1011}));
|
||||
}
|
||||
|
||||
TEST_CASE("Convert Counter Mask to SPI Counter Mask",
|
||||
"[MatterHorn][HelperFunctions]") {
|
||||
auto [counter_mask, expected_spi_counter_mask] =
|
||||
get_test_parameters_countermaskspiconversion();
|
||||
|
||||
REQUIRE(convertCounterMaskToSPICounterMask(counter_mask) ==
|
||||
expected_spi_counter_mask);
|
||||
|
||||
REQUIRE_THROWS(
|
||||
convertCounterMaskToSPICounterMask(0xA)); // invalid counter mask
|
||||
|
||||
REQUIRE_THROWS(
|
||||
convertCounterMaskToSPICounterMask(0x5)); // invalid counter mask
|
||||
}
|
||||
|
||||
TEST_CASE("Convert SPI Counter Mask to Counter Mask",
|
||||
"[MatterHorn][HelperFunctions]") {
|
||||
auto [counter_mask, spi_counter_mask] =
|
||||
get_test_parameters_countermaskspiconversion();
|
||||
|
||||
REQUIRE(convertSPICounterMaskToCounterMask(spi_counter_mask) ==
|
||||
counter_mask);
|
||||
}
|
||||
|
||||
} // namespace sls
|
||||
@@ -0,0 +1,17 @@
|
||||
#Usage: cmake .. -DCMAKE_TOOLCHAIN_FILE=toolchain.cmake -DSLS_BUILD_ONLY_MATTERHORN=ON
|
||||
|
||||
set(SLS_ARM_COMPILER "/psi.ch/group/detector/firmware/arm64_linux/arm-gnu-toolchain-12.3.rel1-x86_64-aarch64-none-linux-gnu/" CACHE PATH "Path to the ARM cross compiler")
|
||||
|
||||
set(CMAKE_SYSTEM_NAME Linux)
|
||||
set(CMAKE_SYSTEM_PROCESSOR aarch64)
|
||||
|
||||
set(CMAKE_C_COMPILER "${SLS_ARM_COMPILER}/bin/aarch64-none-linux-gnu-gcc")
|
||||
set(CMAKE_CXX_COMPILER "${SLS_ARM_COMPILER}/bin/aarch64-none-linux-gnu-g++")
|
||||
|
||||
set(CMAKE_AR "${SLS_ARM_COMPILER}/bin/aarch64-none-linux-gnu-ar")
|
||||
set(CMAKE_RANLIB "${SLS_ARM_COMPILER}/bin/aarch64-none-linux-gnu-ranlib")
|
||||
|
||||
set(CMAKE_FIND_ROOT_PATH "${SLS_ARM_COMPILER}")
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
set(SOURCES
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/TCPInterface.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/CommandLineOptions.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/MemoryModel.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/DetectorServerImpl.cpp
|
||||
)
|
||||
|
||||
add_library(slsServerObject OBJECT
|
||||
@@ -23,13 +25,13 @@ target_link_libraries(slsServerObject
|
||||
set(DETECTOR_LIBRARY_TARGETS slsServerObject)
|
||||
|
||||
set(PUBLICHEADERS
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include/TCPInterface.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include/TCPInterface.hpp
|
||||
)
|
||||
|
||||
#Shared library
|
||||
if(SLS_BUILD_SHARED_LIBRARIES)
|
||||
add_library(slsServerShared SHARED $<TARGET_OBJECTS:slsServerObject>)
|
||||
target_link_libraries(slsServerShared PUBLIC slsServerObject)
|
||||
target_link_libraries(slsServerShared PUBLIC slsServerObject PRIVATE slsProjectWarnings)
|
||||
set_target_properties(slsServerShared PROPERTIES
|
||||
VERSION ${PACKAGE_VERSION_MAJOR}.${PACKAGE_VERSION_MINOR}.${PACKAGE_VERSION_PATCH}
|
||||
SOVERSION ${PACKAGE_VERSION_MAJOR}
|
||||
@@ -42,7 +44,7 @@ endif(SLS_BUILD_SHARED_LIBRARIES)
|
||||
|
||||
#Static library
|
||||
add_library(slsServerStatic STATIC $<TARGET_OBJECTS:slsServerObject>)
|
||||
target_link_libraries(slsServerStatic PUBLIC slsServerObject)
|
||||
target_link_libraries(slsServerStatic PUBLIC slsServerObject PRIVATE slsProjectWarnings)
|
||||
|
||||
set_target_properties(slsServerStatic PROPERTIES
|
||||
ARCHIVE_OUTPUT_NAME SlsServerStatic
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
#pragma once
|
||||
#include "RegisterHelperStructs.hpp"
|
||||
#include "fmt/format.h"
|
||||
#include <cstdint>
|
||||
#include <fcntl.h>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
#include <sys/mman.h>
|
||||
#include <vector>
|
||||
|
||||
// TODO: maybe should be templated on address type (e.g. uint32_t register or
|
||||
// uint64_t register) for more flexibility?
|
||||
|
||||
namespace sls {
|
||||
|
||||
template <typename IPCores, typename MemoryModel> class BusCommunication {
|
||||
|
||||
using IPCoreEnumType = typename IPCores::ipcore_enum_type;
|
||||
|
||||
public:
|
||||
BusCommunication();
|
||||
|
||||
void mapToMemory();
|
||||
|
||||
uint32_t readRegister(const Register ®ister_) const;
|
||||
void writeRegister(const Register ®ister_, const uint32_t data);
|
||||
|
||||
private:
|
||||
void bus_w(const uint32_t offset, IPCoreEnumType baseadress,
|
||||
const uint32_t data);
|
||||
|
||||
uint32_t bus_r(const uint32_t offset, IPCoreEnumType baseadress) const;
|
||||
|
||||
/// @brief map from id of IP Core to memory model for the register block of
|
||||
/// the IP core
|
||||
std::map<IPCoreEnumType, MemoryModel> ipcoreregisterblocks{};
|
||||
};
|
||||
|
||||
template <typename IPCores, typename MemoryModel>
|
||||
BusCommunication<IPCores, MemoryModel>::BusCommunication() {
|
||||
|
||||
for (const auto &ip_core : IPCores::ipcores) {
|
||||
ipcoreregisterblocks.emplace(ip_core,
|
||||
MemoryModel{static_cast<uint32_t>(ip_core),
|
||||
IPCores::ip_core_block_size});
|
||||
}
|
||||
}
|
||||
|
||||
template <typename IPCores, typename MemoryModel>
|
||||
void BusCommunication<IPCores, MemoryModel>::mapToMemory() {
|
||||
|
||||
for (auto &map_elem : ipcoreregisterblocks) {
|
||||
map_elem.second.mapToMemory();
|
||||
}
|
||||
}
|
||||
|
||||
template <typename IPCores, typename MemoryModel>
|
||||
uint32_t BusCommunication<IPCores, MemoryModel>::readRegister(
|
||||
const Register ®ister_) const {
|
||||
return bus_r(register_.offset_in_bytes, register_.ip_core);
|
||||
}
|
||||
|
||||
template <typename IPCores, typename MemoryModel>
|
||||
void BusCommunication<IPCores, MemoryModel>::writeRegister(
|
||||
const Register ®ister_, const uint32_t data) {
|
||||
bus_w(register_.offset_in_bytes, register_.ip_core, data);
|
||||
}
|
||||
|
||||
template <typename IPCores, typename MemoryModel>
|
||||
uint32_t BusCommunication<IPCores, MemoryModel>::bus_r(
|
||||
const uint32_t offset, const IPCoreEnumType baseadress) const {
|
||||
auto ptr1 = ipcoreregisterblocks.at(baseadress).getMappedMemoryPtr() +
|
||||
offset / (sizeof(uint32_t));
|
||||
return *ptr1;
|
||||
}
|
||||
|
||||
template <typename IPCores, typename MemoryModel>
|
||||
void BusCommunication<IPCores, MemoryModel>::bus_w(
|
||||
const uint32_t offset, const IPCoreEnumType baseadress,
|
||||
const uint32_t data) {
|
||||
auto ptr1 = ipcoreregisterblocks.at(baseadress).getMappedMemoryPtr() +
|
||||
offset / (sizeof(uint32_t));
|
||||
*ptr1 = data;
|
||||
}
|
||||
|
||||
} // namespace sls
|
||||
@@ -1,271 +0,0 @@
|
||||
#pragma once
|
||||
#include "TCPInterface.h"
|
||||
// #include "communication_funcs.h"
|
||||
#include "sls/logger.h"
|
||||
#include "sls/network_utils.h"
|
||||
#include "sls/sls_detector_defs.h"
|
||||
#include "sls/versionAPI.h"
|
||||
#include <array>
|
||||
#include <cstring>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace sls {
|
||||
|
||||
// TODO move to defs?
|
||||
/// @brief struct saving udp details (one UDP port per module)
|
||||
struct UDPInfo {
|
||||
uint16_t srcport{};
|
||||
uint16_t dstport{};
|
||||
uint64_t srcmac{};
|
||||
uint64_t dstmac{};
|
||||
uint32_t srcip{};
|
||||
uint32_t dstip{};
|
||||
};
|
||||
|
||||
using ReturnCode = slsDetectorDefs::ReturnCode;
|
||||
|
||||
template <typename DerivedDetectorServer> class DetectorServer {
|
||||
|
||||
public:
|
||||
/**
|
||||
* Constructor
|
||||
* Creates a detector server.
|
||||
* Assembles a detector server using TCP and UDP detector interfaces
|
||||
* throws an exception in case of failure
|
||||
* @param port TCP/IP port number
|
||||
*/
|
||||
explicit DetectorServer(uint16_t port = DEFAULT_TCP_CNTRL_PORTNO);
|
||||
|
||||
protected:
|
||||
/// @brief TCP/IP interface for communication with the client
|
||||
std::unique_ptr<TCPInterface> tcpInterface;
|
||||
|
||||
std::array<UDPInfo, 1>
|
||||
udpDetails{}; // TODO: for now only one receiver per module
|
||||
|
||||
/// @brief TODO what is this?
|
||||
bool updateMode{true};
|
||||
|
||||
private:
|
||||
ReturnCode processFunction(const detFuncs function_id,
|
||||
ServerInterface &socket);
|
||||
|
||||
// TODO dont know what this does?
|
||||
ReturnCode get_update_mode(ServerInterface &socket) const;
|
||||
|
||||
ReturnCode get_source_udp_mac(ServerInterface &socket) const;
|
||||
|
||||
ReturnCode set_source_udp_mac(ServerInterface &socket);
|
||||
|
||||
ReturnCode get_source_udp_ip(ServerInterface &socket) const;
|
||||
|
||||
ReturnCode set_source_udp_ip(ServerInterface &socket);
|
||||
|
||||
ReturnCode get_source_udp_port(ServerInterface &socket) const;
|
||||
|
||||
ReturnCode set_destination_udp_mac(ServerInterface &socket);
|
||||
|
||||
ReturnCode get_destination_udp_mac(ServerInterface &socket) const;
|
||||
|
||||
ReturnCode set_destination_udp_ip(ServerInterface &socket);
|
||||
|
||||
ReturnCode get_destination_udp_ip(ServerInterface &socket) const;
|
||||
|
||||
ReturnCode set_destination_udp_port(ServerInterface &socket);
|
||||
|
||||
ReturnCode get_destination_udp_port(ServerInterface &socket) const;
|
||||
};
|
||||
|
||||
template <typename DerivedDetectorServer>
|
||||
DetectorServer<DerivedDetectorServer>::DetectorServer(uint16_t port) {
|
||||
validatePortNumber(port);
|
||||
|
||||
udpDetails[0].srcport = DEFAULT_UDP_SRC_PORTNO;
|
||||
udpDetails[0].dstport = DEFAULT_UDP_DST_PORTNO;
|
||||
|
||||
std::function<ReturnCode(const detFuncs &, ServerInterface &)> fn =
|
||||
[this](const detFuncs &function_id, ServerInterface &socket) {
|
||||
return this->processFunction(function_id, socket);
|
||||
};
|
||||
tcpInterface = std::make_unique<TCPInterface>(fn, port);
|
||||
}
|
||||
|
||||
template <typename DerivedDetectorServer>
|
||||
ReturnCode DetectorServer<DerivedDetectorServer>::processFunction(
|
||||
const detFuncs function_id, ServerInterface &socket) {
|
||||
|
||||
switch (function_id) {
|
||||
case detFuncs::F_GET_SERVER_VERSION:
|
||||
return static_cast<DerivedDetectorServer *>(this)->get_version(socket);
|
||||
case detFuncs::F_GET_DETECTOR_TYPE:
|
||||
return static_cast<DerivedDetectorServer *>(this)->get_detector_type(
|
||||
socket);
|
||||
case detFuncs::F_INITIAL_CHECKS:
|
||||
return static_cast<DerivedDetectorServer *>(this)->initial_checks(
|
||||
socket);
|
||||
case detFuncs::F_GET_NUM_INTERFACES:
|
||||
return static_cast<DerivedDetectorServer *>(this)
|
||||
->get_num_udp_interfaces(socket);
|
||||
case detFuncs::F_GET_UPDATE_MODE:
|
||||
return get_update_mode(socket);
|
||||
case detFuncs::F_SET_SOURCE_UDP_MAC:
|
||||
return set_source_udp_mac(socket);
|
||||
case detFuncs::F_GET_SOURCE_UDP_MAC:
|
||||
return get_source_udp_mac(socket);
|
||||
case detFuncs::F_SET_SOURCE_UDP_IP:
|
||||
return set_source_udp_ip(socket);
|
||||
case detFuncs::F_GET_SOURCE_UDP_IP:
|
||||
return get_source_udp_ip(socket);
|
||||
case detFuncs::F_SET_DEST_UDP_MAC:
|
||||
return set_destination_udp_mac(socket);
|
||||
case detFuncs::F_GET_DEST_UDP_MAC:
|
||||
return get_destination_udp_mac(socket);
|
||||
case detFuncs::F_SET_DEST_UDP_IP:
|
||||
return set_destination_udp_ip(socket);
|
||||
case detFuncs::F_GET_DEST_UDP_IP:
|
||||
return get_destination_udp_ip(socket);
|
||||
case detFuncs::F_SET_DEST_UDP_PORT:
|
||||
return set_destination_udp_port(socket);
|
||||
case detFuncs::F_GET_DEST_UDP_PORT:
|
||||
return get_destination_udp_port(socket);
|
||||
|
||||
default:
|
||||
LOG(logDEBUG) << "Checking specific server functions for function ID: "
|
||||
<< function_id;
|
||||
// process detector specific functions
|
||||
static_cast<DerivedDetectorServer *>(this)->processFunction(function_id,
|
||||
socket);
|
||||
}
|
||||
|
||||
return ReturnCode::FAIL;
|
||||
}
|
||||
|
||||
template <typename DerivedDetectorServer>
|
||||
ReturnCode DetectorServer<DerivedDetectorServer>::get_update_mode(
|
||||
ServerInterface &socket) const {
|
||||
|
||||
return static_cast<ReturnCode>(
|
||||
socket.sendResult(static_cast<int>(updateMode)));
|
||||
}
|
||||
|
||||
template <typename DerivedDetectorServer>
|
||||
ReturnCode DetectorServer<DerivedDetectorServer>::set_source_udp_mac(
|
||||
ServerInterface &socket) {
|
||||
uint64_t newsrcudpMac;
|
||||
|
||||
try {
|
||||
int ret = socket.Receive<uint64_t>(newsrcudpMac);
|
||||
} catch (const SocketError &e) {
|
||||
LOG(logERROR) << "Failed to receive new source UDP MAC address: "
|
||||
<< e.what();
|
||||
return ReturnCode::FAIL;
|
||||
}
|
||||
|
||||
udpDetails[0].srcmac = newsrcudpMac;
|
||||
// TODO: configuremac, check unicast address
|
||||
return ReturnCode::OK;
|
||||
}
|
||||
|
||||
template <typename DerivedDetectorServer>
|
||||
ReturnCode DetectorServer<DerivedDetectorServer>::get_source_udp_mac(
|
||||
ServerInterface &socket) const {
|
||||
return static_cast<ReturnCode>(socket.sendResult(udpDetails[0].srcmac));
|
||||
}
|
||||
|
||||
template <typename DerivedDetectorServer>
|
||||
ReturnCode DetectorServer<DerivedDetectorServer>::set_source_udp_ip(
|
||||
ServerInterface &socket) {
|
||||
uint32_t newSrcIp;
|
||||
|
||||
try {
|
||||
int ret = socket.Receive(newSrcIp);
|
||||
} catch (const SocketError &e) {
|
||||
LOG(logERROR) << "Failed to receive new source UDP IP address: "
|
||||
<< e.what();
|
||||
return ReturnCode::FAIL;
|
||||
}
|
||||
|
||||
udpDetails[0].srcip = newSrcIp;
|
||||
return ReturnCode::OK;
|
||||
}
|
||||
|
||||
template <typename DerivedDetectorServer>
|
||||
ReturnCode DetectorServer<DerivedDetectorServer>::get_source_udp_ip(
|
||||
ServerInterface &socket) const {
|
||||
return static_cast<ReturnCode>(socket.sendResult(udpDetails[0].srcip));
|
||||
}
|
||||
|
||||
template <typename DerivedDetectorServer>
|
||||
ReturnCode DetectorServer<DerivedDetectorServer>::set_destination_udp_mac(
|
||||
ServerInterface &socket) {
|
||||
uint64_t newDstMac;
|
||||
|
||||
try {
|
||||
int ret = socket.Receive<uint64_t>(newDstMac);
|
||||
} catch (const SocketError &e) {
|
||||
LOG(logERROR) << "Failed to receive new destination UDP MAC address: "
|
||||
<< e.what();
|
||||
return ReturnCode::FAIL;
|
||||
}
|
||||
|
||||
udpDetails[0].dstmac = newDstMac;
|
||||
// TODO: configuremac, check unicast address
|
||||
return ReturnCode::OK;
|
||||
}
|
||||
|
||||
template <typename DerivedDetectorServer>
|
||||
ReturnCode DetectorServer<DerivedDetectorServer>::get_destination_udp_mac(
|
||||
ServerInterface &socket) const {
|
||||
return static_cast<ReturnCode>(socket.sendResult(udpDetails[0].dstmac));
|
||||
}
|
||||
|
||||
template <typename DerivedDetectorServer>
|
||||
ReturnCode DetectorServer<DerivedDetectorServer>::set_destination_udp_ip(
|
||||
ServerInterface &socket) {
|
||||
uint32_t newDstIp;
|
||||
|
||||
try {
|
||||
int ret = socket.Receive(newDstIp);
|
||||
} catch (const SocketError &e) {
|
||||
LOG(logERROR) << "Failed to receive new destination UDP IP address: "
|
||||
<< e.what();
|
||||
return ReturnCode::FAIL;
|
||||
}
|
||||
|
||||
udpDetails[0].dstip = newDstIp;
|
||||
return ReturnCode::OK;
|
||||
}
|
||||
|
||||
template <typename DerivedDetectorServer>
|
||||
ReturnCode DetectorServer<DerivedDetectorServer>::get_destination_udp_ip(
|
||||
ServerInterface &socket) const {
|
||||
return static_cast<ReturnCode>(socket.sendResult(udpDetails[0].dstip));
|
||||
}
|
||||
|
||||
template <typename DerivedDetectorServer>
|
||||
ReturnCode DetectorServer<DerivedDetectorServer>::set_destination_udp_port(
|
||||
ServerInterface &socket) {
|
||||
uint16_t newDstPort;
|
||||
|
||||
try {
|
||||
int ret = socket.Receive(newDstPort);
|
||||
} catch (const SocketError &e) {
|
||||
LOG(logERROR) << "Failed to receive new destination UDP port number: "
|
||||
<< e.what();
|
||||
return ReturnCode::FAIL;
|
||||
}
|
||||
|
||||
udpDetails[0].dstport = newDstPort;
|
||||
return ReturnCode::OK;
|
||||
}
|
||||
|
||||
template <typename DerivedDetectorServer>
|
||||
ReturnCode DetectorServer<DerivedDetectorServer>::get_destination_udp_port(
|
||||
ServerInterface &socket) const {
|
||||
return static_cast<ReturnCode>(socket.sendResult(udpDetails[0].dstport));
|
||||
};
|
||||
|
||||
} // namespace sls
|
||||
@@ -0,0 +1,523 @@
|
||||
#pragma once
|
||||
#include "DetectorServerImpl.hpp"
|
||||
#include "TCPInterface.hpp"
|
||||
#include "helpers/Helpers.hpp"
|
||||
#include "helpers/type_traits.hpp"
|
||||
#include "sls/logger.h"
|
||||
#include "sls/network_utils.h"
|
||||
#include "sls/sls_detector_defs.h"
|
||||
#include "sls/versionAPI.h"
|
||||
#include <array>
|
||||
#include <cstring>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace sls {
|
||||
|
||||
using ReturnCode = slsDetectorDefs::ReturnCode;
|
||||
|
||||
template <typename DerivedDetectorServer> class DetectorServer {
|
||||
|
||||
public:
|
||||
/**
|
||||
* Constructor
|
||||
* Creates a detector server.
|
||||
* Assembles a detector server using TCP and UDP detector interfaces
|
||||
* throws an exception in case of failure
|
||||
* @param port TCP/IP port number
|
||||
*/
|
||||
explicit DetectorServer(
|
||||
std::unique_ptr<
|
||||
DetectorServerImpl<is_stop_server<DerivedDetectorServer>::value>>
|
||||
impl_,
|
||||
uint16_t port = DEFAULT_TCP_CNTRL_PORTNO);
|
||||
|
||||
~DetectorServer() = default;
|
||||
|
||||
protected:
|
||||
/// @brief TCP/IP interface for communication with the client
|
||||
std::unique_ptr<TCPInterface> tcpInterface;
|
||||
|
||||
std::unique_ptr<
|
||||
DetectorServerImpl<is_stop_server<DerivedDetectorServer>::value>>
|
||||
impl;
|
||||
|
||||
auto *getImpl() {
|
||||
return static_cast<typename implementation_type_trait<
|
||||
DerivedDetectorServer>::ImplType *>(impl.get());
|
||||
}
|
||||
|
||||
const auto *getImpl() const {
|
||||
return static_cast<const typename implementation_type_trait<
|
||||
DerivedDetectorServer>::ImplType *>(impl.get());
|
||||
}
|
||||
|
||||
private:
|
||||
/// @brief get derived class
|
||||
DerivedDetectorServer *getDerived() {
|
||||
return static_cast<DerivedDetectorServer *>(this);
|
||||
}
|
||||
|
||||
const DerivedDetectorServer *getDerived() const {
|
||||
return static_cast<const DerivedDetectorServer *>(this);
|
||||
}
|
||||
|
||||
ProcessedResult processFunction(const detFuncs function_id,
|
||||
ServerInterface &socket);
|
||||
|
||||
// TODO dont know what this does?
|
||||
ProcessedResult get_update_mode(ServerInterface &socket) const;
|
||||
|
||||
ProcessedResult get_source_udp_mac(ServerInterface &socket) const;
|
||||
|
||||
ProcessedResult set_source_udp_mac(ServerInterface &socket);
|
||||
|
||||
ProcessedResult get_source_udp_ip(ServerInterface &socket) const;
|
||||
|
||||
ProcessedResult set_source_udp_ip(ServerInterface &socket);
|
||||
|
||||
ProcessedResult get_source_udp_port(ServerInterface &socket) const;
|
||||
|
||||
ProcessedResult set_destination_udp_mac(ServerInterface &socket);
|
||||
|
||||
ProcessedResult get_destination_udp_mac(ServerInterface &socket) const;
|
||||
|
||||
ProcessedResult set_destination_udp_ip(ServerInterface &socket);
|
||||
|
||||
ProcessedResult get_destination_udp_ip(ServerInterface &socket) const;
|
||||
|
||||
ProcessedResult set_destination_udp_port(ServerInterface &socket);
|
||||
|
||||
ProcessedResult get_destination_udp_port(ServerInterface &socket) const;
|
||||
|
||||
ProcessedResult get_num_frames(ServerInterface &socket) const;
|
||||
|
||||
ProcessedResult set_num_frames(ServerInterface &socket);
|
||||
|
||||
ProcessedResult get_num_triggers(ServerInterface &socket) const;
|
||||
|
||||
ProcessedResult set_num_triggers(ServerInterface &socket);
|
||||
|
||||
ProcessedResult get_version(ServerInterface &socket) const;
|
||||
|
||||
ProcessedResult get_num_udp_interfaces(ServerInterface &socket) const;
|
||||
|
||||
ProcessedResult get_detector_type(ServerInterface &socket) const;
|
||||
|
||||
ProcessedResult get_receiver_parameters(ServerInterface &socket) const;
|
||||
|
||||
ProcessedResult get_run_status(ServerInterface &socket) const;
|
||||
|
||||
ProcessedResult initial_checks(ServerInterface &socket) const;
|
||||
|
||||
ProcessedResult
|
||||
set_module_position_and_update_srcudpmac(ServerInterface &socket);
|
||||
};
|
||||
|
||||
template <typename DerivedDetectorServer>
|
||||
DetectorServer<DerivedDetectorServer>::DetectorServer(
|
||||
std::unique_ptr<
|
||||
DetectorServerImpl<is_stop_server<DerivedDetectorServer>::value>>
|
||||
impl_,
|
||||
uint16_t port)
|
||||
: impl(std::move(impl_)) {
|
||||
validatePortNumber(port);
|
||||
|
||||
std::function<ProcessedResult(const detFuncs &, ServerInterface &)> fn =
|
||||
[this](const detFuncs &function_id, ServerInterface &socket) {
|
||||
return this->processFunction(function_id, socket);
|
||||
};
|
||||
|
||||
tcpInterface = std::make_unique<TCPInterface>(fn, port);
|
||||
}
|
||||
|
||||
template <typename DerivedDetectorServer>
|
||||
ProcessedResult DetectorServer<DerivedDetectorServer>::processFunction(
|
||||
const detFuncs function_id, ServerInterface &socket) {
|
||||
|
||||
switch (function_id) {
|
||||
case detFuncs::F_GET_SERVER_VERSION:
|
||||
return get_version(socket);
|
||||
case detFuncs::F_GET_DETECTOR_TYPE:
|
||||
return get_detector_type(socket);
|
||||
case detFuncs::F_INITIAL_CHECKS:
|
||||
return initial_checks(socket);
|
||||
case detFuncs::F_GET_NUM_INTERFACES:
|
||||
return get_num_udp_interfaces(socket);
|
||||
case detFuncs::F_GET_UPDATE_MODE:
|
||||
return get_update_mode(socket);
|
||||
case detFuncs::F_SET_SOURCE_UDP_MAC:
|
||||
return set_source_udp_mac(socket);
|
||||
case detFuncs::F_GET_SOURCE_UDP_MAC:
|
||||
return get_source_udp_mac(socket);
|
||||
case detFuncs::F_SET_SOURCE_UDP_IP:
|
||||
return set_source_udp_ip(socket);
|
||||
case detFuncs::F_GET_SOURCE_UDP_IP:
|
||||
return get_source_udp_ip(socket);
|
||||
case detFuncs::F_SET_DEST_UDP_MAC:
|
||||
return set_destination_udp_mac(socket);
|
||||
case detFuncs::F_GET_DEST_UDP_MAC:
|
||||
return get_destination_udp_mac(socket);
|
||||
case detFuncs::F_SET_DEST_UDP_IP:
|
||||
return set_destination_udp_ip(socket);
|
||||
case detFuncs::F_GET_DEST_UDP_IP:
|
||||
return get_destination_udp_ip(socket);
|
||||
case detFuncs::F_SET_DEST_UDP_PORT:
|
||||
return set_destination_udp_port(socket);
|
||||
case detFuncs::F_GET_DEST_UDP_PORT:
|
||||
return get_destination_udp_port(socket);
|
||||
case detFuncs::F_GET_RUN_STATUS:
|
||||
return get_run_status(socket);
|
||||
case detFuncs::F_GET_NUM_FRAMES:
|
||||
return get_num_frames(socket);
|
||||
case detFuncs::F_SET_NUM_FRAMES:
|
||||
return set_num_frames(socket);
|
||||
case detFuncs::F_GET_NUM_TRIGGERS:
|
||||
return get_num_triggers(socket);
|
||||
case detFuncs::F_SET_NUM_TRIGGERS:
|
||||
return set_num_triggers(socket);
|
||||
case detFuncs::F_GET_RECEIVER_PARAMETERS:
|
||||
return get_receiver_parameters(socket);
|
||||
case detFuncs::F_SET_POSITION:
|
||||
return set_module_position_and_update_srcudpmac(socket);
|
||||
default:
|
||||
LOG(logDEBUG) << "Checking specific server functions for function ID: "
|
||||
<< function_id;
|
||||
// process detector specific functions
|
||||
return getDerived()->processFunction(function_id, socket);
|
||||
}
|
||||
|
||||
return return_fail("Function not implemented");
|
||||
}
|
||||
|
||||
template <typename DerivedDetectorServer>
|
||||
ProcessedResult DetectorServer<DerivedDetectorServer>::get_update_mode(
|
||||
ServerInterface &socket) const {
|
||||
|
||||
const bool updateMode = impl->get_update_mode();
|
||||
|
||||
// TODO: catch the socket error during Send and add error message to the
|
||||
// ProcessedResult but DatSocket shared with receiver - some refactoring
|
||||
return send_result(socket, static_cast<uint32_t>(updateMode));
|
||||
}
|
||||
|
||||
template <typename DerivedDetectorServer>
|
||||
ProcessedResult DetectorServer<DerivedDetectorServer>::get_source_udp_mac(
|
||||
ServerInterface &socket) const {
|
||||
auto srcUdpMac = impl->get_source_udp_mac();
|
||||
|
||||
return send_result(socket, srcUdpMac);
|
||||
}
|
||||
|
||||
template <typename DerivedDetectorServer>
|
||||
ProcessedResult DetectorServer<DerivedDetectorServer>::set_source_udp_mac(
|
||||
ServerInterface &socket) {
|
||||
|
||||
uint64_t newsrcudpMac;
|
||||
|
||||
try {
|
||||
(void)socket.Receive<uint64_t>(newsrcudpMac);
|
||||
} catch (const SocketError &e) {
|
||||
LOG(logERROR) << "Failed to receive new source UDP MAC address: "
|
||||
<< e.what();
|
||||
return return_fail("Failed to receive new source UDP MAC address: " +
|
||||
std::string(e.what()));
|
||||
}
|
||||
|
||||
try {
|
||||
getImpl()->set_source_udp_mac(newsrcudpMac);
|
||||
} catch (const std::exception &e) {
|
||||
LOG(logERROR) << "Failed to set source UDP MAC address: " << e.what();
|
||||
return_fail("Failed to set source UDP MAC address: " +
|
||||
std::string(e.what()));
|
||||
}
|
||||
|
||||
return send_ok(socket);
|
||||
}
|
||||
|
||||
template <typename DerivedDetectorServer>
|
||||
ProcessedResult DetectorServer<DerivedDetectorServer>::set_source_udp_ip(
|
||||
ServerInterface &socket) {
|
||||
|
||||
uint32_t newSrcIp;
|
||||
|
||||
try {
|
||||
(void)socket.Receive(newSrcIp);
|
||||
} catch (const SocketError &e) {
|
||||
auto error_message = "Failed to receive new source UDP IP address: " +
|
||||
std::string(e.what());
|
||||
LOG(logERROR) << error_message;
|
||||
|
||||
return return_fail(error_message);
|
||||
}
|
||||
|
||||
impl->set_source_udp_ip(newSrcIp);
|
||||
return send_ok(socket);
|
||||
}
|
||||
|
||||
template <typename DerivedDetectorServer>
|
||||
ProcessedResult DetectorServer<DerivedDetectorServer>::get_source_udp_ip(
|
||||
ServerInterface &socket) const {
|
||||
uint32_t src_UdpIp = impl->get_source_udp_ip();
|
||||
return send_result(socket, src_UdpIp);
|
||||
}
|
||||
|
||||
template <typename DerivedDetectorServer>
|
||||
ProcessedResult DetectorServer<DerivedDetectorServer>::set_destination_udp_mac(
|
||||
ServerInterface &socket) {
|
||||
uint64_t newDstMac;
|
||||
|
||||
try {
|
||||
(void)socket.Receive<uint64_t>(newDstMac);
|
||||
} catch (const SocketError &e) {
|
||||
auto error_message =
|
||||
"Failed to receive new destination UDP MAC address: " +
|
||||
std::string(e.what());
|
||||
LOG(logERROR) << error_message;
|
||||
return return_fail(error_message);
|
||||
}
|
||||
|
||||
impl->set_destination_udp_mac(newDstMac);
|
||||
|
||||
return send_ok(socket);
|
||||
}
|
||||
|
||||
template <typename DerivedDetectorServer>
|
||||
ProcessedResult DetectorServer<DerivedDetectorServer>::get_destination_udp_mac(
|
||||
ServerInterface &socket) const {
|
||||
|
||||
auto dstUdpMac = impl->get_destination_udp_mac();
|
||||
return send_result(socket, dstUdpMac);
|
||||
}
|
||||
|
||||
template <typename DerivedDetectorServer>
|
||||
ProcessedResult DetectorServer<DerivedDetectorServer>::set_destination_udp_ip(
|
||||
ServerInterface &socket) {
|
||||
uint32_t newDstIp;
|
||||
|
||||
try {
|
||||
(void)socket.Receive(newDstIp);
|
||||
} catch (const SocketError &e) {
|
||||
auto error_message =
|
||||
"Failed to receive new destination UDP IP address: " +
|
||||
std::string(e.what());
|
||||
LOG(logERROR) << error_message;
|
||||
return return_fail(error_message);
|
||||
}
|
||||
|
||||
impl->set_destination_udp_ip(newDstIp);
|
||||
|
||||
return send_ok(socket);
|
||||
}
|
||||
|
||||
template <typename DerivedDetectorServer>
|
||||
ProcessedResult DetectorServer<DerivedDetectorServer>::get_destination_udp_ip(
|
||||
ServerInterface &socket) const {
|
||||
|
||||
uint32_t dstUdpIp = impl->get_destination_udp_ip();
|
||||
return send_result(socket, dstUdpIp);
|
||||
}
|
||||
|
||||
template <typename DerivedDetectorServer>
|
||||
ProcessedResult DetectorServer<DerivedDetectorServer>::set_destination_udp_port(
|
||||
ServerInterface &socket) {
|
||||
uint16_t newDstPort;
|
||||
|
||||
try {
|
||||
(void)socket.Receive(newDstPort);
|
||||
} catch (const SocketError &e) {
|
||||
auto error_message =
|
||||
"Failed to receive new destination UDP port number: " +
|
||||
std::string(e.what());
|
||||
LOG(logERROR) << error_message;
|
||||
return return_fail(error_message);
|
||||
}
|
||||
|
||||
impl->set_destination_udp_port(newDstPort);
|
||||
|
||||
return send_ok(socket);
|
||||
}
|
||||
|
||||
template <typename DerivedDetectorServer>
|
||||
ProcessedResult DetectorServer<DerivedDetectorServer>::get_destination_udp_port(
|
||||
ServerInterface &socket) const {
|
||||
uint16_t dstUdpPort = impl->get_destination_udp_port();
|
||||
return send_result(socket, dstUdpPort);
|
||||
};
|
||||
|
||||
template <typename DerivedDetectorServer>
|
||||
ProcessedResult DetectorServer<DerivedDetectorServer>::get_num_frames(
|
||||
ServerInterface &socket) const {
|
||||
uint64_t num_frames{};
|
||||
try {
|
||||
num_frames = getImpl()->get_num_frames();
|
||||
} catch (const std::exception &e) {
|
||||
auto error_message =
|
||||
"Failed to get number of frames: " + std::string(e.what());
|
||||
LOG(logERROR) << error_message;
|
||||
return return_fail(error_message);
|
||||
}
|
||||
return send_result(socket, num_frames);
|
||||
}
|
||||
|
||||
template <typename DerivedDetectorServer>
|
||||
ProcessedResult
|
||||
DetectorServer<DerivedDetectorServer>::set_num_frames(ServerInterface &socket) {
|
||||
int64_t num_frames{};
|
||||
try {
|
||||
(void)socket.Receive(num_frames);
|
||||
} catch (const SocketError &e) {
|
||||
auto error_message =
|
||||
"Failed to receive number of frames: " + std::string(e.what());
|
||||
LOG(logERROR) << error_message;
|
||||
return return_fail(error_message);
|
||||
}
|
||||
try {
|
||||
getImpl()->set_num_frames(num_frames);
|
||||
} catch (const std::exception &e) {
|
||||
auto error_message =
|
||||
"Failed to set number of frames: " + std::string(e.what());
|
||||
LOG(logERROR) << error_message;
|
||||
return return_fail(error_message);
|
||||
}
|
||||
return send_ok(socket);
|
||||
}
|
||||
|
||||
template <typename DerivedDetectorServer>
|
||||
ProcessedResult DetectorServer<DerivedDetectorServer>::get_num_triggers(
|
||||
ServerInterface &socket) const {
|
||||
uint64_t num_triggers{};
|
||||
try {
|
||||
num_triggers = static_cast<uint64_t>(getImpl()->get_num_triggers());
|
||||
} catch (const std::exception &e) {
|
||||
auto error_message =
|
||||
"Failed to get number of triggers: " + std::string(e.what());
|
||||
LOG(logERROR) << error_message;
|
||||
return return_fail(error_message);
|
||||
}
|
||||
return send_result(socket, num_triggers);
|
||||
}
|
||||
|
||||
template <typename DerivedDetectorServer>
|
||||
ProcessedResult DetectorServer<DerivedDetectorServer>::set_num_triggers(
|
||||
ServerInterface &socket) {
|
||||
int64_t num_triggers{};
|
||||
try {
|
||||
(void)socket.Receive(num_triggers);
|
||||
} catch (const SocketError &e) {
|
||||
auto error_message =
|
||||
"Failed to receive number of triggers: " + std::string(e.what());
|
||||
LOG(logERROR) << error_message;
|
||||
return return_fail(error_message);
|
||||
}
|
||||
try {
|
||||
getImpl()->set_num_triggers(num_triggers);
|
||||
} catch (const std::exception &e) {
|
||||
auto error_message =
|
||||
"Failed to set number of triggers: " + std::string(e.what());
|
||||
LOG(logERROR) << error_message;
|
||||
return return_fail(error_message);
|
||||
}
|
||||
return send_ok(socket);
|
||||
}
|
||||
|
||||
template <typename DerivedDetectorServer>
|
||||
ProcessedResult DetectorServer<DerivedDetectorServer>::get_version(
|
||||
ServerInterface &socket) const {
|
||||
|
||||
auto version =
|
||||
getImpl()->get_server_version(); // TODO: get Impl from derived server
|
||||
|
||||
char version_cstr[MAX_STR_LENGTH]{};
|
||||
std::snprintf(version_cstr, sizeof(version_cstr), "%s",
|
||||
version.c_str()); // ensures temination
|
||||
LOG(TLogLevel::logDEBUG) << "Server Version: " << version;
|
||||
return send_result(
|
||||
socket,
|
||||
version_cstr); // TODO: check what would be possible return codes!!!
|
||||
}
|
||||
|
||||
template <typename DerivedDetectorServer>
|
||||
ProcessedResult DetectorServer<DerivedDetectorServer>::get_num_udp_interfaces(
|
||||
ServerInterface &socket) const {
|
||||
int num_udp_interfaces = getImpl()->get_num_udp_interfaces();
|
||||
|
||||
return send_result(socket, num_udp_interfaces);
|
||||
}
|
||||
|
||||
template <typename DerivedDetectorServer>
|
||||
ProcessedResult DetectorServer<DerivedDetectorServer>::get_detector_type(
|
||||
ServerInterface &socket) const {
|
||||
uint32_t detectortype = getImpl()->get_detector_type();
|
||||
return send_result(socket, detectortype);
|
||||
}
|
||||
|
||||
template <typename DerivedDetectorServer>
|
||||
ProcessedResult DetectorServer<DerivedDetectorServer>::get_receiver_parameters(
|
||||
ServerInterface &socket) const {
|
||||
|
||||
slsDetectorDefs::rxParameters rx_params =
|
||||
getImpl()->get_receiver_parameters();
|
||||
|
||||
return send_result(socket, rx_params);
|
||||
}
|
||||
|
||||
template <typename DerivedDetectorServer>
|
||||
ProcessedResult DetectorServer<DerivedDetectorServer>::get_run_status(
|
||||
ServerInterface &socket) const {
|
||||
|
||||
slsDetectorDefs::runStatus status = getImpl()->get_run_status();
|
||||
|
||||
return send_result(socket, status);
|
||||
}
|
||||
|
||||
template <typename DerivedDetectorServer>
|
||||
ProcessedResult DetectorServer<DerivedDetectorServer>::initial_checks(
|
||||
ServerInterface &socket) const {
|
||||
auto detectorsetupstatus = getImpl()->get_detector_setup_status();
|
||||
|
||||
// TODO: should there be a time limit?
|
||||
while (detectorsetupstatus.setup_status ==
|
||||
detector_setup_status::NOT_SETUP) {
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
detectorsetupstatus = getImpl()->get_detector_setup_status();
|
||||
}
|
||||
if (detectorsetupstatus.setup_status ==
|
||||
detector_setup_status::FAILED_SETUP) {
|
||||
return return_fail("Initial checks failed: " +
|
||||
detectorsetupstatus.error_message);
|
||||
} else {
|
||||
return send_result<bool>(socket, true);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename DerivedDetectorServer>
|
||||
ProcessedResult
|
||||
DetectorServer<DerivedDetectorServer>::set_module_position_and_update_srcudpmac(
|
||||
ServerInterface &socket) {
|
||||
|
||||
std::array<int, 2> position_info{}; // [num_modules_in_y, module_index]
|
||||
try {
|
||||
(void)socket.Receive(position_info.data(),
|
||||
position_info.size() * sizeof(int));
|
||||
} catch (const SocketError &e) {
|
||||
LOG(logERROR)
|
||||
<< "Failed to receive num modules in y dimension and module index: "
|
||||
<< e.what();
|
||||
return_fail(
|
||||
"Failed to receive num modules in y dimension and module index: " +
|
||||
std::string(e.what()));
|
||||
}
|
||||
|
||||
try {
|
||||
getImpl()->set_module_position_and_update_srcudpmac(position_info);
|
||||
} catch (const std::exception &e) {
|
||||
return_fail("Failed to set module position: " + std::string(e.what()));
|
||||
}
|
||||
|
||||
return send_ok(socket);
|
||||
}
|
||||
|
||||
} // namespace sls
|
||||
@@ -0,0 +1,109 @@
|
||||
#pragma once
|
||||
#include "sls/SharedMemory.h"
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
|
||||
namespace sls {
|
||||
|
||||
// TODO move to defs?
|
||||
/// @brief struct saving udp details (one UDP port per module)
|
||||
struct UDPInfo {
|
||||
uint16_t srcport{};
|
||||
uint16_t dstport{};
|
||||
uint64_t srcmac{};
|
||||
uint64_t dstmac{};
|
||||
uint32_t srcip{};
|
||||
uint32_t dstip{};
|
||||
};
|
||||
|
||||
/// @brief struct to store detector setup status
|
||||
struct detector_setup_status {
|
||||
|
||||
enum SETUP_STATUS : uint8_t {
|
||||
FAILED_SETUP = 0,
|
||||
SUCCESSFUL_SETUP = 1,
|
||||
NOT_SETUP = 2
|
||||
};
|
||||
|
||||
/// @brief true if setupDetector() was successful, false otherwise
|
||||
SETUP_STATUS setup_status{NOT_SETUP};
|
||||
/// @brief error message if setupDetector() failed, empty otherwise
|
||||
std::string error_message{};
|
||||
};
|
||||
|
||||
/// @brief Shared memory structure for stop server to store run status
|
||||
struct acquisitionStatus {
|
||||
|
||||
/* FIXED PATTERN FOR STATIC FUNCTIONS. DO NOT CHANGE, ONLY APPEND ------*/
|
||||
int shmversion;
|
||||
|
||||
bool isValid{true}; // false if freed to block access from python or c++ api
|
||||
|
||||
std::atomic<slsDetectorDefs::runStatus> scanStatus{
|
||||
slsDetectorDefs::runStatus::IDLE}; // idle, running or error
|
||||
std::atomic<bool> scanStop{false};
|
||||
|
||||
// TODO: only neccessary for virtual, maybe have two shared memory
|
||||
// structures, one for virtual
|
||||
std::atomic<slsDetectorDefs::runStatus> status{
|
||||
slsDetectorDefs::runStatus::IDLE};
|
||||
std::atomic<bool> stop{false};
|
||||
};
|
||||
|
||||
template <bool isStopServer> class DetectorServerImpl {
|
||||
|
||||
public:
|
||||
DetectorServerImpl();
|
||||
~DetectorServerImpl();
|
||||
|
||||
bool get_update_mode() const;
|
||||
|
||||
uint64_t get_source_udp_mac() const;
|
||||
|
||||
void set_source_udp_ip(const uint32_t srcip);
|
||||
|
||||
uint32_t get_source_udp_ip() const;
|
||||
|
||||
void set_destination_udp_ip(const uint32_t dstip);
|
||||
|
||||
uint32_t get_destination_udp_ip() const;
|
||||
|
||||
void set_destination_udp_mac(const uint64_t dstmac);
|
||||
|
||||
uint64_t get_destination_udp_mac() const;
|
||||
|
||||
void set_destination_udp_port(const uint16_t dstport);
|
||||
|
||||
uint16_t get_destination_udp_port() const;
|
||||
|
||||
detector_setup_status get_detector_setup_status() const;
|
||||
|
||||
protected:
|
||||
std::array<UDPInfo, 1>
|
||||
udpDetails{}; // TODO: for now only one receiver per module
|
||||
|
||||
/// @brief TODO what is this?
|
||||
bool updateMode{
|
||||
false}; // what should the default be - can update module size etc.
|
||||
|
||||
/// @brief shared mempory with aquisition status
|
||||
mutable SharedMemory<acquisitionStatus> shm{
|
||||
0, 0}; // TODO: is mutable really neccessary?
|
||||
|
||||
/// @brief sets source UDP MAC address in udpDetails and updates udp
|
||||
/// header
|
||||
/// @param srcmac
|
||||
void updateSrcMacAddress(const uint64_t srcmac);
|
||||
|
||||
/// @brief true if setupDetector() was successful, false otherwise
|
||||
detector_setup_status detectorSetupStatus{};
|
||||
|
||||
/// @brief true if the derived server is a stop server, false otherwise
|
||||
static constexpr bool stop_server = isStopServer;
|
||||
|
||||
private:
|
||||
/// @brief creates and maps shared memory
|
||||
void createSharedMemory();
|
||||
};
|
||||
|
||||
} // namespace sls
|
||||
@@ -0,0 +1,68 @@
|
||||
#pragma once
|
||||
#include "fmt/format.h"
|
||||
#include "sls/logger.h"
|
||||
#include "sls/sls_detector_exceptions.h"
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
namespace sls {
|
||||
|
||||
/// @brief class to handle memory mapping and access for hardware IP cores
|
||||
class HardwareMemoryModel {
|
||||
|
||||
public:
|
||||
HardwareMemoryModel(const uint32_t IPcore_base_address,
|
||||
const size_t size_memory_space_);
|
||||
|
||||
~HardwareMemoryModel();
|
||||
|
||||
void mapToMemory();
|
||||
|
||||
void unmapMemory();
|
||||
|
||||
volatile uint32_t *getMappedMemoryPtr() const;
|
||||
|
||||
private:
|
||||
volatile uint32_t *mapped_memory_ptr{nullptr};
|
||||
|
||||
/// @brief offset of the IP core base address in the memory space, used for
|
||||
/// mapping
|
||||
const size_t IPCore_base_address{0};
|
||||
|
||||
/// @brief size mapped memory region [bytes]
|
||||
const size_t size_memory_space{0};
|
||||
};
|
||||
|
||||
/// @brief class to handle memory mapping and access for virtual IP cores (e.g.
|
||||
/// use software implementation of memory)
|
||||
template <typename DataType> class VirtualMemoryModel {
|
||||
|
||||
public:
|
||||
// IPcore_base_address is not used for virtual memory model but kept for
|
||||
// compatibility with HardwareMemoryModel interface
|
||||
VirtualMemoryModel(const uint32_t IPcore_base_address,
|
||||
const size_t size_memory_space_)
|
||||
: size_memory_space(size_memory_space_) {
|
||||
(void)IPcore_base_address; // suppress unused parameter warning
|
||||
}
|
||||
|
||||
~VirtualMemoryModel() = default;
|
||||
|
||||
void mapToMemory() {
|
||||
mapped_memory.resize(
|
||||
size_memory_space /
|
||||
sizeof(DataType)); // TODO: should it be zero initialized?
|
||||
}
|
||||
|
||||
DataType *getMappedMemoryPtr() { return mapped_memory.data(); }
|
||||
|
||||
const DataType *getMappedMemoryPtr() const { return mapped_memory.data(); }
|
||||
|
||||
private:
|
||||
std::vector<DataType> mapped_memory{};
|
||||
|
||||
/// @brief size mapped memory region [bytes]
|
||||
const size_t size_memory_space{0};
|
||||
};
|
||||
|
||||
} // namespace sls
|
||||
@@ -0,0 +1,62 @@
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
#include <exception>
|
||||
#include <fmt/format.h>
|
||||
#include <string_view>
|
||||
|
||||
namespace sls {
|
||||
|
||||
enum class IPCore : uint32_t; // forward declaration of IPCore enum class
|
||||
|
||||
/// @brief struct representing 32 bit register
|
||||
struct Register {
|
||||
/// @brief IP core address space
|
||||
const IPCore ip_core{}; // TODO replace by enum type
|
||||
|
||||
/// @brief Offset of the register in bytes from the base address of the IP
|
||||
/// core
|
||||
const uint32_t offset_in_bytes{};
|
||||
};
|
||||
|
||||
struct RegisterField {
|
||||
/// @brief Register to which the field belongs
|
||||
const Register register_{};
|
||||
|
||||
/// @brief Bit position of the least significant bit of the field in the
|
||||
/// register
|
||||
const uint32_t bit_position{};
|
||||
|
||||
/// @brief Bitmask for the field
|
||||
const uint32_t bitmask{};
|
||||
};
|
||||
|
||||
// TODO: maybe static member function of RegisterField?
|
||||
template <typename T>
|
||||
void setRegisterField(uint32_t ®istervalue, const RegisterField ®_field,
|
||||
T field_value) {
|
||||
|
||||
if (field_value > static_cast<T>(reg_field.bitmask)) {
|
||||
throw std::invalid_argument(
|
||||
fmt::format("Value {} cannot fit in field with bitmask {}",
|
||||
field_value, reg_field.bitmask));
|
||||
}
|
||||
// Clear the bits corresponding to the field
|
||||
registervalue &= ~(reg_field.bitmask << reg_field.bit_position);
|
||||
// Set the new value for the field
|
||||
registervalue |= (static_cast<uint32_t>(field_value) & reg_field.bitmask)
|
||||
<< reg_field.bit_position;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T getRegisterField(const uint32_t ®istervalue,
|
||||
const RegisterField ®_field) {
|
||||
// Extract the bits corresponding to the field and shift them to get the
|
||||
// value
|
||||
|
||||
auto field_value =
|
||||
(registervalue >> reg_field.bit_position) & reg_field.bitmask;
|
||||
|
||||
return static_cast<T>(field_value);
|
||||
}
|
||||
|
||||
} // namespace sls
|
||||
+32
-7
@@ -10,6 +10,31 @@
|
||||
|
||||
namespace sls {
|
||||
|
||||
using ReturnCode = slsDetectorDefs::ReturnCode;
|
||||
|
||||
struct ProcessedResult {
|
||||
/// @brief return code of the processed command
|
||||
slsDetectorDefs::ReturnCode returnCode{};
|
||||
/// @brief error message to be sent to client in case of failure
|
||||
std::string error_message{};
|
||||
};
|
||||
|
||||
// communication helpers
|
||||
inline ProcessedResult return_fail(std::string_view error_message) {
|
||||
return ProcessedResult{ReturnCode::FAIL,
|
||||
static_cast<std::string>(error_message)};
|
||||
}
|
||||
|
||||
inline ProcessedResult send_ok(ServerInterface &socket) {
|
||||
return ProcessedResult{
|
||||
static_cast<ReturnCode>(socket.Send(ReturnCode::OK))};
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline ProcessedResult send_result(ServerInterface &socket, const T &value) {
|
||||
return ProcessedResult{static_cast<ReturnCode>(socket.sendResult(value))};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief TCPInterface class handles communication and processing of commands
|
||||
* from Client to Server.
|
||||
@@ -19,9 +44,10 @@ class TCPInterface {
|
||||
public:
|
||||
~TCPInterface();
|
||||
|
||||
TCPInterface(std::function<slsDetectorDefs::ReturnCode(
|
||||
const detFuncs &, ServerInterface &)> &processFunction_,
|
||||
const uint16_t portNumber = DEFAULT_TCP_CNTRL_PORTNO);
|
||||
TCPInterface(
|
||||
std::function<ProcessedResult(const detFuncs &, ServerInterface &)>
|
||||
&processFunction_,
|
||||
const uint16_t portNumber = DEFAULT_TCP_CNTRL_PORTNO);
|
||||
|
||||
/// @brief creates tcp thread
|
||||
void startTCPServer();
|
||||
@@ -40,12 +66,11 @@ class TCPInterface {
|
||||
* @param function_id The ID of the function recived by the server and to
|
||||
* be executed
|
||||
*/
|
||||
slsDetectorDefs::ReturnCode processReceivedData(const detFuncs function_id,
|
||||
ServerInterface &socket);
|
||||
ProcessedResult processReceivedData(const detFuncs function_id,
|
||||
ServerInterface &socket);
|
||||
|
||||
/// @brief map of function IDs and corresponding functions
|
||||
std::function<slsDetectorDefs::ReturnCode(const detFuncs &,
|
||||
ServerInterface &)>
|
||||
std::function<ProcessedResult(const detFuncs &, ServerInterface &)>
|
||||
processFunction;
|
||||
|
||||
/// @brief TCP/IP port number for the detector server
|
||||
@@ -0,0 +1,19 @@
|
||||
/** @file Defs.hpp
|
||||
* @brief this file contains some definitions used in the slsDetectorServer_cpp
|
||||
* project.
|
||||
*/
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
|
||||
namespace sls {
|
||||
|
||||
/// @brief Individual/Group bit offset in a 48 bit MAC address - 0 indicates
|
||||
/// unicast mac address
|
||||
constexpr uint8_t INDIVIDUAL_GROUP_BIT_OFFSET = 40; // 1000 0000
|
||||
|
||||
/// @brief Universal/Local bit offset in a 48 bit MAC address - 1 indicates
|
||||
/// locally administered mac address, 0 indicates universally administered mac
|
||||
/// address
|
||||
constexpr uint8_t UNIVERSAL_LOCAL_BIT_OFFSET = 41; // 0100 0000
|
||||
|
||||
} // namespace sls
|
||||
@@ -0,0 +1,64 @@
|
||||
#pragma once
|
||||
#include "Defs.hpp"
|
||||
#include "DetectorServerImpl.hpp"
|
||||
#include "sls/SharedMemory.h"
|
||||
#include "sls/sls_detector_defs.h"
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
|
||||
namespace sls {
|
||||
|
||||
constexpr uint64_t mac_mask = 0xffffffffffff0000;
|
||||
constexpr uint8_t offset_row_position_in_mac = 8; // given in bits
|
||||
constexpr uint8_t offset_col_position_in_mac = 0; // given in bits
|
||||
|
||||
/// @brief generates a random locally administered unicast MAC address for the
|
||||
/// source UDP
|
||||
/// @return generated MAC address
|
||||
inline uint64_t generateRandomMacAddress() {
|
||||
uint64_t mac =
|
||||
0xAA0000000000; // locally administered unicast address (0xA: 0b1010) //
|
||||
// TODO maybe 0x02000000000 better?
|
||||
for (int i = 2; i < 5; ++i) {
|
||||
mac |= (static_cast<uint64_t>(std::rand() % 256) << (i * 8));
|
||||
}
|
||||
return mac;
|
||||
}
|
||||
|
||||
/// @brief generates a MAC address based on the module's row and column
|
||||
/// position, last 32 bits of the MAC address are set to module_row and
|
||||
/// module_col
|
||||
/// @param module_row
|
||||
/// @param module_col
|
||||
/// @return generated MAC address
|
||||
inline uint64_t generateMacAddressfromModulePosition(const uint8_t module_row,
|
||||
const uint8_t module_col) {
|
||||
|
||||
uint64_t newSrcMac = generateRandomMacAddress();
|
||||
newSrcMac = (newSrcMac & mac_mask) |
|
||||
(module_row << offset_row_position_in_mac) |
|
||||
(module_col << offset_col_position_in_mac);
|
||||
|
||||
return newSrcMac;
|
||||
}
|
||||
|
||||
/// @brief check that mac is unicast and locally administered
|
||||
/// @param mac
|
||||
/// @return true if mac is valid, false otherwise
|
||||
inline bool isValidMac(const uint64_t mac) {
|
||||
if ((mac << INDIVIDUAL_GROUP_BIT_OFFSET) == 0 &&
|
||||
(mac << UNIVERSAL_LOCAL_BIT_OFFSET) == 1) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline void freeSharedMemory() {
|
||||
SharedMemory<acquisitionStatus> shm(0, -1, "server");
|
||||
|
||||
if (shm.exists()) {
|
||||
shm.removeSharedMemory();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace sls
|
||||
@@ -0,0 +1,57 @@
|
||||
#pragma once
|
||||
#include <type_traits>
|
||||
|
||||
namespace sls {
|
||||
|
||||
// forward declares
|
||||
template <bool isStopServer> class MatterhornServer;
|
||||
|
||||
template <bool isStopServer> class VirtualMatterhornServer;
|
||||
|
||||
template <bool isStopServer> class MatterhornServerImpl;
|
||||
|
||||
template <bool isStopServer> class VirtualMatterhornServerImpl;
|
||||
|
||||
template <typename DerivedServer> class BaseMatterhornServer;
|
||||
|
||||
// type trait to get implementation type
|
||||
|
||||
template <typename DetectorServer> struct implementation_type_trait;
|
||||
|
||||
template <bool isStopServer>
|
||||
struct implementation_type_trait<
|
||||
BaseMatterhornServer<MatterhornServer<isStopServer>>> {
|
||||
using ImplType = MatterhornServerImpl<isStopServer>;
|
||||
};
|
||||
|
||||
template <bool isStopServer>
|
||||
struct implementation_type_trait<
|
||||
BaseMatterhornServer<VirtualMatterhornServer<isStopServer>>> {
|
||||
using ImplType = VirtualMatterhornServerImpl<isStopServer>;
|
||||
};
|
||||
|
||||
// type trait to get stop server flag from Detector Server
|
||||
|
||||
template <typename DetectorServerImpl>
|
||||
struct is_stop_server : std::false_type {};
|
||||
|
||||
template <>
|
||||
struct is_stop_server<VirtualMatterhornServerImpl<true>> : std::true_type {};
|
||||
|
||||
template <>
|
||||
struct is_stop_server<MatterhornServerImpl<true>> : std::true_type {};
|
||||
|
||||
template <>
|
||||
struct is_stop_server<VirtualMatterhornServer<true>> : std::true_type {};
|
||||
|
||||
template <> struct is_stop_server<MatterhornServer<true>> : std::true_type {};
|
||||
|
||||
template <>
|
||||
struct is_stop_server<BaseMatterhornServer<VirtualMatterhornServer<true>>>
|
||||
: std::true_type {};
|
||||
|
||||
template <>
|
||||
struct is_stop_server<BaseMatterhornServer<MatterhornServer<true>>>
|
||||
: std::true_type {};
|
||||
|
||||
} // namespace sls
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "CommandLineOptions.h"
|
||||
#include "CommandLineOptions.hpp"
|
||||
#include "sls/ToString.h"
|
||||
#include "sls/sls_detector_exceptions.h"
|
||||
|
||||
|
||||
@@ -0,0 +1,117 @@
|
||||
#include "DetectorServerImpl.hpp"
|
||||
#include "sls/logger.h"
|
||||
#include "sls/sls_detector_exceptions.h"
|
||||
#include <fmt/format.h>
|
||||
|
||||
namespace sls {
|
||||
|
||||
template class DetectorServerImpl<true>; // forward declare
|
||||
template class DetectorServerImpl<false>; // forward declare
|
||||
|
||||
template <bool isStopServer>
|
||||
DetectorServerImpl<isStopServer>::DetectorServerImpl() {
|
||||
udpDetails[0].srcport = DEFAULT_UDP_SRC_PORTNO;
|
||||
udpDetails[0].dstport = DEFAULT_UDP_DST_PORTNO;
|
||||
|
||||
createSharedMemory();
|
||||
}
|
||||
|
||||
template <bool isStopServer>
|
||||
DetectorServerImpl<isStopServer>::~DetectorServerImpl() {
|
||||
shm.removeSharedMemory();
|
||||
}
|
||||
|
||||
template <bool isStopServer>
|
||||
void DetectorServerImpl<isStopServer>::createSharedMemory() {
|
||||
shm = SharedMemory<acquisitionStatus>(0, -1, "server");
|
||||
|
||||
if (shm.exists()) {
|
||||
shm.openSharedMemory(true); // stop server
|
||||
} else {
|
||||
LOG(logINFOBLUE) << "Creating shared memory for acquisition status";
|
||||
try {
|
||||
shm.createSharedMemory();
|
||||
} catch (const SharedMemoryAlreadyExistsError &e) {
|
||||
shm.openSharedMemory(true); // potential race conditions between
|
||||
// stop and control server
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <bool isStopServer>
|
||||
void DetectorServerImpl<isStopServer>::updateSrcMacAddress(
|
||||
const uint64_t srcmac) {
|
||||
LOG(logINFO) << "Updating source MAC address to: "
|
||||
<< fmt::format("{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}",
|
||||
(srcmac >> 40) & 0xff, (srcmac >> 32) & 0xff,
|
||||
(srcmac >> 24) & 0xff, (srcmac >> 16) & 0xff,
|
||||
(srcmac >> 8) & 0xff, srcmac & 0xff);
|
||||
|
||||
udpDetails[0].srcmac = srcmac;
|
||||
|
||||
// TODO: update UDP header with new source MAC address
|
||||
|
||||
// TODO: do i need to keep track of the configured member ?
|
||||
}
|
||||
|
||||
template <bool isStopServer>
|
||||
bool DetectorServerImpl<isStopServer>::get_update_mode() const {
|
||||
return updateMode;
|
||||
}
|
||||
|
||||
template <bool isStopServer>
|
||||
uint64_t DetectorServerImpl<isStopServer>::get_source_udp_mac() const {
|
||||
return udpDetails[0].srcmac;
|
||||
}
|
||||
|
||||
template <bool isStopServer>
|
||||
void DetectorServerImpl<isStopServer>::set_source_udp_ip(const uint32_t srcip) {
|
||||
udpDetails[0].srcip = srcip;
|
||||
}
|
||||
|
||||
template <bool isStopServer>
|
||||
uint32_t DetectorServerImpl<isStopServer>::get_source_udp_ip() const {
|
||||
return udpDetails[0].srcip;
|
||||
}
|
||||
|
||||
template <bool isStopServer>
|
||||
void DetectorServerImpl<isStopServer>::set_destination_udp_ip(
|
||||
const uint32_t dstip) {
|
||||
udpDetails[0].dstip = dstip;
|
||||
}
|
||||
|
||||
template <bool isStopServer>
|
||||
uint32_t DetectorServerImpl<isStopServer>::get_destination_udp_ip() const {
|
||||
return udpDetails[0].dstip;
|
||||
}
|
||||
|
||||
template <bool isStopServer>
|
||||
void DetectorServerImpl<isStopServer>::set_destination_udp_mac(
|
||||
const uint64_t dstmac) {
|
||||
// TODO: configuremac, check unicast address
|
||||
udpDetails[0].dstmac = dstmac;
|
||||
}
|
||||
|
||||
template <bool isStopServer>
|
||||
uint64_t DetectorServerImpl<isStopServer>::get_destination_udp_mac() const {
|
||||
return udpDetails[0].dstmac;
|
||||
}
|
||||
|
||||
template <bool isStopServer>
|
||||
void DetectorServerImpl<isStopServer>::set_destination_udp_port(
|
||||
const uint16_t dstport) {
|
||||
udpDetails[0].dstport = dstport;
|
||||
}
|
||||
|
||||
template <bool isStopServer>
|
||||
uint16_t DetectorServerImpl<isStopServer>::get_destination_udp_port() const {
|
||||
return udpDetails[0].dstport;
|
||||
}
|
||||
|
||||
template <bool isStopServer>
|
||||
detector_setup_status
|
||||
DetectorServerImpl<isStopServer>::get_detector_setup_status() const {
|
||||
return detectorSetupStatus;
|
||||
}
|
||||
|
||||
} // namespace sls
|
||||
@@ -0,0 +1,62 @@
|
||||
#include "MemoryModel.hpp"
|
||||
#include <fcntl.h>
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
#include <stdio.h>
|
||||
#include <sys/mman.h>
|
||||
#include <unistd.h>
|
||||
|
||||
namespace sls {
|
||||
|
||||
HardwareMemoryModel::HardwareMemoryModel(const uint32_t IPcore_base_address,
|
||||
const size_t size_memory_space_)
|
||||
: IPCore_base_address(IPcore_base_address),
|
||||
size_memory_space(size_memory_space_) {}
|
||||
|
||||
void HardwareMemoryModel::mapToMemory() {
|
||||
|
||||
int fd = open("/dev/mem", O_RDWR | O_SYNC, 0);
|
||||
|
||||
if (fd == -1) {
|
||||
throw RuntimeError("Can't find /dev/mem");
|
||||
}
|
||||
|
||||
auto void_mmap_ptr =
|
||||
mmap(nullptr, size_memory_space, PROT_READ | PROT_WRITE, MAP_SHARED, fd,
|
||||
IPCore_base_address);
|
||||
|
||||
if (void_mmap_ptr == MAP_FAILED) {
|
||||
throw RuntimeError(
|
||||
fmt::format("Failed to map base address: {}",
|
||||
IPCore_base_address)); // TODO: needs ToString
|
||||
}
|
||||
|
||||
mapped_memory_ptr = reinterpret_cast<volatile uint32_t *>(void_mmap_ptr);
|
||||
|
||||
close(fd);
|
||||
}
|
||||
|
||||
volatile uint32_t *HardwareMemoryModel::getMappedMemoryPtr() const {
|
||||
return mapped_memory_ptr;
|
||||
}
|
||||
|
||||
void HardwareMemoryModel::unmapMemory() {
|
||||
|
||||
if (mapped_memory_ptr != nullptr) {
|
||||
if (munmap(reinterpret_cast<void *>(
|
||||
const_cast<uint32_t *>(mapped_memory_ptr)),
|
||||
size_memory_space) < 0) {
|
||||
LOG(logWARNING)
|
||||
<< fmt::format("Failed to unmap memory for IP core: {}",
|
||||
IPCore_base_address); // TODO: needs ToString
|
||||
}
|
||||
mapped_memory_ptr = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
HardwareMemoryModel::~HardwareMemoryModel() {
|
||||
LOG(logDEBUG1) << "HardwareMemoryModel destructor called, unmapping memory";
|
||||
unmapMemory();
|
||||
}
|
||||
|
||||
} // namespace sls
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "TCPInterface.h"
|
||||
#include "TCPInterface.hpp"
|
||||
|
||||
#include "fmt/format.h"
|
||||
#include "sls/logger.h"
|
||||
@@ -8,8 +8,8 @@
|
||||
namespace sls {
|
||||
|
||||
TCPInterface::TCPInterface(
|
||||
std::function<slsDetectorDefs::ReturnCode(
|
||||
const detFuncs &, ServerInterface &)> &processFunction_,
|
||||
std::function<ProcessedResult(const detFuncs &, ServerInterface &)>
|
||||
&processFunction_,
|
||||
const uint16_t portNumber_)
|
||||
: processFunction(processFunction_), portNumber(portNumber_),
|
||||
server(portNumber_) {
|
||||
@@ -44,19 +44,23 @@ void TCPInterface::startTCPServerClientConnection() {
|
||||
auto socket = server.accept();
|
||||
try {
|
||||
|
||||
socket.Receive(function_id);
|
||||
(void)socket.Receive(function_id);
|
||||
if (function_id < 0 || function_id >= NUM_DET_FUNCTIONS) {
|
||||
throw RuntimeError(fmt::format(
|
||||
"{}:{}", UNRECOGNIZED_FNUM_ENUM,
|
||||
getFunctionNameFromEnum((enum detFuncs)function_id)));
|
||||
}
|
||||
auto returncode = processReceivedData(
|
||||
auto processedResult = processReceivedData(
|
||||
static_cast<detFuncs>(function_id), socket);
|
||||
|
||||
if (returncode == slsDetectorDefs::ReturnCode::FAIL) {
|
||||
// TODO: should technically fail before
|
||||
if (processedResult.returnCode ==
|
||||
slsDetectorDefs::ReturnCode::FAIL) {
|
||||
throw RuntimeError(fmt::format(
|
||||
"Error processing command with fnum: {}",
|
||||
getFunctionNameFromEnum((enum detFuncs)function_id)));
|
||||
"Error while processing command with fnum: {}, Error: "
|
||||
"{}",
|
||||
getFunctionNameFromEnum((enum detFuncs)function_id),
|
||||
processedResult.error_message));
|
||||
}
|
||||
|
||||
} catch (const RuntimeError &e) {
|
||||
@@ -76,22 +80,20 @@ void TCPInterface::startTCPServerClientConnection() {
|
||||
LOG(logINFOBLUE) << "Exiting TCP Server";
|
||||
}
|
||||
|
||||
slsDetectorDefs::ReturnCode
|
||||
TCPInterface::processReceivedData(const detFuncs function_id,
|
||||
ServerInterface &socket) {
|
||||
ProcessedResult TCPInterface::processReceivedData(const detFuncs function_id,
|
||||
ServerInterface &socket) {
|
||||
|
||||
LOG(logDEBUG1) << "calling function fnum: " << function_id << " ("
|
||||
<< getFunctionNameFromEnum((enum detFuncs)function_id)
|
||||
<< ")";
|
||||
|
||||
slsDetectorDefs::ReturnCode returncode =
|
||||
processFunction(function_id, socket);
|
||||
ProcessedResult processedResult = processFunction(function_id, socket);
|
||||
|
||||
LOG(logDEBUG1) << "Function "
|
||||
<< getFunctionNameFromEnum((enum detFuncs)function_id)
|
||||
<< " finished";
|
||||
|
||||
return returncode;
|
||||
return processedResult;
|
||||
}
|
||||
|
||||
} // namespace sls
|
||||
@@ -1,6 +1,6 @@
|
||||
|
||||
#include "CtbConfig.h"
|
||||
#include "SharedMemory.h"
|
||||
#include "sls/SharedMemory.h"
|
||||
#include "sls/ToString.h"
|
||||
#include "sls/string_utils.h"
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// Copyright (C) 2021 Contributors to the SLS Detector Package
|
||||
#include "DetectorImpl.h"
|
||||
#include "Module.h"
|
||||
#include "SharedMemory.h"
|
||||
#include "sls/SharedMemory.h"
|
||||
#include "sls/ZmqSocket.h"
|
||||
#include "sls/detectorData.h"
|
||||
#include "sls/file_utils.h"
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
#pragma once
|
||||
|
||||
#include "CtbConfig.h"
|
||||
#include "SharedMemory.h"
|
||||
#include "sls/Result.h"
|
||||
#include "sls/SharedMemory.h"
|
||||
#include "sls/ZmqSocket.h"
|
||||
#include "sls/logger.h"
|
||||
#include "sls/sls_detector_defs.h"
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-other
|
||||
// Copyright (C) 2021 Contributors to the SLS Detector Package
|
||||
#include "Module.h"
|
||||
#include "SharedMemory.h"
|
||||
#include "sls/ClientSocket.h"
|
||||
#include "sls/SharedMemory.h"
|
||||
#include "sls/ToString.h"
|
||||
#include "sls/Version.h"
|
||||
#include "sls/bit_utils.h"
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-other
|
||||
// Copyright (C) 2021 Contributors to the SLS Detector Package
|
||||
#pragma once
|
||||
#include "SharedMemory.h"
|
||||
#include "sls/ClientSocket.h"
|
||||
#include "sls/Pattern.h"
|
||||
#include "sls/SharedMemory.h"
|
||||
#include "sls/StaticVector.h"
|
||||
#include "sls/bit_utils.h"
|
||||
#include "sls/logger.h"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "CtbConfig.h"
|
||||
#include "SharedMemory.h"
|
||||
#include "sls/SharedMemory.h"
|
||||
#include <fstream>
|
||||
#include <set>
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
// Copyright (C) 2021 Contributors to the SLS Detector Package
|
||||
#include "Detector.h"
|
||||
#include "Module.h"
|
||||
#include "SharedMemory.h"
|
||||
#include "catch.hpp"
|
||||
#include "sls/SharedMemory.h"
|
||||
|
||||
namespace sls {
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
// Copyright (C) 2021 Contributors to the SLS Detector Package
|
||||
|
||||
#define DISABLE_STATIC_ASSERT // to be able to test obsolete shm without isValid
|
||||
#include "SharedMemory.h"
|
||||
#include "catch.hpp"
|
||||
#include "sls/SharedMemory.h"
|
||||
#include "sls/string_utils.h"
|
||||
#include <filesystem>
|
||||
|
||||
|
||||
@@ -402,7 +402,7 @@ int ClientInterface::setup_receiver(Interface &socket) {
|
||||
}
|
||||
impl()->setThresholdEnergy(val);
|
||||
}
|
||||
if (detType == EIGER || detType == MYTHEN3) {
|
||||
if (detType == EIGER || detType == MYTHEN3 || detType == MATTERHORN) {
|
||||
impl()->setDynamicRange(arg.dynamicRange);
|
||||
}
|
||||
impl()->setTimingMode(arg.timMode);
|
||||
@@ -433,6 +433,10 @@ int ClientInterface::setup_receiver(Interface &socket) {
|
||||
impl()->setGateDelay3(std::chrono::nanoseconds(arg.gateDelay3Ns));
|
||||
impl()->setNumberOfGates(arg.gates);
|
||||
}
|
||||
if (detType == MATTERHORN) {
|
||||
impl()->setCounterMask(arg.countermask);
|
||||
}
|
||||
LOG(logDEBUG) << "set counter mask to " << arg.countermask;
|
||||
if (detType == GOTTHARD2) {
|
||||
impl()->setBurstMode(arg.burstType);
|
||||
}
|
||||
@@ -454,6 +458,7 @@ void ClientInterface::setDetectorType(detectorType arg) {
|
||||
case MOENCH:
|
||||
case MYTHEN3:
|
||||
case GOTTHARD2:
|
||||
case MATTERHORN:
|
||||
break;
|
||||
default:
|
||||
throw RuntimeError("Unknown detector type: " + std::to_string(arg));
|
||||
@@ -670,12 +675,21 @@ int ClientInterface::set_dynamic_range(Interface &socket) {
|
||||
break;
|
||||
*/
|
||||
case 4:
|
||||
if (detType == MATTERHORN || detType == EIGER) {
|
||||
exists = true;
|
||||
}
|
||||
break;
|
||||
case 12:
|
||||
if (detType == EIGER) {
|
||||
exists = true;
|
||||
}
|
||||
break;
|
||||
case 8:
|
||||
if (detType == MATTERHORN || detType == EIGER ||
|
||||
detType == MYTHEN3) {
|
||||
exists = true;
|
||||
}
|
||||
break;
|
||||
case 32:
|
||||
if (detType == EIGER || detType == MYTHEN3) {
|
||||
exists = true;
|
||||
|
||||
@@ -472,6 +472,66 @@ class Mythen3Data : public GeneralData {
|
||||
};
|
||||
};
|
||||
|
||||
class MatterhornData : public GeneralData {
|
||||
|
||||
public:
|
||||
MatterhornData() {
|
||||
detType = slsDetectorDefs::MATTERHORN;
|
||||
headerSizeinPacket = sizeof(slsDetectorDefs::sls_detector_header);
|
||||
framesPerFile = MATTERHORN_MAX_FRAMES_PER_FILE; // TODO: dummy value
|
||||
fifoDepth = 50000; // TODO: dummy value
|
||||
standardheader = true;
|
||||
dataSize = 8192;
|
||||
packetSize = headerSizeinPacket + dataSize;
|
||||
// udpSocketBufferSize = 0; // TODO: dummy value
|
||||
dynamicRange = 16; // default
|
||||
SetCounterMask(0xf); // default all 4 counters enabled
|
||||
UpdateImageSize();
|
||||
};
|
||||
|
||||
void SetDynamicRange(int dr) {
|
||||
dynamicRange = dr;
|
||||
UpdateImageSize();
|
||||
};
|
||||
|
||||
void SetCounterMask(const int mask) {
|
||||
int n = __builtin_popcount(mask);
|
||||
if (n < 1 || n > 4) {
|
||||
throw RuntimeError("Invalid number of counters " +
|
||||
std::to_string(n) + ". Expected 1-4.");
|
||||
}
|
||||
counterMask = mask;
|
||||
ncounters = n;
|
||||
UpdateImageSize();
|
||||
};
|
||||
|
||||
void CalculatefifoDepth() { fifoDepth = max_memory_allocated / imageSize; }
|
||||
|
||||
private:
|
||||
void UpdateImageSize() {
|
||||
nPixelsX = nChannelsX;
|
||||
nPixelsY = nChannelsY * ncounters;
|
||||
|
||||
imageSize = nPixelsX * nPixelsY * GetPixelDepth();
|
||||
LOG(logINFO) << "imageSize: " << imageSize;
|
||||
actualImageSize = imageSize;
|
||||
|
||||
CalculatefifoDepth();
|
||||
|
||||
packetsPerFrame = imageSize / dataSize;
|
||||
|
||||
LOG(logINFO) << "Packets Per Frame: " << packetsPerFrame;
|
||||
};
|
||||
|
||||
private:
|
||||
int ncounters{0};
|
||||
static constexpr int nChannelsX{1024};
|
||||
static constexpr int nChannelsY{512};
|
||||
|
||||
constexpr static int max_memory_allocated =
|
||||
100000; // TODO: dummy value for now
|
||||
};
|
||||
|
||||
class Gotthard2Data : public GeneralData {
|
||||
public:
|
||||
Gotthard2Data() {
|
||||
|
||||
@@ -118,6 +118,7 @@ void Implementation::setDetectorType(const detectorType d) {
|
||||
case XILINX_CHIPTESTBOARD:
|
||||
case MYTHEN3:
|
||||
case GOTTHARD2:
|
||||
case MATTERHORN:
|
||||
LOG(logINFO) << " ***** " << ToString(d) << " Receiver *****";
|
||||
break;
|
||||
default:
|
||||
@@ -151,6 +152,9 @@ void Implementation::setDetectorType(const detectorType d) {
|
||||
case GOTTHARD2:
|
||||
generalData = new Gotthard2Data();
|
||||
break;
|
||||
case MATTERHORN:
|
||||
generalData = new MatterhornData();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -265,7 +269,11 @@ void Implementation::setModulePositionId(const int id) {
|
||||
xy portGeometry = GetPortGeometry();
|
||||
streamingPort = DEFAULT_ZMQ_RX_PORTNO + modulePos * portGeometry.x;
|
||||
|
||||
assert(numModules.y != 0);
|
||||
if (numModules.y == 0) {
|
||||
throw RuntimeError("Number of modules in y direction is 0. Cannot set "
|
||||
"module position.");
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < listener.size(); ++i) {
|
||||
uint16_t row = 0, col = 0;
|
||||
row = (modulePos % numModules.y) * portGeometry.y;
|
||||
@@ -1606,7 +1614,8 @@ uint32_t Implementation::getDynamicRange() const {
|
||||
|
||||
void Implementation::setDynamicRange(const uint32_t i) {
|
||||
if (generalData->dynamicRange != i) {
|
||||
if (generalData->detType == EIGER || generalData->detType == MYTHEN3) {
|
||||
if (generalData->detType == EIGER || generalData->detType == MYTHEN3 ||
|
||||
generalData->detType == MATTERHORN) {
|
||||
generalData->SetDynamicRange(i);
|
||||
SetupFifoStructure();
|
||||
}
|
||||
|
||||
@@ -31,6 +31,9 @@ namespace sls {
|
||||
#define XILINX_CTB_MAX_FRAMES_PER_FILE 20000
|
||||
#define MYTHEN3_MAX_FRAMES_PER_FILE 10000
|
||||
#define GOTTHARD2_MAX_FRAMES_PER_FILE 20000
|
||||
#define MATTERHORN_MAX_FRAMES_PER_FILE \
|
||||
20000 // dummy value for now - maybe even specialized receiver for
|
||||
// matterhorn?
|
||||
|
||||
#define STATISTIC_FRAMENUMBER_INFINITE (20000)
|
||||
|
||||
|
||||
@@ -92,7 +92,7 @@ template <typename T> class SharedMemory {
|
||||
|
||||
~SharedMemory() {
|
||||
if (shared_struct)
|
||||
unmapSharedMemory();
|
||||
unmapSharedMemory(); // only unmapped as resued in command line
|
||||
}
|
||||
|
||||
/** memory is valid if it has the IsValid flag and is true */
|
||||
@@ -168,7 +168,11 @@ template <typename T> class SharedMemory {
|
||||
if (fd < 0) {
|
||||
std::string msg =
|
||||
"Create shared memory " + name + " failed: " + strerror(errno);
|
||||
throw SharedMemoryError(msg);
|
||||
if (errno == EEXIST) {
|
||||
throw SharedMemoryAlreadyExistsError(msg);
|
||||
} else {
|
||||
throw SharedMemoryError(msg);
|
||||
}
|
||||
}
|
||||
|
||||
if (ftruncate(fd, sizeof(T)) < 0) {
|
||||
@@ -17,6 +17,11 @@ class SharedMemoryError : public RuntimeError {
|
||||
explicit SharedMemoryError(const std::string &msg);
|
||||
};
|
||||
|
||||
class SharedMemoryAlreadyExistsError : public SharedMemoryError {
|
||||
public:
|
||||
explicit SharedMemoryAlreadyExistsError(const std::string &msg);
|
||||
};
|
||||
|
||||
class SocketError : public RuntimeError {
|
||||
public:
|
||||
explicit SocketError(const std::string &msg);
|
||||
|
||||
@@ -10,4 +10,4 @@
|
||||
#define APIXILINXCTB "0.0.0 0x260506"
|
||||
#define APIJUNGFRAU "0.0.0 0x260424"
|
||||
#define APIMYTHEN3 "0.0.0 0x260506"
|
||||
#define APIMATTERHORN "0.0.0 0x260212"
|
||||
#define APIMATTERHORN "0.0.0 0x260529"
|
||||
|
||||
@@ -14,6 +14,11 @@ RuntimeError::RuntimeError(const char *msg) : runtime_error(msg) {
|
||||
}
|
||||
SharedMemoryError::SharedMemoryError(const std::string &msg)
|
||||
: RuntimeError(msg) {}
|
||||
|
||||
SharedMemoryAlreadyExistsError::SharedMemoryAlreadyExistsError(
|
||||
const std::string &msg)
|
||||
: SharedMemoryError(msg) {}
|
||||
|
||||
SocketError::SocketError(const std::string &msg) : RuntimeError(msg) {}
|
||||
ZmqSocketError::ZmqSocketError(const std::string &msg) : RuntimeError(msg) {}
|
||||
NotImplementedError::NotImplementedError(const std::string &msg)
|
||||
|
||||
Reference in New Issue
Block a user