From 5a8c31fec9f6091afd520c8f97b7383166b1fb8f Mon Sep 17 00:00:00 2001 From: Alice Date: Fri, 13 Feb 2026 18:14:59 +0100 Subject: [PATCH] added first draft of matterhorn --- slsDetectorServers/CMakeLists.txt | 4 +- .../matterhonServer/CMakeLists.txt | 36 ++++++ .../include/CommandLineOptions.h | 49 ++++++++ .../include/MatterhornClientInterface.h | 19 +++ .../include/MatterhornServer.h | 37 ++++++ .../matterhonServer/include/StopServer.h | 9 ++ .../src/CommandLineOptions.cpp | 95 ++++++++++++++ .../matterhonServer/src/MatterhornApp.cpp | 116 ++++++++++++++++++ .../src/MatterhornClientInterface.cpp | 33 +++++ .../matterhonServer/src/MatterhornServer.cpp | 35 ++++++ .../matterhonServer/src/StopServer.cpp | 12 ++ slsSupportLib/include/sls/versionAPI.h | 19 +-- 12 files changed, 453 insertions(+), 11 deletions(-) create mode 100644 slsDetectorServers/matterhonServer/CMakeLists.txt create mode 100644 slsDetectorServers/matterhonServer/include/CommandLineOptions.h create mode 100644 slsDetectorServers/matterhonServer/include/MatterhornClientInterface.h create mode 100644 slsDetectorServers/matterhonServer/include/MatterhornServer.h create mode 100644 slsDetectorServers/matterhonServer/include/StopServer.h create mode 100644 slsDetectorServers/matterhonServer/src/CommandLineOptions.cpp create mode 100644 slsDetectorServers/matterhonServer/src/MatterhornApp.cpp create mode 100644 slsDetectorServers/matterhonServer/src/MatterhornClientInterface.cpp create mode 100644 slsDetectorServers/matterhonServer/src/MatterhornServer.cpp create mode 100644 slsDetectorServers/matterhonServer/src/StopServer.cpp diff --git a/slsDetectorServers/CMakeLists.txt b/slsDetectorServers/CMakeLists.txt index 9d1db734c..04c13ece4 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(matterhonServer) + diff --git a/slsDetectorServers/matterhonServer/CMakeLists.txt b/slsDetectorServers/matterhonServer/CMakeLists.txt new file mode 100644 index 000000000..612ecdf2c --- /dev/null +++ b/slsDetectorServers/matterhonServer/CMakeLists.txt @@ -0,0 +1,36 @@ +# TODO: should be different executable if not simulators on !! +add_executable(matterhornDetectorServer_virtual + ${CMAKE_CURRENT_SOURCE_DIR}/src/MatterhornApp.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/MatterhornServer.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/MatterhornClientInterface.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/CommandLineOptions.cpp +) + +target_include_directories(matterhornDetectorServer_virtual + PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include + ${CMAKE_CURRENT_SOURCE_DIR}/../../slsSupportLib/include + ${CMAKE_CURRENT_SOURCE_DIR}/../slsDetectorServer/include +) + +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? +) + +target_link_libraries(matterhornDetectorServer_virtual + PUBLIC + slsProjectCSettings + slsSupportStatic + slsDetectorStatic + slsServerStatic + fmt::fmt +) + +set_target_properties(matterhornDetectorServer_virtual PROPERTIES + RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin +) + +install(TARGETS matterhornDetectorServer_virtual + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} +) + + diff --git a/slsDetectorServers/matterhonServer/include/CommandLineOptions.h b/slsDetectorServers/matterhonServer/include/CommandLineOptions.h new file mode 100644 index 000000000..05defdcf7 --- /dev/null +++ b/slsDetectorServers/matterhonServer/include/CommandLineOptions.h @@ -0,0 +1,49 @@ +#include "MatterhornServer.h" +#include "sls/sls_detector_defs.h" +#include +#include +#include +#include + +namespace sls { + +struct DetectorServerOptions { + uint16_t port{DEFAULT_TCP_CNTRL_PORTNO}; + bool isControlServer{true}; + bool debugflag{false}; + bool updateFlag{false}; + bool checkModuleFlag{true}; + bool versionRequested{false}; + bool helpRequested{false}; +}; + +// 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 getHelpMessage(const std::string &executable) const; + + std::string getVersion() const; + + uint16_t parsePort(const char *optarg) const; + + private: + static constexpr std::array options{ + {{"help", no_argument, nullptr, 'h'}, + {"version", no_argument, nullptr, 'v'}, + {"port", required_argument, nullptr, 'p'}, + {"devel", no_argument, nullptr, 'd'}, + {"update", no_argument, nullptr, 'u'}, + {nullptr, 0, nullptr, 0}}}; + + inline static const std::string optstring{"hvp:du"}; +}; + +} // namespace sls \ No newline at end of file diff --git a/slsDetectorServers/matterhonServer/include/MatterhornClientInterface.h b/slsDetectorServers/matterhonServer/include/MatterhornClientInterface.h new file mode 100644 index 000000000..0cd0c04c5 --- /dev/null +++ b/slsDetectorServers/matterhonServer/include/MatterhornClientInterface.h @@ -0,0 +1,19 @@ +#include "ClientInterface.h" + +namespace sls { + +class MatterhornClientInterface : public ClientInterface { + + public: + MatterhornClientInterface( + const uint16_t portNumber = DEFAULT_TCP_CNTRL_PORTNO); + + ~MatterhornClientInterface() = default; + + private: + ReturnCode get_version(ServerInterface &socket); + + static std::string getMatterhornServerVersion(); +}; + +} // namespace sls \ No newline at end of file diff --git a/slsDetectorServers/matterhonServer/include/MatterhornServer.h b/slsDetectorServers/matterhonServer/include/MatterhornServer.h new file mode 100644 index 000000000..c08b7b584 --- /dev/null +++ b/slsDetectorServers/matterhonServer/include/MatterhornServer.h @@ -0,0 +1,37 @@ +#pragma once +#include "MatterhornClientInterface.h" +#include "sls/sls_detector_defs.h" +#include + +namespace sls { + +/// @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; +}; + +class 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; + + private: + std::unique_ptr tcpipInterface; + UDPInfo udpDetails{}; // TODO: for now only one receiver per module +}; + +} // namespace sls \ No newline at end of file diff --git a/slsDetectorServers/matterhonServer/include/StopServer.h b/slsDetectorServers/matterhonServer/include/StopServer.h new file mode 100644 index 000000000..91f85b1f7 --- /dev/null +++ b/slsDetectorServers/matterhonServer/include/StopServer.h @@ -0,0 +1,9 @@ +#include + +// TODO: should this inherit from MatterhornServer? +class StopServer { + public: + StopServer(uint16_t port); + + ~StopServer(); +}; \ No newline at end of file diff --git a/slsDetectorServers/matterhonServer/src/CommandLineOptions.cpp b/slsDetectorServers/matterhonServer/src/CommandLineOptions.cpp new file mode 100644 index 000000000..3f1b73073 --- /dev/null +++ b/slsDetectorServers/matterhonServer/src/CommandLineOptions.cpp @@ -0,0 +1,95 @@ +#include "CommandLineOptions.h" +#include "sls/ToString.h" +#include "sls/sls_detector_exceptions.h" +#include "sls/versionAPI.h" + +#include +#include +#include +#include + +namespace sls { + +std::string CommandLineOptions::getVersion() const { + return fmt::format( + "MatterhornServer Version: {}", + APIMATTERHORN); // TODO check that it is updated correctly !!! +} + +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 (...) { + throw("Could not parse port number " + std::string(optarg)); + } + + if (val == std::numeric_limits::max()) { + throw sls::RuntimeError("Cannot parse stop server port number. " + "Value must be in range 0 - 65535."); + } + + 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-d, --devel : Developer mode. Skips firmware " + "checks. \n" + "\t-u, --update : Update mode. Skips firmware checks " + "and " + "initial detector setup. \n", + executable); + return helpmessage; +} + +DetectorServerOptions CommandLineOptions::parse(int argc, char *argv[]) { + + int opt, option_index = 0; + + DetectorServerOptions serverOptionsValues{}; + + while ((opt = getopt_long(argc, argv, optstring.c_str(), options.data(), + &option_index)) != -1) { + switch (opt) { + case 'h': + std::cout << getHelpMessage(argv[0]) << std::endl; + serverOptionsValues.helpRequested = true; // to exit in main + break; + case 'v': + serverOptionsValues.versionRequested = true; // to exit in main + std::cout << getVersion() << std::endl; + break; + case 'p': + serverOptionsValues.port = parsePort(optarg); + break; + case 'd': + serverOptionsValues.debugflag = true; + break; + case 'u': + serverOptionsValues.updateFlag = true; + break; + default: + std::cout << getHelpMessage(argv[0]) << std::endl; + throw std::runtime_error("Wrong command line arguments."); + } + } + + return serverOptionsValues; +} + +} // namespace sls diff --git a/slsDetectorServers/matterhonServer/src/MatterhornApp.cpp b/slsDetectorServers/matterhonServer/src/MatterhornApp.cpp new file mode 100644 index 000000000..c24fc1688 --- /dev/null +++ b/slsDetectorServers/matterhonServer/src/MatterhornApp.cpp @@ -0,0 +1,116 @@ +#include "CommandLineOptions.h" +#include "MatterhornServer.h" +#include "StopServer.h" +#include "sls/logger.h" +#include "sls/sls_detector_exceptions.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; + +sem_t semaphore; + +pid_t child_pid = -1; + +/** + * 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 + if (child_pid > 0) { + kill(child_pid, SIGTERM); // tell child to exit + } + sem_post(&semaphore); +} + +void childSigTermHandler(int signal) { + (void)signal; // suppress unused warning if needed + sem_post(&semaphore); +} + +// 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 || opts.helpRequested) { + return EXIT_SUCCESS; + } + + // LOG(sls::logINFOBLUE) << "Current Process [ Tid: " << gettid() << " ]"; + + // handle locally on socket crash + // sls::setupSignalHandler(SIGPIPE, SIG_IGN); / what is this? + + sem_init(&semaphore, 1, 0); + + child_pid = fork(); // fork process for control and stop server + + if (child_pid == 0) { + // Stop server Process + std::signal(SIGTERM, childSigTermHandler); + LOG(TLogLevel::logINFOBLUE) << "Stop Server [" << opts.port + 1 << "]"; + try { + // StopServer stopServer(opts.port + 1); TODO: forget the stop + // server for now + sem_wait(&semaphore); // wait until parent signals to exit + sem_destroy(&semaphore); + } catch (...) { + sem_destroy(&semaphore); + LOG(TLogLevel::logINFOBLUE) + << "Exiting Stop Server [ Tid: " << gettid() << " ]"; + // TODO: maybe also terminate the control server !!!! + std::exit(EXIT_FAILURE); + } + LOG(TLogLevel::logINFOBLUE) + << "Exiting Stop Server [ Tid: " << gettid() << " ]"; + LOG(sls::logINFO) << "Exiting Stop Server"; + exit(EXIT_SUCCESS); + } else if (child_pid > 0) { + // Control Server Process + LOG(TLogLevel::logINFOBLUE) << "Control Server [" << opts.port << "]\n"; + + if (opts.updateFlag == 0) { + // update flag if update file exists (command line arg overwrites) + } + + try { + sls::MatterhornServer server(opts.port); + LOG(sls::logINFO) << "[ Press \'Ctrl+c\' to exit ]"; + // exit upon ctr + c + sem_wait(&semaphore); + sem_destroy(&semaphore); + } catch (...) { + sem_destroy(&semaphore); + kill(child_pid, SIGTERM); // tell child to exit + LOG(sls::logINFOBLUE) << "Exiting [ Tid: " << gettid() << " ]"; + std::exit(EXIT_FAILURE); + } + waitpid(child_pid, nullptr, 0); // wait for child to exit + LOG(sls::logINFOBLUE) << "Exiting [ Tid: " << gettid() << " ]"; + LOG(sls::logINFO) << "Exiting Detector Server"; + exit(EXIT_SUCCESS); + } else { + LOG(sls::logERROR) + << "Failed to fork process for control and stop server"; + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} diff --git a/slsDetectorServers/matterhonServer/src/MatterhornClientInterface.cpp b/slsDetectorServers/matterhonServer/src/MatterhornClientInterface.cpp new file mode 100644 index 000000000..78b379231 --- /dev/null +++ b/slsDetectorServers/matterhonServer/src/MatterhornClientInterface.cpp @@ -0,0 +1,33 @@ +#include "MatterhornClientInterface.h" +#include "sls/logger.h" +#include "sls/sls_detector_funcs.h" +#include "sls/versionAPI.h" + +namespace sls { + +MatterhornClientInterface::MatterhornClientInterface(const uint16_t portNumber) + : ClientInterface(portNumber) { + + // TODO: maybe define the function list in another .hpp file as inline + // unorderer map also this F_GET_SERVER_VERSION should be a global enum + // shared by client and server + + functionTable = { + {detFuncs::F_GET_SERVER_VERSION, + [this](ServerInterface &si) { return this->get_version(si); }}}; +} + +ReturnCode MatterhornClientInterface::get_version(ServerInterface &socket) { + + auto version = getMatterhornServerVersion(); + version.resize(MAX_STR_LENGTH); + LOG(TLogLevel::logDEBUG1) << "Matterhorn Server Version: " << version; + return static_cast(socket.sendResult( + version)); // TODO: check what would be possible return codes!!! +} + +std::string MatterhornClientInterface::getMatterhornServerVersion() { + return APIMATTERHORN; +} + +} // namespace sls \ No newline at end of file diff --git a/slsDetectorServers/matterhonServer/src/MatterhornServer.cpp b/slsDetectorServers/matterhonServer/src/MatterhornServer.cpp new file mode 100644 index 000000000..4f2fec156 --- /dev/null +++ b/slsDetectorServers/matterhonServer/src/MatterhornServer.cpp @@ -0,0 +1,35 @@ +#include "MatterhornServer.h" +#include "sls/network_utils.h" +#include "sls/sls_detector_defs.h" +// #include "sharedMemory.h" +#include "communication_funcs.h" + +namespace sls { + +MatterhornServer::MatterhornServer(uint16_t port) { + + validatePortNumber(port); + /* + // TODO: keep the c code for now + if (sharedMemory_create(port) == slsDetectorDefs::FAIL) { + throw sls::RuntimeError("Failed to create shared memory"); + } + */ + +// mmh do I want a virtual server inheriting from parent Server class? and +// parent Matterhorn class - probably better +#ifdef VIRTUAL + udpDetails.srcip = LOCALHOSTIP_INT; +#endif + udpDetails.srcport = DEFAULT_UDP_SRC_PORTNO; + udpDetails.dstport = DEFAULT_UDP_DST_PORTNO; + + // TODO: when do i set the udp mac and ip ? + + tcpipInterface = std::make_unique( + port); // TODO: need a tcp and udp interface + + // need a function to setup detector - e.g. set all registers etc. +} + +} // namespace sls \ No newline at end of file diff --git a/slsDetectorServers/matterhonServer/src/StopServer.cpp b/slsDetectorServers/matterhonServer/src/StopServer.cpp new file mode 100644 index 000000000..5c1f9e965 --- /dev/null +++ b/slsDetectorServers/matterhonServer/src/StopServer.cpp @@ -0,0 +1,12 @@ +#include "StopServer.h" +#include "sls/network_utils.h" +#include "sls/sls_detector_defs.h" + +StopServer::StopServer(uint16_t port) { + validatePortNumber(port); + + // open shared memory segment of control server map to virtual memory space + if (sharedMemory_open(port - 1) == slsDetectorDefs::FAIL) { + throw sls::RuntimeError("Failed to open shared memory"); + } +} diff --git a/slsSupportLib/include/sls/versionAPI.h b/slsSupportLib/include/sls/versionAPI.h index 245acb823..ccec83d76 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 0x250922" -#define APIGOTTHARD2 "0.0.0 0x250909" -#define APIMOENCH "0.0.0 0x250909" -#define APIEIGER "0.0.0 0x250909" -#define APIXILINXCTB "0.0.0 0x260128" -#define APIJUNGFRAU "0.0.0 0x250909" -#define APIMYTHEN3 "0.0.0 0x250922" +#define APILIB "0.0.0 0x250909" +#define APIRECEIVER "0.0.0 0x250822" +#define APICTB "0.0.0 0x250922" +#define APIGOTTHARD2 "0.0.0 0x250909" +#define APIMOENCH "0.0.0 0x250909" +#define APIEIGER "0.0.0 0x250909" +#define APIXILINXCTB "0.0.0 0x260128" +#define APIJUNGFRAU "0.0.0 0x250909" +#define APIMYTHEN3 "0.0.0 0x250922" +#define APIMATTERHORN "0.0.0 0x260212"