diff --git a/.github/workflows/build_documentation.yml b/.github/workflows/build_documentation.yml index 64ef03451..a7fd764c4 100644 --- a/.github/workflows/build_documentation.yml +++ b/.github/workflows/build_documentation.yml @@ -54,7 +54,7 @@ jobs: - name: Install System Packages uses: awalsh128/cache-apt-pkgs-action@latest with: - packages: libhdf5-dev doxygen + packages: libhdf5-dev doxygen libfmt-dev version: 1.0 - name: Setup Python diff --git a/.github/workflows/cmake.yaml b/.github/workflows/cmake.yaml index 9ca278e9e..773700f1c 100644 --- a/.github/workflows/cmake.yaml +++ b/.github/workflows/cmake.yaml @@ -23,7 +23,7 @@ jobs: - uses: awalsh128/cache-apt-pkgs-action@latest with: - packages: libhdf5-dev qtbase5-dev qt5-qmake libqt5svg5-dev libpng-dev libtiff-dev + packages: libhdf5-dev qtbase5-dev qt5-qmake libqt5svg5-dev libpng-dev libtiff-dev libfmt-dev version: 1.0 - name: Configure CMake diff --git a/.github/workflows/run_tests.yaml b/.github/workflows/run_tests.yaml index 215efb8a3..7d3487f29 100644 --- a/.github/workflows/run_tests.yaml +++ b/.github/workflows/run_tests.yaml @@ -22,7 +22,7 @@ jobs: - uses: awalsh128/cache-apt-pkgs-action@latest with: - packages: libhdf5-dev + packages: libhdf5-dev libfmt-dev version: 1.0 - name: Configure CMake diff --git a/CMakeLists.txt b/CMakeLists.txt index cb9645225..fb5d5df0f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -32,6 +32,7 @@ if(NOT CMAKE_USE_PTHREADS_INIT) message(FATAL_ERROR "A POSIX threads (pthread) implementation is required, but was not found.") endif() +set(SLS_LOG_MAX_REPORTING_LEVEL "sls::TLogLevel::logINFO" CACHE STRING "Set the maximum logging level for the project") option(SLS_USE_SYSTEM_ZMQ "Use system installed libzmq" OFF) @@ -39,6 +40,7 @@ option(SLS_USE_SYSTEM_ZMQ "Use system installed libzmq" OFF) include(FetchContent) option(SLS_FETCH_ZMQ_FROM_GITHUB "Fetch zmq from github" OFF) option(SLS_FETCH_PYBIND11_FROM_GITHUB "Fetch pybind11 from github" OFF) +option(SLS_FETCH_FMT_FROM_GITHUB "Fetch fmt from github" OFF) # Allow FetchContent_Populate to be called with a single argument # otherwise deprecated warning is issued @@ -187,6 +189,40 @@ if (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR) set(SLS_MASTER_PROJECT ON) endif() +if (SLS_FETCH_FMT_FROM_GITHUB) + set(FMT_TEST OFF CACHE INTERNAL "disabling fmt tests") + FetchContent_Declare( + fmt + GIT_REPOSITORY https://github.com/fmtlib/fmt.git + GIT_TAG 12.1.0 + GIT_PROGRESS TRUE + USES_TERMINAL_DOWNLOAD TRUE + ) + set(FMT_INSTALL ON CACHE BOOL "") + FetchContent_MakeAvailable(fmt) + set_property(TARGET fmt PROPERTY POSITION_INDEPENDENT_CODE ON) +else() + # downloaded from https://github.com/fmtlib/fmt/releases/tag/12.1.0 + set(FMT_TEST OFF CACHE INTERNAL "disabling fmt tests") + FetchContent_Declare( + fmt + URL ${CMAKE_CURRENT_SOURCE_DIR}/libs/fmt/fmt-12.1.0.tar.gz + # Compute hash: md5sum fmt-12.1.0.tar.gz + URL_HASH MD5=92eb6f492e4838e5f024ce5207beafc7) + FetchContent_MakeAvailable(fmt) + set_property(TARGET fmt PROPERTY POSITION_INDEPENDENT_CODE ON) +endif() + +# Export fmt +if(SLS_MASTER_PROJECT) + install(TARGETS fmt + EXPORT ${TARGETS_EXPORT_NAME} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} + ) +endif() option(SLS_USE_HDF5 "HDF5 File format" OFF) @@ -194,6 +230,7 @@ option(SLS_BUILD_SHARED_LIBRARIES "Build shared libaries" OFF) option(SLS_USE_TEXTCLIENT "Text Client" ON) option(SLS_USE_DETECTOR "Detector libs" ON) option(SLS_USE_RECEIVER "Receiver" ON) +option(SLS_USE_SERVER "Server" ON) option(SLS_USE_RECEIVER_BINARIES "Receiver binaries" ON) option(SLS_USE_GUI "GUI" OFF) option(SLS_USE_SIMULATOR "Simulator" OFF) @@ -208,6 +245,7 @@ option(SLS_TUNE_LOCAL "tune to local machine" OFF) option(SLS_DEVEL_HEADERS "install headers for devel" OFF) option(SLS_USE_MOENCH "compile zmq and post processing for Moench" OFF) option(SLS_USE_JUNGFRAU "compile post processing for Jungfrau" OFF) +option(SLS_USE_MATTERHORN "compile matterhorn server" OFF) option(SLS_INSTALL_VERSIONED_BINARIES "Add version number to binaries on install" OFF) #Needed for multi version RPM #Convenience option to switch off defaults when building Moench binaries only @@ -282,18 +320,15 @@ if(SLS_EXT_BUILD) endif() - # slsProjectOptions and slsProjectWarnings are used # to control options for the libraries if(NOT TARGET slsProjectOptions) add_library(slsProjectOptions INTERFACE) - target_compile_features(slsProjectOptions INTERFACE cxx_std_17) + target_compile_features(slsProjectOptions INTERFACE cxx_std_17) + target_compile_definitions(slsProjectOptions + INTERFACE LOG_MAX_REPORTING_LEVEL=${SLS_LOG_MAX_REPORTING_LEVEL}) endif() -set(LOG_MAX_REPORTING_LEVEL sls::logINFO CACHE STRING "set logging level") -target_compile_definitions(slsProjectOptions - INTERFACE LOG_MAX_REPORTING_LEVEL=${LOG_MAX_REPORTING_LEVEL} -) if (NOT TARGET slsProjectWarnings) add_library(slsProjectWarnings INTERFACE) @@ -393,7 +428,12 @@ endif() if (SLS_USE_DETECTOR OR SLS_USE_TEXTCLIENT) add_subdirectory(slsDetectorSoftware) -endif () +endif() + +# TODO refactor with simulators +if (SLS_USE_SERVER) + add_subdirectory(slsDetectorServers/slsDetectorServer_cpp) +endif() if (SLS_USE_RECEIVER) add_subdirectory(slsReceiverSoftware) @@ -404,6 +444,10 @@ 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) diff --git a/README.md b/README.md index f468bd102..3727bb07f 100644 --- a/README.md +++ b/README.md @@ -83,51 +83,62 @@ To use the basic building blocks, meaning sls_detector_get/put and the shared li > **Note:** For v9.x.x of slsDetectorPackage and older, C++11 compatible compiler. -#### Python bindings -* Python >= 3.8 +Additionally the core requires the following dependencies: -* pybind11 2.13.6 (packaged in libs) + * fmt 12.1.0 (packaged in libs) (since version 11.0.0) + * ZeroMQ 4.3.4 (packaged in libs) + * rapidjson (packaged in libs) -> **Note:** Refer [pybind11 notes](#4-pybind-and-zeromq). - -#### ZeroMQ - -* Zeromq 4.3.4 (packaged in libs) +> **Note:** Both fmt, ZeroMQ and rapidjson are bundled in libs. One does not need to pre-install them on the system. Alternatively, one can fetch fmt and ZeroMQ from GitHub by passing the cmake options ``-DSLS_FETCH_FMT_FROM_GITHUB=ON`` and ``-DSLS_FETCH_ZEROMQ_FROM_GITHUB=ON`` respectively. > **Note:** Refer [zeromq notes](#4-pybind-and-zeromq). -#### GUI +#### Dependencies to build Python module -* Qt 5.9 +To build the python module the following dependencies are needed: -* Qwt 6.1.5 (packaged in libs) + * Python >= 3.8 + * pybind11 2.13.6 (packaged in libs) + +> **Note:** pybind11 is bundled in libs. One does not need to pre-install it on the system. Alternatively, one can fetch pybind11 from GitHub by passing the cmake option ``-DSLS_FETCH_PYBIND11_FROM_GITHUB=ON``. -#### Moench executables +> **Note:** Refer [pybind11 notes](#4-pybind-and-zeromq). -* libtiff -#### Documentation +#### Dependencies to build documentation -The documentation is built with -* Doxygen (to extract C++ classes etc.) +To build this documentation that you are reading now the following dependencies are needed: -* Breathe (Sphinx plugin to handle doxygen xml) + * Doxygen (to extract C++ classes etc.) + * Breathe (Sphinx plugin to handle doxygen xml) + * Sphinx with sphinx_rtd_theme -* Sphinx with sphinx_rtd_theme +#### Dependencies to build GUI -#### Packaged in libs/ +To build the GUI the following dependencies are needed: -* catch2 (unit testing) + * Qt 5.9 + * Qwt 6.1.5 (packaged in libs) -* rapidjson (streaming from receiver) +> **Note:** Qwt is bundled in libs. One does not need to pre-install it on the system. -* pybind11 (python bindings) -* qwt (gui plotting) +#### Dependencies to build Moench and Jungfrau executables -* libzmq (streaming to/from receiver) + +To build the Moench and Jungfrau executables for preprocessing and calibration the following dependencies are needed: + + * libtiff + +#### Dependencies to build Tests + +To build the tests the following dependencies are needed: + + * Catch2 3.4.0 (packaged in libs) + +> **Note:** Catch2 is bundled in libs. One does not need to pre-install it on the system. ### 3.2. Download Source Code from github ``` diff --git a/conda-recipes/main-library/meta.yaml b/conda-recipes/main-library/meta.yaml index 54e97c1be..1c495645d 100755 --- a/conda-recipes/main-library/meta.yaml +++ b/conda-recipes/main-library/meta.yaml @@ -30,6 +30,7 @@ requirements: - zlib - expat - zeromq + - fmt run: - libstdcxx-ng diff --git a/docs/src/dependencies.rst b/docs/src/dependencies.rst index a4b02f98e..a64d7a219 100644 --- a/docs/src/dependencies.rst +++ b/docs/src/dependencies.rst @@ -16,61 +16,82 @@ the shared libraries these are needed: * CMake >= 3.14 * C++17 compatible compiler. (We test with gcc and clang) -.. note :: +.. note:: For v9.x.x of slsDetectorPackage and older, C++11 compatible compiler. ------------------------ -Python bindings ------------------------ +Additionally the core requires the following dependencies: - * Python >= 3.8 - * pybind11 2.13.6 (packaged in libs) + * fmt 12.1.0 (packaged in libs) + * ZeroMQ 4.3.4 (packaged in libs) + * rapidjson (packaged in libs) -.. note :: +.. note:: - Refer :ref:`pybind11 notes. ` + Both fmt, ZeroMQ and rapidjson are bundled in libs. One does not need to pre-install them on the system. Alternatively, one can fetch fmt and ZeroMQ from GitHub by passing the cmake options ``-DSLS_FETCH_FMT_FROM_GITHUB=ON`` and ``-DSLS_FETCH_ZEROMQ_FROM_GITHUB=ON`` respectively. ------------------------ -ZeroMQ ------------------------ - - * Zeromq 4.3.4 (packaged in libs) - -.. note :: +.. note:: Refer :ref:`zeromq notes. ` ------------------------ -GUI ------------------------ + +------------------------------------ +Dependencies to build Python module +------------------------------------ + +To build the python module the following dependencies are needed: + + * Python >= 3.8 + * pybind11 2.13.6 (packaged in libs) + +.. note:: + + pybind11 is bundled in libs. One does not need to pre-install it on the system. Alternatively, one can fetch pybind11 from GitHub by passing the cmake option ``-DSLS_FETCH_PYBIND11_FROM_GITHUB=ON``. + +.. note:: + + Refer :ref:`pybind11 notes. ` + +------------------------------- +Dependencies to build documentation +------------------------------- + +To build this documentation that you are reading now the following dependencies are needed: + + * Doxygen (to extract C++ classes etc.) + * Breathe (Sphinx plugin to handle doxygen xml) + * Sphinx with sphinx_rtd_theme + +------------------------- +Dependencies to build GUI +------------------------- + +To build the GUI the following dependencies are needed: * Qt 5.9 * Qwt 6.1.5 (packaged in libs) ------------------------ -Moench executables ------------------------ +.. note:: + + Qwt is bundled in libs. One does not need to pre-install it on the system. + +------------------------------------------------------ +Dependencies to build Moench and Jungfrau executables +----------------------------------------------------- + +To build the Moench and Jungfrau executables for preprocessing and calibration the following dependencies are needed: * libtiff ------------------------ -Documentation ------------------------ +-------------------------------------------------- +Dependencies to build Tests +-------------------------------------------------- -The documentation that you are reading now is built with +To build the tests the following dependencies are needed: - * Doxygen (to extract C++ classes etc.) - * Breathe (Sphinx plugin to handle doxygen xml) - * Sphinx with sphinx_rtd_theme + * Catch2 3.4.0 (packaged in libs) ------------------------ -Packaged in libs/ ------------------------ - - * catch2 (unit testing) - * rapidjson (streaming from receiver) - * pybind11 (python bindings) - * qwt (gui plotting) - * libzmq (streaming to/from receiver) \ No newline at end of file +.. note:: + + Catch2 is bundled in libs. One does not need to pre-install it on the system. diff --git a/etc/generate_registerdefs.py b/etc/generate_registerdefs.py new file mode 100644 index 000000000..91178b0e3 --- /dev/null +++ b/etc/generate_registerdefs.py @@ -0,0 +1,113 @@ +import pandas as pd +import argparse + +def Ip_core_name_to_enum_type(ip_core_name : str) -> str: + """Convert IP core name to enum type IPCore.""" + if pd.isna(ip_core_name): + return "IPCore::UNKNOWN" + + return f"IPCore::{ip_core_name.upper()}" + +def create_bitmask_and_offset(from_bit : int, to_bit : int) -> tuple[int, int]: + """Create a bitmask for a register field given the from_bit and to_bit.""" + if from_bit < 0 or to_bit < 0 or from_bit > to_bit or from_bit >= 32 or to_bit >= 32: + raise ValueError(f"Invalid bit range: from_bit={from_bit}, to_bit={to_bit}") + + offset = from_bit + num_bits = to_bit - from_bit + 1 + adress_space = 0xFFFFFFFF # Assuming a 32-bit address space for the bitmask + mask = (adress_space >> (32 - num_bits)) + return mask, offset # to get value of field: (register_value >> offset) & mask, to set value of field: register_value = (register_value & ~(mask << offset)) | ((field_value & mask) << offset) + +def argument_parser(): + parser = argparse.ArgumentParser(description="Generate register definitions from a CSV file.") + parser.add_argument("--csv_file", required=True, help="Path to the CSV file containing register definitions.") + parser.add_argument("--output_header_file", required=True, help="Path to the output header file to write the register definitions to.") + parser.add_argument( + "--overwrite", + action="store_true", + help="Overwrite the output file instead of appending.", + ) + return parser.parse_args() + +# TODO: should be configurable +header = r""" +// clang-format off +#include "RegisterHelperStructs.hpp" + +namespace sls { + +/// @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 +}; +""" + +postpend = r""" +} // namespace sls +// clang-format on +""" + +def main(): + + args = argument_parser() + + registers_list = pd.read_csv(args.csv_file) + + registers = registers_list.drop_duplicates(subset=["Reg_name", "Address"]) + + file_mode = "w" if args.overwrite else "a" + header_file = open(args.output_header_file, file_mode) + + if args.overwrite: + header_file.write(header) + header_file.write("\n\n") + + header_file.write("// Register definitions") + header_file.write("\n") + + for index, row in registers.iterrows(): + local_address_offset_in_bytes = row["Address"] + register_name = row["Reg_name"] + ip_core_name = row["Interface"] + + define_register_string = ( + f"constexpr Register {register_name}{{" + f"{Ip_core_name_to_enum_type(ip_core_name)}, {hex(int(local_address_offset_in_bytes, 16))}}};" + ) + + header_file.write(f"{define_register_string}\n") + header_file.write("\n") + + header_file.write("\n") + header_file.write("\n") + + header_file.write("// Register fields") + header_file.write("\n") + + for index, row in registers_list.iterrows(): + register_name = row["Reg_name"] + field_name = row["Name"] + from_bit = row["From_bit"] + to_bit = row["To_bit"] + mask, offset = create_bitmask_and_offset(from_bit, to_bit) + + define_registerfield_string = ( + f"constexpr RegisterField {field_name}{{\n" + f" {register_name}, {offset}, {hex(mask)}}};" + ) + + header_file.write(f"{define_registerfield_string}\n") + header_file.write("\n") + + header_file.write(postpend) # TODO: have to take care xof it manually when in append mode - ugly + header_file.close() + + +if __name__ == "__main__": + main() diff --git a/libs/fmt/fmt-12.1.0.tar.gz b/libs/fmt/fmt-12.1.0.tar.gz new file mode 100644 index 000000000..4af9bd165 Binary files /dev/null and b/libs/fmt/fmt-12.1.0.tar.gz differ diff --git a/slsDetectorServers/CMakeLists.txt b/slsDetectorServers/CMakeLists.txt index 9d1db734c..3a04f2bf9 100644 --- a/slsDetectorServers/CMakeLists.txt +++ b/slsDetectorServers/CMakeLists.txt @@ -1,8 +1,6 @@ # SPDX-License-Identifier: LGPL-3.0-or-other # Copyright (C) 2021 Contributors to the SLS Detector Package - - # Install fake the library install(TARGETS slsProjectCSettings EXPORT "${TARGETS_EXPORT_NAME}" @@ -17,3 +15,5 @@ add_subdirectory(jungfrauDetectorServer) add_subdirectory(mythen3DetectorServer) add_subdirectory(gotthard2DetectorServer) add_subdirectory(moenchDetectorServer) +add_subdirectory(matterhornServer) + diff --git a/slsDetectorServers/matterhornServer/CMakeLists.txt b/slsDetectorServers/matterhornServer/CMakeLists.txt new file mode 100644 index 000000000..e4d237e41 --- /dev/null +++ b/slsDetectorServers/matterhornServer/CMakeLists.txt @@ -0,0 +1,62 @@ + + +set(MATTERHORN_SOURCES + ${CMAKE_CURRENT_SOURCE_DIR}/src/MatterhornApp.cpp +) + +if(SLS_USE_SIMULATOR) + list(APPEND MATTERHORN_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src/VirtualMatterhornServer.cpp) + + add_executable(matterhornDetectorServer_virtual ${MATTERHORN_SOURCES}) + + target_include_directories(matterhornDetectorServer_virtual + PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include + ${CMAKE_CURRENT_SOURCE_DIR}/../../slsSupportLib/include + ${CMAKE_CURRENT_SOURCE_DIR}/../slsDetectorServer_cpp/include) + + target_link_libraries(matterhornDetectorServer_virtual + PUBLIC + slsSupportStatic + slsServerStatic) + + set_target_properties(matterhornDetectorServer_virtual PROPERTIES + RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin + ) + + install(TARGETS matterhornDetectorServer_virtual + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + ) +else() + list(APPEND MATTERHORN_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src/MatterhornServer.cpp) + + add_executable(matterhornDetectorServer ${MATTERHORN_SOURCES}) + + target_include_directories(matterhornDetectorServer + PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include + ${CMAKE_CURRENT_SOURCE_DIR}/../../slsSupportLib/include + ${CMAKE_CURRENT_SOURCE_DIR}/../slsDetectorServer_cpp/include) + + target_link_libraries(matterhornDetectorServer + PUBLIC + slsSupportStatic + #slsDetectorStatic + slsServerStatic) + + set_target_properties(matterhornDetectorServer PROPERTIES + RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin + ) + + install(TARGETS matterhornDetectorServer + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + ) + +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? +#) + + + + diff --git a/slsDetectorServers/matterhornServer/include/BaseMatterhornServer.h b/slsDetectorServers/matterhornServer/include/BaseMatterhornServer.h new file mode 100644 index 000000000..4ca5e46cc --- /dev/null +++ b/slsDetectorServers/matterhornServer/include/BaseMatterhornServer.h @@ -0,0 +1,113 @@ +#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 +#include +#include +#include +#include +#include + +namespace sls { + +/// @brief Base class for Matterhorn Server, can be used to implement a virtual +/// server for testing and actual server +template +class BaseMatterhornServer + : public DetectorServer> { + + 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>(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 +ReturnCode +BaseMatterhornServer::processFunction(const detFuncs function_id, + ServerInterface &socket) { + + switch (function_id) { + default: + throw RuntimeError( + fmt::format("Function {} not implemented", + getFunctionNameFromEnum((enum detFuncs)function_id))); + } +} + +template +ReturnCode BaseMatterhornServer::get_num_udp_interfaces( + ServerInterface &socket) const { + return static_cast( + socket.sendResult(static_cast(numUDPInterfaces))); +} + +template +ReturnCode +BaseMatterhornServer::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(socket.sendResult( + version_cstr)); // TODO: check what would be possible return codes!!! +} + +template +ReturnCode BaseMatterhornServer::get_detector_type( + ServerInterface &socket) { + int detectortype = slsDetectorDefs::detectorType::MATTERHORN; + return static_cast(socket.sendResult(detectortype)); +} + +template +std::string BaseMatterhornServer::getMatterhornServerVersion() { + return APIMATTERHORN; +} + +template +ReturnCode +BaseMatterhornServer::initial_checks(ServerInterface &socket) { + + return static_cast(this)->initial_checks(socket); +} + +} // namespace sls \ No newline at end of file diff --git a/slsDetectorServers/matterhornServer/include/MatterhornServer.h b/slsDetectorServers/matterhornServer/include/MatterhornServer.h new file mode 100644 index 000000000..586818b71 --- /dev/null +++ b/slsDetectorServers/matterhornServer/include/MatterhornServer.h @@ -0,0 +1,27 @@ +#pragma once +#include "BaseMatterhornServer.h" +#include "TCPInterface.h" +#include "sls/sls_detector_defs.h" +#include +#include + +namespace sls { + +class MatterhornServer : public BaseMatterhornServer { + + 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 \ No newline at end of file diff --git a/slsDetectorServers/matterhornServer/include/RegisterDefs.hpp b/slsDetectorServers/matterhornServer/include/RegisterDefs.hpp new file mode 100644 index 000000000..60335ccb4 --- /dev/null +++ b/slsDetectorServers/matterhornServer/include/RegisterDefs.hpp @@ -0,0 +1,240 @@ + +// clang-format off +#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 +}; + + +// Register definitions +constexpr Register CTRL_Reg{IPCore::UNKNOWN, 0x0}; + +constexpr Register Status_Reg{IPCore::UNKNOWN, 0x4}; + +constexpr Register FPGAVersionReg{IPCore::UNKNOWN, 0x8}; + +constexpr Register FPGA_GIT_HEAD{IPCore::UNKNOWN, 0xc}; + +constexpr Register FixedPatternReg{IPCore::UNKNOWN, 0x10}; + +constexpr Register ApiVersionReg{IPCore::UNKNOWN, 0x14}; + +constexpr Register Chip_ID_Reg{IPCore::UNKNOWN, 0x18}; + +constexpr Register MH_SM_Ctrl_Reg{IPCore::MH_RO_SM_AXI, 0x0}; + +constexpr Register MH_SM_Exposure_Reg{IPCore::MH_RO_SM_AXI, 0x4}; + +constexpr Register MH_SM_Period_Reg{IPCore::MH_RO_SM_AXI, 0x8}; + +constexpr Register MH_SM_Frames_Reg{IPCore::MH_RO_SM_AXI, 0xc}; + +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 Frame_HDR_Set_Reg{IPCore::FHDR_AXI, 0x0}; + +constexpr Register Frame_HDR_FrameNumLSB_Reg{IPCore::FHDR_AXI, 0x4}; + +constexpr Register Frame_HDR_FrameNumMSB_Reg{IPCore::FHDR_AXI, 0x8}; + +constexpr Register Frame_HDR_TimestampLSB_Reg{IPCore::FHDR_AXI, 0xc}; + +constexpr Register Frame_HDR_TimestampMSB_Reg{IPCore::FHDR_AXI, 0x10}; + +constexpr Register Frame_HDR_ModCoord_LSB_Reg{IPCore::FHDR_AXI, 0x14}; + +constexpr Register Frame_HDR_ModCoord_MSB_Reg{IPCore::FHDR_AXI, 0x18}; + +constexpr Register Frame_HDR_PktctrMax_Reg{IPCore::FHDR_AXI, 0x1c}; + +constexpr Register Aurora_Valid_DW_Reg{IPCore::AURORA_STATUS, 0x0}; + +constexpr Register Aurora_Valid_Bytes_Reg{IPCore::AURORA_STATUS, 0x4}; + +constexpr Register Aurora_Busy_Up_Cycles_Reg{IPCore::AURORA_STATUS, 0x8}; + +constexpr Register Aurora_Hard_Errors_Reg{IPCore::AURORA_STATUS, 0xc}; + +constexpr Register Aurora_Soft_Errors_Reg{IPCore::AURORA_STATUS, 0x10}; + +constexpr Register Aurora_Channel_n_Lanes_Up_Reg{IPCore::AURORA_STATUS, 0x14}; + +constexpr Register Aurora_GT_PLL_Lock_Reg{IPCore::AURORA_STATUS2, 0x0}; + +constexpr Register PktPacketLengthReg{IPCore::PACKETIZERREG, 0xa100}; + +constexpr Register PktNoPacketsReg{IPCore::PACKETIZERREG, 0xa104}; + +constexpr Register PktCtrlReg{IPCore::PACKETIZERREG, 0xa108}; + +constexpr Register PktCoordReg1{IPCore::PACKETIZERREG, 0xa10c}; + +constexpr Register PktCoordReg2{IPCore::PACKETIZERREG, 0xa110}; + + + +// Register fields +constexpr RegisterField Power_VIO{ + CTRL_Reg, 0, 0x1}; + +constexpr RegisterField Power_Vcc_A{ + CTRL_Reg, 1, 0x1}; + +constexpr RegisterField Power_Vcc_B{ + CTRL_Reg, 2, 0x1}; + +constexpr RegisterField Power_Vcc_C{ + CTRL_Reg, 3, 0x1}; + +constexpr RegisterField Power_Vcc_D{ + CTRL_Reg, 4, 0x1}; + +constexpr RegisterField MH_Enable_Enable{ + CTRL_Reg, 5, 0x1}; + +constexpr RegisterField MH_Clk_Enable{ + CTRL_Reg, 6, 0x1}; + +constexpr RegisterField sm_busy{ + Status_Reg, 0, 0x1}; + +constexpr RegisterField FPGACompDate{ + FPGAVersionReg, 0, 0xffffff}; + +constexpr RegisterField FPGADetType{ + FPGAVersionReg, 24, 0xff}; + +constexpr RegisterField FPGA_GIT_HEAD{ + FPGA_GIT_HEAD, 0, 0xffffffff}; + +constexpr RegisterField FixedPattern{ + FixedPatternReg, 0, 0xffffffff}; + +constexpr RegisterField ApiCompDate{ + ApiVersionReg, 0, 0xffffff}; + +constexpr RegisterField ApiDetType{ + ApiVersionReg, 24, 0xff}; + +constexpr RegisterField ChipID{ + Chip_ID_Reg, 0, 0x7}; + +constexpr RegisterField Start_Acquistion{ + MH_SM_Ctrl_Reg, 0, 0x1}; + +constexpr RegisterField Stop_Acquistion{ + MH_SM_Ctrl_Reg, 1, 0x1}; + +constexpr RegisterField MH_Readout_Exposure_Time{ + MH_SM_Exposure_Reg, 0, 0xffffffff}; + +constexpr RegisterField MH_Readout_Period_Time{ + MH_SM_Period_Reg, 0, 0xffffffff}; + +constexpr RegisterField MH_Readout_Frames{ + MH_SM_Frames_Reg, 0, 0xffffffff}; + +constexpr RegisterField MH_SM_StoreLength{ + MH_SM_StoreLength_Reg, 0, 0xffffffff}; + +constexpr RegisterField MH_SM_ResetMHLength{ + MH_SM_ResetMHLength_Reg, 0, 0xffffffff}; + +constexpr RegisterField Frame_Hdr_Set_Framenumber{ + Frame_HDR_Set_Reg, 0, 0x1}; + +constexpr RegisterField Frame_Hdr_Set_Timestamp{ + Frame_HDR_Set_Reg, 1, 0x1}; + +constexpr RegisterField Frame_Hdr_Framenumber_LSB{ + Frame_HDR_FrameNumLSB_Reg, 0, 0xffffffff}; + +constexpr RegisterField Frame_Hdr_Framenumber_MSB{ + Frame_HDR_FrameNumMSB_Reg, 0, 0xffffffff}; + +constexpr RegisterField Frame_Hdr_Timestamp_LSB{ + Frame_HDR_TimestampLSB_Reg, 0, 0xffffffff}; + +constexpr RegisterField Frame_Hdr_Timestamp_MSB{ + Frame_HDR_TimestampMSB_Reg, 0, 0xffffffff}; + +constexpr RegisterField Frame_HDR_ModCoord_LSB{ + Frame_HDR_ModCoord_LSB_Reg, 0, 0xffffffff}; + +constexpr RegisterField Frame_HDR_ModCoord_MSB{ + Frame_HDR_ModCoord_MSB_Reg, 0, 0xffffffff}; + +constexpr RegisterField Frame_HDR_PktctrMax{ + Frame_HDR_PktctrMax_Reg, 0, 0xff}; + +constexpr RegisterField Aurora_Number_Valid_DW{ + Aurora_Valid_DW_Reg, 0, 0xffffffff}; + +constexpr RegisterField Aurora_Valid_Bytes{ + Aurora_Valid_Bytes_Reg, 0, 0xffffffff}; + +constexpr RegisterField Aurora_Busy_Up_Cycles{ + Aurora_Busy_Up_Cycles_Reg, 0, 0xffffffff}; + +constexpr RegisterField Aurora_Hard_Errors{ + Aurora_Hard_Errors_Reg, 0, 0xffffffff}; + +constexpr RegisterField Aurora_Soft_Errors{ + Aurora_Soft_Errors_Reg, 0, 0xffffffff}; + +constexpr RegisterField Aurora_Lanes_Up{ + Aurora_Channel_n_Lanes_Up_Reg, 0, 0xf}; + +constexpr RegisterField Aurora_Channel_Up{ + Aurora_Channel_n_Lanes_Up_Reg, 4, 0x1}; + +constexpr RegisterField Aurora_GT_PLL_Lock{ + Aurora_GT_PLL_Lock_Reg, 0, 0x1}; + +constexpr RegisterField Aurora_GT_PLL_Lock_Counter{ + Aurora_GT_PLL_Lock_Reg, 4, 0x1ffffff}; + +constexpr RegisterField PacketLength1G{ + PktPacketLengthReg, 0, 0xffff}; + +constexpr RegisterField PacketLength10G{ + PktPacketLengthReg, 16, 0xffff}; + +constexpr RegisterField NoPackets1G{ + PktNoPacketsReg, 0, 0x3f}; + +constexpr RegisterField NoPackets10G{ + PktNoPacketsReg, 16, 0x3f}; + +constexpr RegisterField NoServers{ + PktCtrlReg, 0, 0x3f}; + +constexpr RegisterField ServerStart{ + PktCtrlReg, 8, 0x1f}; + +constexpr RegisterField EthInterf{ + PktCtrlReg, 16, 0x1}; + +constexpr RegisterField Coordx{ + PktCoordReg1, 0, 0xffff}; + +constexpr RegisterField Coordy{ + PktCoordReg1, 16, 0xffff}; + +constexpr RegisterField Coordz{ + PktCoordReg2, 0, 0xffff}; + + +} // namespace sls +// clang-format on diff --git a/slsDetectorServers/matterhornServer/include/RegisterHelperStructs.hpp b/slsDetectorServers/matterhornServer/include/RegisterHelperStructs.hpp new file mode 100644 index 000000000..5f561a285 --- /dev/null +++ b/slsDetectorServers/matterhornServer/include/RegisterHelperStructs.hpp @@ -0,0 +1,29 @@ +#include +#include + +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 \ No newline at end of file diff --git a/slsDetectorServers/matterhornServer/include/VirtualMatterhornServer.h b/slsDetectorServers/matterhornServer/include/VirtualMatterhornServer.h new file mode 100644 index 000000000..61cb31bda --- /dev/null +++ b/slsDetectorServers/matterhornServer/include/VirtualMatterhornServer.h @@ -0,0 +1,24 @@ + +#include "BaseMatterhornServer.h" + +namespace sls { + +class VirtualMatterhornServer + : public BaseMatterhornServer { + + 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 \ No newline at end of file diff --git a/slsDetectorServers/matterhornServer/src/MatterhornApp.cpp b/slsDetectorServers/matterhornServer/src/MatterhornApp.cpp new file mode 100644 index 000000000..a60b328a7 --- /dev/null +++ b/slsDetectorServers/matterhornServer/src/MatterhornApp.cpp @@ -0,0 +1,113 @@ +#include "CommandLineOptions.h" +#include "VirtualMatterhornServer.h" +#include "sls/logger.h" +#include "sls/sls_detector_exceptions.h" +#include "sls/versionAPI.h" +#include + +#include +#include +#include +#include + +// gettid added in glibc 2.30 +#if __GLIBC__ == 2 && __GLIBC_MINOR__ < 30 +#include +#define gettid() syscall(SYS_gettid) +#endif + +using namespace sls; + +pid_t pid = -1; + +static volatile sig_atomic_t interruption = 0; + +/** + * Control+C Interrupt Handler + * to let all the other process know to exit properly + */ +void sigInterruptHandler(int signal) { + (void)signal; // suppress unused warning if needed + interruption = 1; +} + +// TODO: should be a generic ServerApp for all detectors +int main(int argc, char *argv[]) { + + CommandLineOptions cli; + DetectorServerOptions opts{}; + try { + opts = cli.parse(argc, argv); + } catch (sls::RuntimeError &e) { + return EXIT_FAILURE; + } + if (opts.versionRequested) { + std::cout << fmt::format("MatterhornServer Version: {}", APIMATTERHORN) + << std::endl; + + return EXIT_SUCCESS; + } + + if (opts.helpRequested) { + return EXIT_SUCCESS; + } + + LOG(TLogLevel::logINFOMAGENTA) << cli.printOptions(); + + // Register Ctrl+C handler + std::signal(SIGINT, sigInterruptHandler); + + // handle locally on socket crash + signal(SIGPIPE, SIG_IGN); + + pid = fork(); // fork process for control and stop server + + if (pid == 0) { + // Stop server Process + + LOG(TLogLevel::logINFOBLUE) << "Stop Server [" << opts.port + 1 << "]"; + try { + VirtualMatterhornServer stopServer(opts.port + 1); + while (!interruption) { + pause(); // wait for signal to exit + } + } catch (...) { + kill(getppid(), SIGINT); // tell parent to exit // TODO: should then + // also return EXIT_FAILURE + } + LOG(TLogLevel::logINFOBLUE) + << "Exiting Stop Server [ Tid: " << gettid() << " ]"; + LOG(sls::logINFO) << "Exiting Stop Server"; + } else if (pid > 0) { + // parent + // Control Server Process + + LOG(TLogLevel::logINFOBLUE) << "Control Server [" << opts.port << "]\n"; + + try { + VirtualMatterhornServer server( + opts.port); // TODO use virtual if compiled with virtual + // simulators on + while (!interruption) { + pause(); // wait for signal to exit + } + } catch (...) { + LOG(sls::logINFOBLUE) + << "Exiting Control Server [ Tid: " << gettid() << " ]"; + LOG(sls::logINFO) << "Exiting Detector Server"; + kill(pid, SIGINT); // tell child to exit + waitpid(pid, nullptr, 0); // wait for child to exit + return EXIT_FAILURE; + } + waitpid(pid, nullptr, 0); // wait for child to exit + LOG(sls::logINFOBLUE) + << "Exiting Detector Control Server [ Tid: " << gettid() << " ]"; + LOG(sls::logINFO) << "Exiting Detector Server"; + } else { + LOG(sls::logERROR) + << "Failed to fork process for control and stop server"; + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} diff --git a/slsDetectorServers/matterhornServer/src/MatterhornServer.cpp b/slsDetectorServers/matterhornServer/src/MatterhornServer.cpp new file mode 100644 index 000000000..522d5b486 --- /dev/null +++ b/slsDetectorServers/matterhornServer/src/MatterhornServer.cpp @@ -0,0 +1,24 @@ +#include "MatterhornServer.h" + +namespace sls { + +MatterhornServer::MatterhornServer(uint16_t port) + : BaseMatterhornServer(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(socket.sendResult(initial_checks_passed)); +} + +} // namespace sls \ No newline at end of file diff --git a/slsDetectorServers/matterhornServer/src/VirtualMatterhornServer.cpp b/slsDetectorServers/matterhornServer/src/VirtualMatterhornServer.cpp new file mode 100644 index 000000000..8c82da20c --- /dev/null +++ b/slsDetectorServers/matterhornServer/src/VirtualMatterhornServer.cpp @@ -0,0 +1,24 @@ +#include "VirtualMatterhornServer.h" + +namespace sls { + +VirtualMatterhornServer::VirtualMatterhornServer(uint16_t port) + : BaseMatterhornServer(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(socket.sendResult(initial_checks_passed)); +} + +} // namespace sls \ No newline at end of file diff --git a/slsDetectorServers/slsDetectorServer/src/slsDetectorServer_funcs.c b/slsDetectorServers/slsDetectorServer/src/slsDetectorServer_funcs.c index 5b708a09f..755f78104 100644 --- a/slsDetectorServers/slsDetectorServer/src/slsDetectorServer_funcs.c +++ b/slsDetectorServers/slsDetectorServer/src/slsDetectorServer_funcs.c @@ -11057,9 +11057,11 @@ int spi_read(int file_des) { #elif defined(CHIPTESTBOARDD) // set spi to 8 bit per word (-1 comes from the firmware), set chipselect bus_w(SPI_CTRL_REG, + ((8 - 1) << SPI_CTRL_NBIT_OFST) + (1 << SPI_CTRL_CHIPSELECT_BIT)); for (int i = 0; i < n_bytes + 1; ++i) { // TODO: should we make bus_w to this address blocking in the firmware + // // to remove usleep ? bus_w(SPI_WRITEDATA_REG, local_tx[i]); usleep_bf(BFIN_SPI_WAIT_uSECONDS); diff --git a/slsDetectorServers/slsDetectorServer_cpp/CMakeLists.txt b/slsDetectorServers/slsDetectorServer_cpp/CMakeLists.txt new file mode 100644 index 000000000..9060b99f2 --- /dev/null +++ b/slsDetectorServers/slsDetectorServer_cpp/CMakeLists.txt @@ -0,0 +1,64 @@ +set(SOURCES + ${CMAKE_CURRENT_SOURCE_DIR}/src/TCPInterface.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/CommandLineOptions.cpp +) + +add_library(slsServerObject OBJECT + ${SOURCES} +) + +target_include_directories(slsServerObject PUBLIC + "$" + "$" +) + +target_link_libraries(slsServerObject + PUBLIC + slsProjectOptions + slsSupportStatic + PRIVATE + slsProjectWarnings +) + +set(DETECTOR_LIBRARY_TARGETS slsServerObject) + +set(PUBLICHEADERS + ${CMAKE_CURRENT_SOURCE_DIR}/include/TCPInterface.h +) + +#Shared library +if(SLS_BUILD_SHARED_LIBRARIES) + add_library(slsServerShared SHARED $) + target_link_libraries(slsServerShared PUBLIC slsServerObject) + set_target_properties(slsServerShared PROPERTIES + VERSION ${PACKAGE_VERSION_MAJOR}.${PACKAGE_VERSION_MINOR}.${PACKAGE_VERSION_PATCH} + SOVERSION ${PACKAGE_VERSION_MAJOR} + LIBRARY_OUTPUT_NAME SlsServer + LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin + PUBLIC_HEADER "${PUBLICHEADERS}" + ) + list(APPEND DETECTOR_LIBRARY_TARGETS slsServerShared) +endif(SLS_BUILD_SHARED_LIBRARIES) + +#Static library +add_library(slsServerStatic STATIC $) +target_link_libraries(slsServerStatic PUBLIC slsServerObject) + +set_target_properties(slsServerStatic PROPERTIES + ARCHIVE_OUTPUT_NAME SlsServerStatic + ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin + PUBLIC_HEADER "${PUBLICHEADERS}" +) +list(APPEND DETECTOR_LIBRARY_TARGETS slsServerStatic) + +if((CMAKE_BUILD_TYPE STREQUAL "Release") AND SLS_LTO_AVAILABLE) + set_property(TARGET ${DETECTOR_LIBRARY_TARGETS} PROPERTY INTERPROCEDURAL_OPTIMIZATION True) +endif() + +install(TARGETS ${DETECTOR_LIBRARY_TARGETS} + EXPORT "${TARGETS_EXPORT_NAME}" + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/sls +) diff --git a/slsDetectorServers/slsDetectorServer_cpp/include/CommandLineOptions.h b/slsDetectorServers/slsDetectorServer_cpp/include/CommandLineOptions.h new file mode 100644 index 000000000..7ec69b175 --- /dev/null +++ b/slsDetectorServers/slsDetectorServer_cpp/include/CommandLineOptions.h @@ -0,0 +1,66 @@ +#include "sls/sls_detector_defs.h" +#include +#include +#include +#include + +namespace sls { + +struct DetectorServerOptions { + // TODO: careful changed for other detectors + uint16_t port{DEFAULT_TCP_CNTRL_PORTNO}; + /// @brief ignore firmware version compatibility + bool ignoreFirmwareCompatibility{false}; + /// @brief safe startup - skip initial detector setup and checks + bool safeStartup{false}; + bool versionRequested{false}; + bool helpRequested{false}; +}; + +template +struct SpecificDetectorServerOptions : DetectorServerOptions {}; + +// template specialization +// template <> +// struct SpecificDetectorServerOptions {}; + +// TODO should be a general server specific class or even shared with +// CommandLIneOptions in Receiver +class CommandLineOptions { + + public: + CommandLineOptions() = default; + + ~CommandLineOptions() = default; + + DetectorServerOptions parse(int argc, char *argv[]); + + std::string printOptions() const; + + private: + std::string getHelpMessage(const std::string &executable) const; + + uint16_t parsePort(const char *optarg) const; + + void parse_deprecated(const int &opt, char *argv[]); + + DetectorServerOptions detectorserveroptions{}; + + static constexpr std::array options{ + {{"help", no_argument, nullptr, 'h'}, + {"version", no_argument, nullptr, 'v'}, + {"port", required_argument, nullptr, 'p'}, + {"ignore_fw_compatibility", no_argument, nullptr, + 'f'}, // ignore firmware compatibility check + {"safe_startup", no_argument, nullptr, 's'}, // safe startup + // deprecated options for backward compatibility + {"devel", no_argument, nullptr, 'd'}, // safe_startup mode + {"update", no_argument, nullptr, 'u'}, // firmware compatibility check + + {nullptr, 0, nullptr, 0}}}; + + inline static const char optstring[] = "hvp:fs" + "du"; // second part is deprecated +}; + +} // namespace sls \ No newline at end of file diff --git a/slsDetectorServers/slsDetectorServer_cpp/include/DetectorServer.h b/slsDetectorServers/slsDetectorServer_cpp/include/DetectorServer.h new file mode 100644 index 000000000..7f1a6eb89 --- /dev/null +++ b/slsDetectorServers/slsDetectorServer_cpp/include/DetectorServer.h @@ -0,0 +1,269 @@ +#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 +#include +#include +#include +#include +#include + +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{}; +}; + +template 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; + + std::array + 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 +DetectorServer::DetectorServer(uint16_t port) { + validatePortNumber(port); + + udpDetails[0].srcport = DEFAULT_UDP_SRC_PORTNO; + udpDetails[0].dstport = DEFAULT_UDP_DST_PORTNO; + + std::function fn = + [this](const detFuncs &function_id, ServerInterface &socket) { + return this->processFunction(function_id, socket); + }; + tcpInterface = std::make_unique(fn, port); +} + +template +ReturnCode DetectorServer::processFunction( + const detFuncs function_id, ServerInterface &socket) { + + switch (function_id) { + case detFuncs::F_GET_SERVER_VERSION: + return static_cast(this)->get_version(socket); + case detFuncs::F_GET_DETECTOR_TYPE: + return static_cast(this)->get_detector_type( + socket); + case detFuncs::F_INITIAL_CHECKS: + return static_cast(this)->initial_checks( + socket); + case detFuncs::F_GET_NUM_INTERFACES: + return static_cast(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(this)->processFunction(function_id, + socket); + } + + return ReturnCode::FAIL; +} + +template +ReturnCode DetectorServer::get_update_mode( + ServerInterface &socket) const { + + return static_cast( + socket.sendResult(static_cast(updateMode))); +} + +template +ReturnCode DetectorServer::set_source_udp_mac( + ServerInterface &socket) { + uint64_t newsrcudpMac; + + try { + int ret = socket.Receive(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 +ReturnCode DetectorServer::get_source_udp_mac( + ServerInterface &socket) const { + return static_cast(socket.sendResult(udpDetails[0].srcmac)); +} + +template +ReturnCode DetectorServer::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 +ReturnCode DetectorServer::get_source_udp_ip( + ServerInterface &socket) const { + return static_cast(socket.sendResult(udpDetails[0].srcip)); +} + +template +ReturnCode DetectorServer::set_destination_udp_mac( + ServerInterface &socket) { + uint64_t newDstMac; + + try { + int ret = socket.Receive(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 +ReturnCode DetectorServer::get_destination_udp_mac( + ServerInterface &socket) const { + return static_cast(socket.sendResult(udpDetails[0].dstmac)); +} + +template +ReturnCode DetectorServer::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 +ReturnCode DetectorServer::get_destination_udp_ip( + ServerInterface &socket) const { + return static_cast(socket.sendResult(udpDetails[0].dstip)); +} + +template +ReturnCode DetectorServer::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 +ReturnCode DetectorServer::get_destination_udp_port( + ServerInterface &socket) const { + return static_cast(socket.sendResult(udpDetails[0].dstport)); +}; + +} // namespace sls \ No newline at end of file diff --git a/slsDetectorServers/slsDetectorServer_cpp/include/TCPInterface.h b/slsDetectorServers/slsDetectorServer_cpp/include/TCPInterface.h new file mode 100644 index 000000000..9538a3e42 --- /dev/null +++ b/slsDetectorServers/slsDetectorServer_cpp/include/TCPInterface.h @@ -0,0 +1,60 @@ +#pragma once +#include "sls/ServerSocket.h" +#include "sls/sls_detector_defs.h" +#include "sls/sls_detector_funcs.h" + +#include +#include +#include +#include + +namespace sls { + +/** + * @brief TCPInterface class handles communication and processing of commands + * from Client to Server. + */ +class TCPInterface { + + public: + ~TCPInterface(); + + TCPInterface(std::function + &processFunction_, + const uint16_t portNumber = DEFAULT_TCP_CNTRL_PORTNO); + + /// @brief creates tcp thread + void startTCPServer(); + + std::atomic killTcpThread{false}; + + private: + /** + * @brief starts the TCP/IP server to listen for client commands and process + * them + */ + void startTCPServerClientConnection(); + + /** + * @brief decodes the received command and calls the corresponding function + * @param function_id The ID of the function recived by the server and to + * be executed + */ + ReturnCode processReceivedData(const detFuncs function_id, + ServerInterface &socket); + + /// @brief map of function IDs and corresponding functions + std::function + processFunction; + + /// @brief TCP/IP port number for the detector server + uint16_t portNumber{}; + + /// @brief socket for TCP/IP communication with the client + ServerSocket server; + + /// @brief thread for running the TCP/IP server + std::unique_ptr tcpThread; +}; + +} // namespace sls \ No newline at end of file diff --git a/slsDetectorServers/slsDetectorServer_cpp/src/CommandLineOptions.cpp b/slsDetectorServers/slsDetectorServer_cpp/src/CommandLineOptions.cpp new file mode 100644 index 000000000..49d6a016b --- /dev/null +++ b/slsDetectorServers/slsDetectorServer_cpp/src/CommandLineOptions.cpp @@ -0,0 +1,116 @@ +#include "CommandLineOptions.h" +#include "sls/ToString.h" +#include "sls/sls_detector_exceptions.h" + +#include +#include +#include +#include + +namespace sls { + +uint16_t CommandLineOptions::parsePort(const char *optarg) const { + uint16_t val = 0; // TODO: in c code its unsigned int + + try { + val = sls::StringTo(optarg); + } catch (const std::exception &e) { + throw sls::RuntimeError(fmt::format( + "Could not parse port number {}. {}", optarg, e.what())); + } + + if (val < 1024) { + throw sls::RuntimeError( + "Invalid/ privileged port number parsed. Min: 1024."); + } + return val; +} + +std::string +CommandLineOptions::getHelpMessage(const std::string &executable) const { + // TODO: update if we keep it Matterhonr specific - refactor a bit better - + // e.g. if compiled with detector macro + std::string helpmessage = fmt::format( + "Usage: {}" + " [arguments]\n" + "Possible arguments are:\n" + "\t-v, --version : Software version\n" + "\t-p, --port : TCP communication port with client. " + "\n" + "\t-s, --safe_startup : Safe startup mode. Skips initial " + "detector setup and checks. \n" + "\t-f, --ignore_fw_compatibility : Ignore firmware compatibility " + "check. \n", + executable); + return helpmessage; +} + +void CommandLineOptions::parse_deprecated(const int &opt, char *argv[]) { + + switch (opt) { + case 'd': + std::cout << "Warning: -d/--devel option is deprecated. Use " + "-l/--safe_startup instead." + << std::endl; + detectorserveroptions.safeStartup = true; + break; + case 'u': + std::cout << "Warning: -u/--update option is deprecated. Use " + "-f/--ignore_fw_compatibility instead." + << std::endl; + detectorserveroptions.ignoreFirmwareCompatibility = true; + break; + default: + throw std::runtime_error(fmt::format("Wrong command line arguments. {}", + getHelpMessage(argv[0]))); + } +} + +std::string CommandLineOptions::printOptions() const { + std::string msg = "setting up detector server"; + + if (detectorserveroptions.ignoreFirmwareCompatibility) { + msg += " skipping firmware compatibility checks"; + msg += detectorserveroptions.safeStartup ? " and" : ""; + } + if (detectorserveroptions.safeStartup) { + msg += " in safe startup mode e.g. skipping any initial detector setup " + "and checks"; + } + + return msg; +} + +DetectorServerOptions CommandLineOptions::parse(int argc, char *argv[]) { + + int opt, option_index = 0; + + while ((opt = getopt_long(argc, argv, optstring, options.data(), + &option_index)) != -1) { + switch (opt) { + case 'h': + std::cout << getHelpMessage(argv[0]) << std::endl; + detectorserveroptions.helpRequested = true; // to exit in main + break; + case 'v': + detectorserveroptions.versionRequested = true; // to exit in main + break; + case 'p': + detectorserveroptions.port = parsePort(optarg); + break; + case 'f': + detectorserveroptions.ignoreFirmwareCompatibility = true; + break; + case 's': + detectorserveroptions.safeStartup = true; + break; + default: + parse_deprecated(opt, argv); // to handle deprecated options and + // throw error for wrong options + } + } + + return detectorserveroptions; +} + +} // namespace sls diff --git a/slsDetectorServers/slsDetectorServer_cpp/src/TCPInterface.cpp b/slsDetectorServers/slsDetectorServer_cpp/src/TCPInterface.cpp new file mode 100644 index 000000000..9d2d7911e --- /dev/null +++ b/slsDetectorServers/slsDetectorServer_cpp/src/TCPInterface.cpp @@ -0,0 +1,95 @@ +#include "TCPInterface.h" + +#include "fmt/format.h" +#include "sls/logger.h" +#include "sls/string_utils.h" +#include + +namespace sls { + +TCPInterface::TCPInterface( + std::function + &processFunction_, + const uint16_t portNumber_) + : processFunction(processFunction_), portNumber(portNumber_), + server(portNumber_) { + // validatePortNumber(portNumber); TODO: where to validate? +} + +TCPInterface::~TCPInterface() { + killTcpThread = true; // mmh but if the receiver is stuck in a function, + // this will be of no help + LOG(logINFO) << "Shutting down TCP Socket on port " << portNumber; + server.shutdown(); + LOG(logDEBUG) << "TCP Socket closed on port " << portNumber; + if (tcpThread && tcpThread->joinable()) { + tcpThread->join(); + } +} + +void TCPInterface::startTCPServer() { + + tcpThread = std::make_unique( + &TCPInterface::startTCPServerClientConnection, this); +} + +void TCPInterface::startTCPServerClientConnection() { + + LOG(logINFO) << "SLS Server starting TCP Server on port " << portNumber + << '\n'; + + int function_id{}; // TODO should it be an enum type + while (!killTcpThread) { + try { + auto socket = server.accept(); + try { + + 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( + static_cast(function_id), socket); + + if (returncode == FAIL) { + throw RuntimeError(fmt::format( + "Error processing command with fnum: {}", + getFunctionNameFromEnum((enum detFuncs)function_id))); + } + + } catch (const RuntimeError &e) { + // We had an error needs to be sent to client + char mess[MAX_STR_LENGTH]{}; + LOG(logERROR) << "Error processing command: " << e.what(); + strcpy_safe(mess, e.what()); + socket.Send(slsDetectorDefs::FAIL); + socket.Send(mess); + } + // TODO handle exiting server if tcp command was to exit server + } catch (const RuntimeError &e) { + LOG(logERROR) << "Accept failed: " << e.what(); + } + } + + LOG(logINFOBLUE) << "Exiting TCP Server"; +} + +ReturnCode TCPInterface::processReceivedData(const detFuncs function_id, + ServerInterface &socket) { + + LOG(logDEBUG1) << "calling function fnum: " << function_id << " (" + << getFunctionNameFromEnum((enum detFuncs)function_id) + << ")"; + + ReturnCode returncode = processFunction(function_id, socket); + + LOG(logDEBUG1) << "Function " + << getFunctionNameFromEnum((enum detFuncs)function_id) + << " finished"; + + return returncode; +} + +} // namespace sls \ No newline at end of file diff --git a/slsDetectorSoftware/src/DetectorImpl.cpp b/slsDetectorSoftware/src/DetectorImpl.cpp index 3ce196ce9..b83e3a52e 100644 --- a/slsDetectorSoftware/src/DetectorImpl.cpp +++ b/slsDetectorSoftware/src/DetectorImpl.cpp @@ -196,7 +196,7 @@ void DetectorImpl::setHostname(const std::vector &name) { } void DetectorImpl::addModule(const std::string &name) { - LOG(logINFO) << "Adding module " << name; + LOG(TLogLevel::logINFO) << "Adding module " << name; auto host = verifyUniqueDetHost(name); std::string hostname = host.first; uint16_t port = host.second; diff --git a/slsDetectorSoftware/src/Module.cpp b/slsDetectorSoftware/src/Module.cpp index 6724f1d9f..5cfa39875 100644 --- a/slsDetectorSoftware/src/Module.cpp +++ b/slsDetectorSoftware/src/Module.cpp @@ -50,8 +50,6 @@ std::string Module::getHostname() const { return shm()->hostname; } void Module::setHostname(const std::string &hostname, const bool initialChecks) { strcpy_safe(shm()->hostname, hostname.c_str()); - auto client = DetectorSocket(shm()->hostname, shm()->controlPort); - client.close(); try { checkDetectorVersionCompatibility(); initialDetectorServerChecks(); @@ -87,9 +85,11 @@ std::string Module::getControlServerLongVersion() const { // throw with old server version (sends 8 bytes) catch (RuntimeError &e) { std::string emsg = std::string(e.what()); + if (emsg.find(F_GET_SERVER_VERSION) && emsg.find("8 bytes")) { throwDeprecatedServerVersion(); } + throw; } } @@ -146,7 +146,6 @@ std::string Module::getReceiverSoftwareVersion() const { // static function slsDetectorDefs::detectorType Module::getTypeFromDetector(const std::string &hostname, uint16_t cport) { - LOG(logDEBUG1) << "Getting Module type "; ClientSocket socket("Detector", hostname, cport); socket.Send(F_GET_DETECTOR_TYPE); socket.setFnum(F_GET_DETECTOR_TYPE); @@ -3515,6 +3514,9 @@ void Module::initialDetectorServerChecks() { void Module::checkDetectorVersionCompatibility() { std::string detServers[2] = {getControlServerLongVersion(), getStopServerLongVersion()}; + LOG(logDEBUG1) + << "Checking detector version compatibility with client version " + << detServers[0] << " and " << detServers[1]; for (int i = 0; i != 2; ++i) { // det and client (sem. versioning) Version det(detServers[i]); @@ -3563,6 +3565,8 @@ const std::string Module::getDetectorAPI() const { return APIGOTTHARD2; case XILINX_CHIPTESTBOARD: return APIXILINXCTB; + case MATTERHORN: + return APIMATTERHORN; default: throw NotImplementedError( "Detector type not implemented to get Detector API"); diff --git a/slsReceiverSoftware/src/ClientInterface.cpp b/slsReceiverSoftware/src/ClientInterface.cpp index 7acf59e2e..0c08534a8 100644 --- a/slsReceiverSoftware/src/ClientInterface.cpp +++ b/slsReceiverSoftware/src/ClientInterface.cpp @@ -85,7 +85,6 @@ void ClientInterface::startTCPServer() { << '\n'; while (!killTcpThread) { - LOG(logDEBUG1) << "Start accept loop"; try { auto socket = server.accept(); try { @@ -96,7 +95,7 @@ void ClientInterface::startTCPServer() { // We had an error needs to be sent to client char mess[MAX_STR_LENGTH]{}; strcpy_safe(mess, e.what()); - socket.Send(FAIL); + socket.Send(slsDetectorDefs::FAIL); socket.Send(mess); } // if tcp command was to exit server diff --git a/slsSupportLib/CMakeLists.txt b/slsSupportLib/CMakeLists.txt index 995d24819..e0431c3cc 100755 --- a/slsSupportLib/CMakeLists.txt +++ b/slsSupportLib/CMakeLists.txt @@ -95,7 +95,7 @@ target_link_libraries(slsSupportObject slsProjectOptions ${STD_FS_LIB} # from helpers.cmake Threads::Threads # slsDetector and Receiver need this - + fmt::fmt PRIVATE slsProjectWarnings md5sls diff --git a/slsSupportLib/include/sls/DataSocket.h b/slsSupportLib/include/sls/DataSocket.h index 01215c20e..31d9afa72 100644 --- a/slsSupportLib/include/sls/DataSocket.h +++ b/slsSupportLib/include/sls/DataSocket.h @@ -3,6 +3,7 @@ #pragma once #include "sls/TypeTraits.h" +#include "sls/logger.h" #include #include #include diff --git a/slsSupportLib/include/sls/ServerInterface.h b/slsSupportLib/include/sls/ServerInterface.h index 475201983..d4ed04576 100644 --- a/slsSupportLib/include/sls/ServerInterface.h +++ b/slsSupportLib/include/sls/ServerInterface.h @@ -3,6 +3,8 @@ #pragma once #include "sls/DataSocket.h" +#include "sls/logger.h" + namespace sls { class ServerInterface; } diff --git a/slsSupportLib/include/sls/logger.h b/slsSupportLib/include/sls/logger.h index 9b949d802..5754286e7 100644 --- a/slsSupportLib/include/sls/logger.h +++ b/slsSupportLib/include/sls/logger.h @@ -27,11 +27,6 @@ enum TLogLevel { logDEBUG5 }; -// Compiler should optimize away anything below this value -#ifndef LOG_MAX_REPORTING_LEVEL -#define LOG_MAX_REPORTING_LEVEL sls::logINFO -#endif - #define __AT__ \ std::string(__FILE__) + std::string("::") + std::string(__func__) + \ std::string("(): ") @@ -43,7 +38,7 @@ enum TLogLevel { class Logger { std::ostringstream os; - TLogLevel level = LOG_MAX_REPORTING_LEVEL; + TLogLevel level = ReportingLevel(); public: Logger() = default; @@ -55,7 +50,7 @@ class Logger { } static TLogLevel &ReportingLevel() { // singelton eeh - static TLogLevel reportingLevel = logINFO; + static TLogLevel reportingLevel = LOG_MAX_REPORTING_LEVEL; return reportingLevel; } diff --git a/slsSupportLib/include/sls/sls_detector_defs.h b/slsSupportLib/include/sls/sls_detector_defs.h index f8b4b7877..54285ba17 100644 --- a/slsSupportLib/include/sls/sls_detector_defs.h +++ b/slsSupportLib/include/sls/sls_detector_defs.h @@ -46,6 +46,9 @@ #define DEFAULT_UDP_SRC_PORTNO 32410 #define DEFAULT_UDP_DST_PORTNO 50001 +/** for virtual detectors */ +#define LOCALHOSTIP_INT 2130706433 + #define MAX_UDP_DESTINATION 32 #define SLS_DETECTOR_HEADER_VERSION 0x2 @@ -82,8 +85,13 @@ #define DEFAULT_STREAMING_TIMER_IN_MS 500 #define NUM_RX_THREAD_IDS 9 + // NOLINTEND(cppcoreguidelines-macro-usage) #ifdef __cplusplus + +// TODO: why are all these defs inside a class? - why not static +enum ReturnCode { OK = 0, FAIL = 1 }; + class slsDetectorDefs { public: #endif @@ -98,7 +106,9 @@ class slsDetectorDefs { MOENCH, MYTHEN3, GOTTHARD2, - XILINX_CHIPTESTBOARD + XILINX_CHIPTESTBOARD, + MATTERHORN // TODO: maybe better to have it under a namespace + // slsDetectorDefs instead of grouped in a class }; /** return values */ @@ -758,6 +768,13 @@ struct detParameters { nChipY = 1; nDacs = 14; break; + case slsDetectorDefs::detectorType::MATTERHORN: + nChanX = 256; + nChanY = 256; + nChipX = 4; + nChipY = 2; + nDacs = 31; + break; default: throw sls::RuntimeError("Unknown detector type! " + std::to_string(type)); diff --git a/slsSupportLib/include/sls/versionAPI.h b/slsSupportLib/include/sls/versionAPI.h index 89017dad9..1b1f5ce66 100644 --- a/slsSupportLib/include/sls/versionAPI.h +++ b/slsSupportLib/include/sls/versionAPI.h @@ -1,12 +1,13 @@ // SPDX-License-Identifier: LGPL-3.0-or-other // Copyright (C) 2021 Contributors to the SLS Detector Package /** API versions */ -#define APILIB "0.0.0 0x250909" -#define APIRECEIVER "0.0.0 0x250822" -#define APICTB "0.0.0 0x260427" -#define APIGOTTHARD2 "0.0.0 0x260427" -#define APIMOENCH "0.0.0 0x260424" -#define APIEIGER "0.0.0 0x260424" -#define APIXILINXCTB "0.0.0 0x260427" -#define APIJUNGFRAU "0.0.0 0x260424" -#define APIMYTHEN3 "0.0.0 0x260427" +#define APILIB "0.0.0 0x250909" +#define APIRECEIVER "0.0.0 0x250822" +#define APICTB "0.0.0 0x260427" +#define APIGOTTHARD2 "0.0.0 0x260427" +#define APIMOENCH "0.0.0 0x260424" +#define APIEIGER "0.0.0 0x260424" +#define APIXILINXCTB "0.0.0 0x260427" +#define APIJUNGFRAU "0.0.0 0x260424" +#define APIMYTHEN3 "0.0.0 0x260427" +#define APIMATTERHORN "0.0.0 0x260212" \ No newline at end of file diff --git a/slsSupportLib/src/ServerSocket.cpp b/slsSupportLib/src/ServerSocket.cpp index e61c5d132..08c12b562 100644 --- a/slsSupportLib/src/ServerSocket.cpp +++ b/slsSupportLib/src/ServerSocket.cpp @@ -52,9 +52,11 @@ ServerInterface ServerSocket::accept() { if (newSocket == -1) { throw SocketError("Server ERROR: socket accept failed\n"); } + char tc[INET_ADDRSTRLEN]{}; inet_ntop(AF_INET, &(clientAddr.sin_addr), tc, INET_ADDRSTRLEN); thisClient = IpAddr{tc}; + // Set socket buffer size return ServerInterface(newSocket); } diff --git a/slsSupportLib/src/ToString.cpp b/slsSupportLib/src/ToString.cpp index f8ac4c684..dedb2f165 100644 --- a/slsSupportLib/src/ToString.cpp +++ b/slsSupportLib/src/ToString.cpp @@ -221,6 +221,8 @@ std::string ToString(const defs::detectorType s) { return std::string("Gotthard2"); case defs::XILINX_CHIPTESTBOARD: return std::string("Xilinx_ChipTestBoard"); + case defs::MATTERHORN: + return std::string("Matterhorn"); default: return std::string("Unknown"); } @@ -756,6 +758,8 @@ template <> defs::detectorType StringTo(const std::string &s) { return defs::GOTTHARD2; if (s == "Xilinx_ChipTestBoard") return defs::XILINX_CHIPTESTBOARD; + if (s == "Matterhorn") + return defs::MATTERHORN; throw RuntimeError("Unknown detector type " + s); }