Commit 4cbe905d authored by Giuseppe Carboni's avatar Giuseppe Carboni
Browse files

Updated SRT MinorServo Libraries and tests

parent ba9e2a75
Loading
Loading
Loading
Loading
+3 −31
Original line number Diff line number Diff line
@@ -3,42 +3,14 @@

#include <sstream>
#include <map>
#include <variant>
#include <type_traits>
#include <mutex>
#include <shared_mutex>
#include <IRA>

#include <Cplusplus11Helper.h>
C11_IGNORE_WARNING_PUSH
C11_IGNORE_WARNING("-Wunused-function")

static std::ostream& operator<<(std::ostream& out, const std::variant<long, double, std::string>& value)
{
    std::visit([&out](const auto& val) { out << val; }, value);
    return out;
}

C11_IGNORE_WARNING_POP
#include "SRTMinorServoUtils.h"


namespace MinorServo
{
    /**
     * The following templates are useful if you want to check if a given type for the SRTMinorServoAnswerMap is accepted
     */
    template <typename T>
    struct is_string : public std::disjunction<std::is_same<char*, std::decay_t<T>>, std::is_same<const char*, std::decay_t<T>>, std::is_same<std::string, std::decay_t<T>>> {};

    template <typename T>
    inline constexpr bool is_string_v = is_string<T>::value;

    template <typename T>
    struct is_known : public std::disjunction<std::is_arithmetic<std::decay_t<T>>, is_string<std::decay_t<T>>> {};

    template <typename T>
    inline constexpr bool is_known_v = is_known<T>::value;

    class SRTMinorServoAnswerMap : private  std::map<std::string, std::variant<long, double, std::string>>
    {
        /**
@@ -114,7 +86,7 @@ namespace MinorServo
        template <typename T>
        T get(const std::string& key) const
        {
            if constexpr(std::negation_v<MinorServo::is_known<T>>)
            if constexpr(std::negation_v<is_known<T>>)
            {
                throw std::runtime_error("Unsupported type.");
            }
@@ -144,7 +116,7 @@ namespace MinorServo
        template <typename T>
        void put(const std::string& key, const T& value)
        {
            if constexpr(std::negation_v<MinorServo::is_known<T>>)
            if constexpr(std::negation_v<is_known<T>>)
            {
                throw std::runtime_error("Unsupported type.");
            }
+4 −12
Original line number Diff line number Diff line
@@ -23,7 +23,7 @@ namespace MinorServo
    /**
     * Testing class forward declaration.
     * The declaration of this class can be found in the SRTMinorServoTestingSocket.h header file.
     * Instructions on how to use this for testing purposes can be found there as well.
     * A developer must use this class for testing purposes if he needs to destroy the singleton socket instance as well.
     */
    class SRTMinorServoTestingSocket;

@@ -39,8 +39,7 @@ namespace MinorServo
         * @param ip_address the IP address to which the socket will connect
         * @param port the port to which the socket will connect
         * @param timeout the timeout, in seconds, for the communication to be considered failed
         * @throw MinorServoErrors::MinorServoErrorsEx when the user calls this method a second time with different IP address and port arguments (non testing mode)
         * @throw MinorServoErrors::CommunicationErrorExImpl (testing mode)
         * @throw MinorServoErrors::MinorServoErrorsEx when the user calls this method a second time with different IP address and port arguments
         * @return the singleton socket instance, eventually connected to the given IP address and port, by reference
         */
        static SRTMinorServoSocket& getInstance(std::string ip_address, int port, double timeout=SOCKET_TIMEOUT);
@@ -56,8 +55,7 @@ namespace MinorServo
         * Sends a command on the socket and returns the received answer, if any
         * @param command the command to be sent over the socket
         * @param map, optional SRTMinorServoAnswerMap object. If provided, the 'map' argument content gets updated with the newly received answer
         * @throw MinorServoErrors::MinorServoErrorsEx when the operation of sending or receiving fails unexpectedly (non testing mode)
         * @throw MinorServoErrors::CommunicationErrorExImpl (testing mode)
         * @throw MinorServoErrors::MinorServoErrorsEx when the operation of sending or receiving fails unexpectedly
         * @return the received answer to the given command
         */
        SRTMinorServoAnswerMap sendCommand(std::string command, std::optional<std::reference_wrapper<SRTMinorServoAnswerMap>> map = {});
@@ -99,8 +97,7 @@ namespace MinorServo

        /**
         * Connection function. It gets called every time the socket gets disconnected
         * throw MinorServoErrors::MinorServoErrorsEx when the connection attempt fails (non testing mode)
         * throw MinorServoErrors::CommunicationErrorExImpl (testing mode)
         * throw MinorServoErrors::MinorServoErrorsEx when the connection attempt fails
         */
        void connect();

@@ -130,11 +127,6 @@ namespace MinorServo
         */
        static std::mutex c_mutex;

        /**
         * Boolean indicating whether we are testing the socket or not
         */
        inline static bool c_testing = false;

        /**
         * Socket status enumerator
         */
+0 −40
Original line number Diff line number Diff line
@@ -6,48 +6,8 @@ namespace MinorServo
    {
        /**
         * This class is a friend class of SRTMinorServoSocket. It can be used for testing purposes without altering the behavior of the original class.
         * Instructions on how to use this class inside tests:
         * 1) Declare the test class with a forward declaration
         * 2) Define the FRIEND_CLASS_DECLARATION macro
         * 3) Include this header file
         * 4) Finally implement the test class
         * Example:
         *
         * ...
         * class TestClass;
         * #define FRIEND_CLASS_DECLARATION friend class ::TestClass;
         * #include "SRTMinorServoTestingSocket.h"
         *
         * class TestClass : public ::testing::Test
         * {
         * ...
         */

        /**
         * This is a macro that each test file will have to define prior to including this header file.
         * It can be a single or multiple lines each one containing a friend class declaration.
         */
        FRIEND_CLASS_DECLARATION;
    public:
        /**
         * Ovverride of the original SRTMinorServoSocket getInstance methods. Before doing anything, they set the c_testing variable of the original class to true.
         * This changes how the exceptions are thrown.
         * In non testing purposes, exceptions are thrown as MinorServoErrorsEx
         * In testing purposes, exceptions are thrown as they are (ExImpl)
         * This change in behavior allow for better testing and debugging purposes, while still allowing the socket to throw the base MinorServoErrorsEx when not used in testing purposes.
         * This allow us to avoid catching exceptions in the component, since MinorServoErrorsEx are already captured by CORBA
         */
        static SRTMinorServoSocket& getInstance(std::string ip_address, int port, double timeout=SOCKET_TIMEOUT)
        {
            SRTMinorServoSocket::c_testing = true;
            return SRTMinorServoSocket::getInstance(ip_address, port, timeout);
        }
        static SRTMinorServoSocket& getInstance()
        {
            SRTMinorServoSocket::c_testing = true;
            return SRTMinorServoSocket::getInstance();
        }

        /**
         * This method explicitly destroys the singleton socket instance.
         * Each test in the same test file is executed under the same process, therefore a singleton instance that does not get destroyed will still exist in the next executed tests.
+149 −0
Original line number Diff line number Diff line
#ifndef _SRTMINORSERVOUTILS_H
#define _SRTMINORSERVOUTILS_H
#include <variant>
#include <type_traits>
#include <Cplusplus11Helper.h>
#include <IRA>
#include <ComponentErrors.h>

/**
 * The following templates are useful if you want to check if a given type for the SRTMinorServoAnswerMap is accepted
 */
template <typename T>
struct is_atomic { static constexpr bool value = false; };

template <typename T>
struct is_atomic<std::atomic<T>> { static constexpr bool value = true; };

template <typename T>
inline constexpr bool is_atomic_v = is_atomic<T>::value;

template <typename T, typename... Ts>
struct is_any : public std::disjunction<std::is_same<T, Ts>...> {};

template <typename T, typename... Ts>
inline constexpr bool is_any_v = (std::is_same_v<T, Ts> || ...);

template <typename T>
struct is_string : public std::disjunction<is_any<std::decay_t<T>, char*, const char*, std::string>> {};

template <typename T>
inline constexpr bool is_string_v = is_string<T>::value;

template <typename T>
struct is_known : public std::disjunction<std::is_arithmetic<std::decay_t<T>>, is_string<std::decay_t<T>>> {};

template <typename T>
inline constexpr bool is_known_v = is_known<T>::value;

template <typename T, typename Enable = std::enable_if_t<std::disjunction_v<is_known<T>, std::is_same<T, std::vector<double>>>>>
struct DB_type
{
    using type = std::conditional_t<std::disjunction_v<is_string<T>, std::is_same<T, std::vector<double>>>, IRA::CString, std::conditional_t<std::is_integral_v<T>, long, double>>;
};

template <typename T>
T getCDBValue(maci::ContainerServices* container_services, const std::string& field, const std::string& component="")
{
    return getCDBValue<T>(container_services, field.c_str(), component.c_str());
}

template <typename T>
T getCDBValue(maci::ContainerServices* container_services, const char* field, const char* component="")
{
    using C = typename DB_type<T>::type;

    C temp;
    if(IRA::CIRATools::getDBValue(container_services, field, temp, "alma/", component))
    {
        if constexpr(std::is_same_v<T, std::vector<double>>)
        {
            std::vector<double> values;
            std::istringstream iss(std::string(temp).c_str());
            std::string token;
            while(std::getline(iss, token, ','))
            {
                double value;
                try
                {
                    value = std::stod(token);
                }
                catch(std::invalid_argument& ia)
                {
                    _EXCPT(ComponentErrors::CDBAccessExImpl, ex, "SRTMinorServoUtils::getCDBValue()");
                    ex.setFieldName(field);
                    throw ex.getComponentErrorsEx();
                }
                catch(std::out_of_range& oor)
                {
                    _EXCPT(ComponentErrors::ValueOutofRangeExImpl, ex, "SRTMinorServoUtils::getCDBValue()");
                    ex.setValueName(field);
                    ex.setValueLimit(token.find('-') == std::string::npos ? std::numeric_limits<double>::max() : std::numeric_limits<double>::min());
                    throw ex.getComponentErrorsEx();
                }

                values.push_back(value);
            }
            return values;
        }
        else if constexpr(std::is_same_v<C, IRA::CString>)
        {
            return (T)std::string(temp).c_str();
        }
        else
        {
            return T(temp);
        }
    }
    else
    {
        _EXCPT(ComponentErrors::CDBAccessExImpl, ex, "SRTMinorServoUtils::getCDBValue()");
        ex.setFieldName(field);
        throw ex.getComponentErrorsEx();  // Maybe throw the plain ex
    }
}

const char* getReasonFromEx(const auto& ex)
{
    std::string reason = "Unknown reason";

    for(auto [name, value] : ex.errorTrace.data)
    {
        if(strcmp(name, "Reason") == 0)
        {
            reason = value;
            break;
        }
    }

    return reason.c_str();
}

const char* getErrorFromEx(const auto& ex)
{
    std::string error(ex.errorTrace.routine);

    for(auto [name, value] : ex.errorTrace.data)
    {
        if(strcmp(name, "Reason") == 0)
        {
            error += ": " + std::string(value);
            break;
        }
    }

    return error.c_str();
}

C11_IGNORE_WARNING_PUSH
C11_IGNORE_WARNING("-Wunused-function")

static std::ostream& operator<<(std::ostream& out, const std::variant<long, double, std::string>& value)
{
    std::visit([&out](const auto& val) { out << val; }, value);
    return out;
}

C11_IGNORE_WARNING_POP

#endif
+4 −4
Original line number Diff line number Diff line
@@ -54,7 +54,7 @@ xxxxx_LIBS =
#
# Includes (.h) files (public only)
# ---------------------------------
INCLUDES        = SRTMinorServoCommandLibrary.h SRTMinorServoAnswerMap.h SRTMinorServoSocket.h SRTMinorServoTestingSocket.h #hexlib.h
INCLUDES        = SRTMinorServoCommandLibrary.h SRTMinorServoAnswerMap.h SRTMinorServoSocket.h SRTMinorServoTestingSocket.h SRTMinorServoUtils.h #hexlib.h

#
# Libraries (public and local)
@@ -64,14 +64,14 @@ LIBRARIES_L =
SRTMinorServoLibrary_OBJECTS = hexlib
SRTMinorServoLibrary_LIBS = gsl gslcblas m
SRTMinorServoCommandLibrary_OBJECTS = SRTMinorServoCommandLibrary
SRTMinorServoCommandLibrary_CFLAGS = -std=c++17
SRTMinorServoCommandLibrary_CFLAGS = -std=c++17 -fconcepts
SRTMinorServoCommandLibrary_LIBS = pthread IRALibrary
PySRTMinorServoCommandLibrary_OBJECTS = PySRTMinorServoCommandLibrary
PySRTMinorServoCommandLibrary_CFLAGS = -std=c++17
PySRTMinorServoCommandLibrary_CFLAGS = -std=c++17 -fconcepts
PySRTMinorServoCommandLibrary_LIBS = SRTMinorServoCommandLibrary boost_python3
SRTMinorServoSocketLibrary_OBJECTS = SRTMinorServoSocket
SRTMinorServoSocketLibrary_LIBS = IRALibrary ComponentErrors MinorServoErrors SRTMinorServoCommandLibrary
SRTMinorServoSocket_CFLAGS = -std=c++17
SRTMinorServoSocket_CFLAGS = -std=c++17 -fconcepts

#
# <brief description of lllll library>
Loading