used CRTP for virtual detector
All checks were successful
Build on RHEL9 docker image / build (push) Successful in 3m13s
Build on RHEL8 docker image / build (push) Successful in 4m45s
Run Simulator Tests on local RHEL9 / build (push) Successful in 14m40s
Run Simulator Tests on local RHEL8 / build (push) Successful in 17m5s

This commit is contained in:
2026-03-30 11:03:44 +02:00
parent 7b918ff2e9
commit 0d2b91cd1f
8 changed files with 240 additions and 192 deletions

View File

@@ -1,8 +1,8 @@
# 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/StopServer.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/VirtualMatterhornServer.cpp
#${CMAKE_CURRENT_SOURCE_DIR}/src/StopServer.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/CommandLineOptions.cpp
)
@@ -20,7 +20,8 @@ target_link_libraries(matterhornDetectorServer_virtual
PUBLIC
slsSupportStatic
slsDetectorStatic
slsServerStatic)
slsServerStatic
)
set_target_properties(matterhornDetectorServer_virtual PROPERTIES
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin

View File

@@ -0,0 +1,152 @@
#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 <memory>
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{};
};
/// @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:
/**
* 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);
~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);
ReturnCode get_update_mode(ServerInterface &socket);
ReturnCode get_source_udp_mac(ServerInterface &socket);
protected:
size_t num_udp_interfaces() const;
/// @brief TODO what is this?
bool updateMode{true};
/// @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
private:
static std::string getMatterhornServerVersion();
private:
/// @brief map of function IDs and corresponding functions
// maybe load from additional file cleaner
std::unordered_map<detFuncs, std::function<ReturnCode(ServerInterface &)>>
function_table = {
{detFuncs::F_GET_SERVER_VERSION,
[this](ServerInterface &si) { return this->get_version(si); }},
{detFuncs::F_GET_DETECTOR_TYPE,
[this](ServerInterface &si) {
return this->get_detector_type(si);
}},
{detFuncs::F_INITIAL_CHECKS,
[this](ServerInterface &si) {
return static_cast<DerivedServer *>(this)->initial_checks(si);
}},
{detFuncs::F_GET_NUM_INTERFACES,
[this](ServerInterface &si) {
return this->get_num_udp_interfaces(si);
}},
{detFuncs::F_GET_UPDATE_MODE,
[this](ServerInterface &si) {
return static_cast<DerivedServer *>(this)->get_update_mode(si);
}},
{detFuncs::F_GET_SOURCE_UDP_MAC, [this](ServerInterface &si) {
return this->get_source_udp_mac(si);
}}};
};
template <typename DerivedServer>
BaseMatterhornServer<DerivedServer>::BaseMatterhornServer(uint16_t port) {
validatePortNumber(port);
udpDetails[0].srcport = DEFAULT_UDP_SRC_PORTNO;
udpDetails[0].dstport = DEFAULT_UDP_DST_PORTNO;
// TODO: when do i set the udp mac and ip ?
tcpInterface = std::make_unique<TCPInterface>(
function_table, port); // TODO: need a tcp and udp interface
// need a function to setup detector - e.g. set all registers etc.
}
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>
size_t BaseMatterhornServer<DerivedServer>::num_udp_interfaces() const {
return udpDetails.size();
}
template <typename DerivedServer>
ReturnCode BaseMatterhornServer<DerivedServer>::get_num_udp_interfaces(
ServerInterface &socket) {
int numUDPInterfaces = static_cast<int>(num_udp_interfaces());
return static_cast<ReturnCode>(socket.sendResult(numUDPInterfaces));
}
template <typename DerivedServer>
ReturnCode BaseMatterhornServer<DerivedServer>::get_source_udp_mac(
ServerInterface &socket) {
uint64_t srcMac = udpDetails[0].srcmac;
return static_cast<ReturnCode>(socket.sendResult(srcMac));
}
} // namespace sls

View File

@@ -1,88 +1,14 @@
#pragma once
#include "TCPInterface.h"
#include "BaseMatterhornServer.h"
#include "sls/sls_detector_defs.h"
#include <array>
#include <memory>
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{};
};
/// @brief Base class for Matterhorn Server, can be used to implement a virtual
/// server for testing and actual server
class 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 BaseMatterhornServer(uint16_t port = DEFAULT_TCP_CNTRL_PORTNO);
~BaseMatterhornServer() = default;
ReturnCode get_version(ServerInterface &socket);
ReturnCode get_detector_type(ServerInterface &socket);
virtual ReturnCode initial_checks(ServerInterface &socket) = 0;
ReturnCode get_num_udp_interfaces(ServerInterface &socket);
virtual ReturnCode get_update_mode(ServerInterface &socket) = 0;
ReturnCode get_source_udp_mac(ServerInterface &socket);
protected:
static std::string getMatterhornServerVersion();
size_t num_udp_interfaces() const;
/// @brief TODO what is this?
bool updateMode{true};
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
private:
/// @brief map of function IDs and corresponding functions
// maybe load from additional file cleaner
std::unordered_map<detFuncs, std::function<ReturnCode(ServerInterface &)>>
function_table = {
{detFuncs::F_GET_SERVER_VERSION,
[this](ServerInterface &si) { return this->get_version(si); }},
{detFuncs::F_GET_DETECTOR_TYPE,
[this](ServerInterface &si) {
return this->get_detector_type(si);
}},
{detFuncs::F_INITIAL_CHECKS,
[this](ServerInterface &si) { return this->initial_checks(si); }},
{detFuncs::F_GET_NUM_INTERFACES,
[this](ServerInterface &si) {
return this->get_num_udp_interfaces(si);
}},
{detFuncs::F_GET_UPDATE_MODE,
[this](ServerInterface &si) { return this->get_update_mode(si); }},
{detFuncs::F_GET_SOURCE_UDP_MAC, [this](ServerInterface &si) {
return this->get_source_udp_mac(si);
}}};
};
class MatterhornServer : public BaseMatterhornServer {
class MatterhornServer : public BaseMatterhornServer<MatterhornServer> {
public:
/**
@@ -96,28 +22,11 @@ class MatterhornServer : public BaseMatterhornServer {
~MatterhornServer() = default;
ReturnCode initial_checks(ServerInterface &socket) override;
ReturnCode initial_checks(ServerInterface &socket);
ReturnCode get_update_mode(ServerInterface &socket) override;
ReturnCode get_update_mode(ServerInterface &socket);
};
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) override;
ReturnCode get_update_mode(ServerInterface &socket) override;
};
} // namespace sls

View File

@@ -0,0 +1,26 @@
#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);
ReturnCode get_update_mode(ServerInterface &socket);
};
} // namespace sls

View File

@@ -1,80 +0,0 @@
#include "MatterhornServer.h"
#include "communication_funcs.h"
#include "sls/logger.h"
#include "sls/network_utils.h"
#include "sls/sls_detector_defs.h"
#include "sls/versionAPI.h"
namespace sls {
BaseMatterhornServer::BaseMatterhornServer(uint16_t port) {
validatePortNumber(port);
// mmh do I want a virtual server inheriting from parent Server class? and
// parent Matterhorn class - probably better
#ifdef VIRTUAL
udpDetails[0].srcip = LOCALHOSTIP_INT;
#endif
udpDetails[0].srcport = DEFAULT_UDP_SRC_PORTNO;
udpDetails[0].dstport = DEFAULT_UDP_DST_PORTNO;
// TODO: when do i set the udp mac and ip ?
tcpInterface = std::make_unique<TCPInterface>(
function_table, port); // TODO: need a tcp and udp interface
// should maybe be part of the constructor?
tcpInterface->startTCPServer();
// need a function to setup detector - e.g. set all registers etc.
}
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<ReturnCode>(socket.sendResult(
version_cstr)); // TODO: check what would be possible return codes!!!
}
ReturnCode BaseMatterhornServer::get_detector_type(ServerInterface &socket) {
int detectortype = slsDetectorDefs::detectorType::MATTERHORN;
return static_cast<ReturnCode>(socket.sendResult(detectortype));
}
std::string BaseMatterhornServer::getMatterhornServerVersion() {
return APIMATTERHORN;
}
size_t BaseMatterhornServer::num_udp_interfaces() const {
return udpDetails.size();
}
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));
}
ReturnCode
BaseMatterhornServer::get_num_udp_interfaces(ServerInterface &socket) {
int numUDPInterfaces = static_cast<int>(num_udp_interfaces());
return static_cast<ReturnCode>(socket.sendResult(numUDPInterfaces));
}
ReturnCode MatterhornServer::get_update_mode(ServerInterface &socket) {
return static_cast<ReturnCode>(
socket.sendResult(static_cast<int>(updateMode)));
}
ReturnCode BaseMatterhornServer::get_source_udp_mac(ServerInterface &socket) {
uint64_t srcMac = udpDetails[0].srcmac;
return static_cast<ReturnCode>(socket.sendResult(srcMac));
}
} // namespace sls

View File

@@ -1,6 +1,6 @@
#include "CommandLineOptions.h"
#include "MatterhornServer.h"
#include "StopServer.h"
#include "VirtualMatterhornServer.h"
#include "sls/logger.h"
#include "sls/sls_detector_exceptions.h"
#include <semaphore.h>
@@ -61,7 +61,7 @@ int main(int argc, char *argv[]) {
// std::signal(SIGTERM, childSigTermHandler);
LOG(TLogLevel::logINFOBLUE) << "Stop Server [" << opts.port + 1 << "]";
try {
MatterhornServer stopServer(opts.port + 1);
VirtualMatterhornServer stopServer(opts.port + 1);
} catch (...) {
LOG(TLogLevel::logINFOBLUE)
<< "Exiting Stop Server [ Tid: " << gettid() << " ]";
@@ -79,7 +79,9 @@ int main(int argc, char *argv[]) {
LOG(TLogLevel::logINFOBLUE) << "Control Server [" << opts.port << "]\n";
try {
sls::MatterhornServer server(opts.port);
VirtualMatterhornServer server(
opts.port); // TODO use virtual if compiled with virtual
// simulators on
} catch (...) {
kill(child_pid, SIGTERM); // tell child to exit
LOG(sls::logINFOBLUE) << "Exiting [ Tid: " << gettid() << " ]";

View File

@@ -0,0 +1,29 @@
#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<ReturnCode>(socket.sendResult(initial_checks_passed));
}
ReturnCode MatterhornServer::get_update_mode(ServerInterface &socket) {
return static_cast<ReturnCode>(
socket.sendResult(static_cast<int>(updateMode)));
}
} // namespace sls

View File

@@ -1,21 +1,30 @@
#include "MatterhornServer.h"
#include "VirtualMatterhornServer.h"
namespace sls {
VirtualMatterhornServer::VirtualMatterhornServer(uint16_t port)
: BaseMatterhornServer(port) {
: BaseMatterhornServer<VirtualMatterhornServer>(port) {
udpDetails[0].srcip = LOCALHOSTIP_INT;
udpDetails[0].srcport = DEFAULT_UDP_SRC_PORTNO;
udpDetails[0].dstport = DEFAULT_UDP_DST_PORTNO;
// TODO: when do i set the udp mac and ip ?
BaseMatterhornServer(port);
tcpInterface = std::make_unique<TCPInterface>(
function_table, port); // TODO: need a tcp and udp interface
// 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));
}
ReturnCode VirtualMatterhornServer::get_update_mode(ServerInterface &socket) {
return static_cast<ReturnCode>(
socket.sendResult(static_cast<int>(updateMode)));
}
} // namespace sls