LCOV - code coverage report
Current view: top level - apps/stateRuleEngine - indiCompRules.hpp (source / functions) Coverage Total Hit
Test: MagAOX Lines: 60.4 % 328 198
Test Date: 2026-01-03 21:03:39 Functions: 80.9 % 47 38

            Line data    Source code
       1              : /** \file indiCompRules.hpp
       2              :   * \brief The rules for the MagAO-X stateRuleEngine
       3              :   *
       4              :   * \ingroup stateRuleEngine_files
       5              :   */
       6              : 
       7              : #ifndef stateRuleEngine_indiCompRules_hpp
       8              : #define stateRuleEngine_indiCompRules_hpp
       9              : 
      10              : #include <variant>
      11              : 
      12              : #include "../../libMagAOX/libMagAOX.hpp" //Note this is included on command line to trigger pch
      13              :                                          //Included here for standalone testing of this file
      14              : #include <mx/mxException.hpp>
      15              : 
      16              : /// Logical comparisons for the INDI rules
      17              : enum class ruleComparison
      18              : {
      19              :     Eq,        ///< Equal
      20              :     Neq,       ///< Not equal
      21              :     Lt,        ///< Less than
      22              :     Gt,        ///< Greater than
      23              :     LtEq,      ///< Less than or equal to
      24              :     GtEq,      ///< Greater than or equal to
      25              :     And,       ///< boolean and
      26              :     Nand,      ///< boolean nand
      27              :     Or,        ///< boolean or
      28              :     Nor,       ///< boolean nor
      29              :     Imply,
      30              :     Nimply,
      31              :     Xor = Neq, ///< boolean xor, equivalent to not equal
      32              :     Xnor = Eq  ///< boolean xnor, equivalent to equal
      33              : };
      34              : 
      35              : /// Get the \ref ruleComparison member from a string representation.
      36              : /** Needed for processing configuration files
      37              :   */
      38            0 : ruleComparison string2comp( const std::string & cstr )
      39              : {
      40            0 :     if(cstr == "Eq")
      41              :     {
      42            0 :         return ruleComparison::Eq;
      43              :     }
      44            0 :     else if(cstr == "Neq")
      45              :     {
      46            0 :         return ruleComparison::Neq;
      47              :     }
      48            0 :     else if(cstr == "Lt")
      49              :     {
      50            0 :         return ruleComparison::Lt;
      51              :     }
      52            0 :     else if(cstr == "Gt")
      53              :     {
      54            0 :         return ruleComparison::Gt;
      55              :     }
      56            0 :     else if(cstr == "LtEq")
      57              :     {
      58            0 :         return ruleComparison::LtEq;
      59              :     }
      60            0 :     else if(cstr == "GtEq")
      61              :     {
      62            0 :         return ruleComparison::GtEq;
      63              :     }
      64            0 :     else if(cstr == "And")
      65              :     {
      66            0 :         return ruleComparison::And;
      67              :     }
      68            0 :     else if(cstr == "Nand")
      69              :     {
      70            0 :         return ruleComparison::Nand;
      71              :     }
      72            0 :     else if(cstr == "Or")
      73              :     {
      74            0 :         return ruleComparison::Or;
      75              :     }
      76            0 :     else if(cstr == "Nor")
      77              :     {
      78            0 :         return ruleComparison::Nor;
      79              :     }
      80            0 :     else if(cstr == "Xor")
      81              :     {
      82            0 :         return ruleComparison::Xor;
      83              :     }
      84            0 :     else if(cstr == "Xnor")
      85              :     {
      86            0 :         return ruleComparison::Xnor;
      87              :     }
      88            0 :     else if(cstr == "Imply")
      89              :     {
      90            0 :         return ruleComparison::Imply;
      91              :     }
      92            0 :     else if(cstr == "Nimply")
      93              :     {
      94            0 :         return ruleComparison::Nimply;
      95              :     }
      96              :     else
      97              :     {
      98            0 :         mxThrowException(mx::err::invalidarg, "string2comp", cstr + " is not a valid comparison");
      99              :     }
     100              : }
     101              : 
     102              : /// Reporting priorities for rules
     103              : enum class rulePriority
     104              : {
     105              :     none,    ///< Don't publish
     106              :     info,    ///< For information only
     107              :     caution, ///< Caution -- make sure you know what you're doing
     108              :     warning, ///< Warning -- something is probably wrong, you should check
     109              :     alert    ///< Alert -- something is definitely wrong, you should take action
     110              : };
     111              : 
     112              : /// Get the \ref rulePriority member from a string representation.
     113              : /** Needed for processing configuration files
     114              :   */
     115            0 : rulePriority string2priority(const std::string & pstr)
     116              : {
     117            0 :     if(pstr == "none")
     118              :     {
     119            0 :         return rulePriority::none;
     120              :     }
     121            0 :     else if(pstr == "info")
     122              :     {
     123            0 :         return rulePriority::info;
     124              :     }
     125            0 :     else if(pstr == "caution")
     126              :     {
     127            0 :         return rulePriority::caution;
     128              :     }
     129            0 :     else if(pstr == "warning")
     130              :     {
     131            0 :         return rulePriority::warning;
     132              :     }
     133            0 :     else if(pstr == "alert")
     134              :     {
     135            0 :         return rulePriority::alert;
     136              :     }
     137              :     else
     138              :     {
     139            0 :         mxThrowException(mx::err::invalidarg, "string2priority", pstr + " is not a valid priority");
     140              :     }
     141              : }
     142              : 
     143              : /// Virtual base-class for all rules
     144              : /** Provides error handling and comparison functions.
     145              :   * Derived classes must implement valid() and value().
     146              :   */
     147              : struct indiCompRule
     148              : {
     149              : public:
     150              : 
     151              :     /// In-band error reporting type
     152              :     typedef std::variant<bool, std::string> boolorerr_t;
     153              : 
     154              :     /// Check if returned value indicates an error
     155          152 :     bool isError(boolorerr_t rv /**< [in] the return value to check*/)
     156              :     {
     157          152 :         return (rv.index() > 0);
     158              :     }
     159              : 
     160              : protected:
     161              : 
     162              :     /// The reporting priority for this rule
     163              :     rulePriority m_priority {rulePriority::none};
     164              : 
     165              :     /// The message used for notifications
     166              :     std::string m_message;
     167              : 
     168              :     /// The comparison for this rule
     169              :     ruleComparison m_comparison {ruleComparison::Eq};
     170              : 
     171              : public:
     172              : 
     173              :     /// Virtual destructor
     174           63 :     virtual ~indiCompRule()
     175           63 :     {}
     176              : 
     177              :     /// Set priority of this rule
     178            0 :     void priority( const rulePriority & p /**< [in] the new priority */)
     179              :     {
     180            0 :         m_priority = p;
     181            0 :     }
     182              : 
     183              :     /// Get the rule priority
     184              :     /**
     185              :       * \returns the current rule priority
     186              :       */
     187            0 :     const rulePriority & priority()
     188              :     {
     189            0 :         return m_priority;
     190              :     }
     191              : 
     192              :     /// Set the message
     193            0 :     void message(const std::string & m /**< [in] the new message*/)
     194              :     {
     195            0 :         m_message = m;
     196            0 :     }
     197              : 
     198              :     /// Get the message
     199              :     /**
     200              :       * \returns the current message
     201              :       */
     202            0 :     const std::string & message()
     203              :     {
     204            0 :         return m_message;
     205              :     }
     206              : 
     207              :     /// Set the comparison for this rule
     208           72 :     void comparison( const ruleComparison & c /**< [in] the new comparison*/)
     209              :     {
     210           72 :         m_comparison = c;
     211           72 :     }
     212              : 
     213              :     /// Get the rule comparison
     214              :     /**
     215              :       * \returns the current rule comparison
     216              :       *
     217              :       */
     218              :     const ruleComparison & comparison()
     219              :     {
     220              :         return m_comparison;
     221              :     }
     222              : 
     223              :     /// Report whether the rule is valid as configured
     224              :     /** If not valid, the return value is a std::string with the reason.
     225              :       * If valid, the return value is a bool set to true.
     226              :       */
     227              :     virtual boolorerr_t valid() = 0;
     228              : 
     229              :     /// Get the value of this rule
     230              :     /**
     231              :       * \returns the result of the comparison defined by the rule
     232              :       */
     233              :     virtual bool value() = 0;
     234              : 
     235              :     /// Compare two strings
     236              :     /** String comparison can only be Eq or Neq.
     237              :       *
     238              :       * \returns true if the comparison is true
     239              :       * \returns false if the comparison is false
     240              :       * \returns std::string with error message if the comparison is not valid
     241              :       */
     242           22 :     boolorerr_t compTxt( const std::string & str1, ///< [in] the first string to compare
     243              :                          const std::string & str2  ///< [in] the second string to compare
     244              :                        )
     245              :     {
     246           22 :         boolorerr_t rv = false;
     247              : 
     248           22 :         switch(m_comparison)
     249              :         {
     250           18 :             case ruleComparison::Eq:
     251           18 :                 if(str1 == str2) rv = true;
     252           18 :                 break;
     253            4 :             case ruleComparison::Neq:
     254            4 :                 if(str1 != str2) rv = true;
     255            4 :                 break;
     256            0 :             default:
     257            0 :                 rv = "operator not valid for string comparison";
     258              :         }
     259              : 
     260           22 :         return rv;
     261            0 :     }
     262              : 
     263              :     /// Compare two switches
     264              :     /** Switch comparison can only be Eq or Neq.
     265              :       *
     266              :       * \returns true if the comparison is true
     267              :       * \returns false if the comparison is false
     268              :       * \returns std::string with error message if the comparison is not valid
     269              :       */
     270           16 :     boolorerr_t compSw( const pcf::IndiElement::SwitchStateType & sw1, ///< [in] the first switch to compare
     271              :                         const pcf::IndiElement::SwitchStateType & sw2  ///< [in] the first switch to compare
     272              :                       )
     273              :     {
     274           16 :         boolorerr_t rv = false;
     275              : 
     276           16 :         switch(m_comparison)
     277              :         {
     278            8 :             case ruleComparison::Eq:
     279            8 :                 if(sw1 == sw2) rv = true;
     280            8 :                 break;
     281            8 :             case ruleComparison::Neq:
     282            8 :                 if(sw1 != sw2) rv = true;
     283            8 :                 break;
     284            0 :             default:
     285            0 :                 rv = "operator not valid for switch comparison";
     286              :         }
     287              : 
     288           16 :         return rv;
     289            0 :     }
     290              : 
     291              :     /// Compare two numbers
     292              :     /** The comparison is (num1 comp num2), e.g. (num1 \< num2).
     293              :       * A tolerance is included for floating point equality.
     294              :       *
     295              :       * \returns true if the comparison is true
     296              :       * \returns false if the comparison is false
     297              :       * \returns std::string with error message if the comparison is not valid
     298              :       */
     299           16 :     boolorerr_t compNum( const double & num1, ///< [in] the first number to compare
     300              :                          const double & num2, ///< [in] the second number to compare
     301              :                          const double & tol   ///< [in] the tolerance for the comparison
     302              :                        )
     303              :     {
     304           16 :         boolorerr_t rv = false;
     305              : 
     306           16 :         switch(m_comparison)
     307              :         {
     308            6 :             case ruleComparison::Eq:
     309            6 :                 if( fabs(num1 - num2) <= tol ) rv = true;
     310            6 :                 break;
     311            0 :             case ruleComparison::Neq:
     312            0 :                 if( fabs(num1 - num2) > tol ) rv = true;
     313            0 :                 break;
     314            2 :             case ruleComparison::Lt:
     315            2 :                 if( num1 < num2) rv = true;
     316            2 :                 break;
     317            2 :             case ruleComparison::Gt:
     318            2 :                 if( num1 > num2) rv = true;
     319            2 :                 break;
     320            3 :             case ruleComparison::LtEq:
     321            3 :                 if( fabs(num1 - num2) <= tol ) rv = true;
     322            2 :                 else if (num1 < num2) rv = true;
     323            3 :                 break;
     324            3 :             case ruleComparison::GtEq:
     325            3 :                 if( fabs(num1 - num2) <= tol ) rv = true;
     326            2 :                 else if (num1 > num2) rv = true;
     327            3 :                 break;
     328            0 :             default:
     329            0 :                 rv = "operator not valid for compNum";
     330              :         }
     331              : 
     332           16 :         return rv;
     333            0 :     }
     334              : 
     335              :     /// Compare two booleans
     336              :     /**
     337              :       * \returns true if the comparison is true
     338              :       * \returns false if the comparison is false
     339              :       * \returns std::string with error message if the comparison is not valid
     340              :       */
     341            9 :     boolorerr_t compBool( const bool & b1, ///< [in] the first bool to compare
     342              :                           const bool & b2  ///< [in] the second bool to compare
     343              :                         )
     344              :     {
     345            9 :         boolorerr_t rv = false;
     346              : 
     347            9 :         switch(m_comparison)
     348              :         {
     349            0 :             case ruleComparison::Eq:
     350            0 :                 if(b1 == b2) rv = true;
     351            0 :                 break;
     352            0 :             case ruleComparison::Neq:
     353            0 :                 if(b1 != b2) rv = true;
     354            0 :                 break;
     355            5 :             case ruleComparison::And:
     356            5 :                 if(b1 && b2) rv = true;
     357            5 :                 break;
     358            0 :             case ruleComparison::Nand:
     359            0 :                 if(!(b1 && b2)) rv = true;
     360            0 :                 break;
     361            4 :             case ruleComparison::Or:
     362            4 :                 if(b1 || b2) rv = true;
     363            4 :                 break;
     364            0 :             case ruleComparison::Nor:
     365            0 :                 if(!b1 && !b2) rv = true;
     366            0 :                 break;
     367            0 :             case ruleComparison::Imply:
     368              :                 // https://en.wikipedia.org/wiki/Material_conditional
     369            0 :                 if(!b1 || b2) rv=true;
     370            0 :                 break;
     371            0 :             case ruleComparison::Nimply:
     372              :                 // https://en.wikipedia.org/wiki/Material_nonimplication
     373            0 :                 if(b1 && !b2) rv=true;
     374            0 :                 break;
     375            0 :             default:
     376            0 :                 rv = "operator not valid for ruleCompRule";
     377              :         }
     378              : 
     379            9 :         return rv;
     380            0 :     }
     381              : };
     382              : 
     383              : /// A rule base class for testing an element in one property
     384              : struct onePropRule : public indiCompRule
     385              : {
     386              : 
     387              : protected:
     388              : 
     389              :     int m_type; ///< The property type, from pcf::IndiProperty::Type
     390              : 
     391              :     pcf::IndiProperty * m_property {nullptr}; ///< Pointer to the property
     392              : 
     393              :     std::string m_element; ///< The element name within the property
     394              : 
     395              : public:
     396              : 
     397              :     //Default c'tor is deleted, you must supply the property type
     398              :     onePropRule() = delete;
     399              : 
     400              :     /// Constructor.  You must provide the property type to construct a onePropRule
     401           40 :     explicit onePropRule( int type ) : m_type(type /**< The property type, from pcf::IndiProperty::Type*/)
     402           40 :     {}
     403              : 
     404              :     /// Set the property pointer
     405              :     /**
     406              :       * \throws mx::err::invalidarg if \p property is nullptr
     407              :       * \throws mx::err::invalidconfig if the supplied property has the wrong type
     408              :       */
     409           40 :     void property( pcf::IndiProperty * property /**< [in] the new property pointer*/)
     410              :     {
     411           40 :         if(property == nullptr)
     412              :         {
     413            0 :             mxThrowException(mx::err::invalidarg, "onePropRule::property", "property is nullptr");
     414              :         }
     415              : 
     416           40 :         if(property->getType() != m_type)
     417              :         {
     418            0 :             mxThrowException(mx::err::invalidconfig, "onePropRule::property", "property is not correct type");
     419              :         }
     420              : 
     421           40 :         m_property = property;
     422           40 :     }
     423              : 
     424              :     /// Get the property pointer
     425              :     /**
     426              :       * \returns the current value of m_property
     427              :       */
     428              :     const pcf::IndiProperty * property()
     429              :     {
     430              :         return m_property;
     431              :     }
     432              : 
     433              :     /// Set the element name
     434           40 :     void element(const std::string & el /**< [in] the new element name*/)
     435              :     {
     436           40 :         m_element = el;
     437           40 :     }
     438              : 
     439              :     /// Get the element name
     440              :     /**
     441              :       * \returns the current value of m_element
     442              :       */
     443              :     const std::string & element()
     444              :     {
     445              :         return m_element;
     446              :     }
     447              : 
     448              :     /// Check if this rule is valid
     449              :     /** The rule is valid if the property pointer is not null, and the element
     450              :       * is contained within the property.
     451              :       *
     452              :       * If not valid, the return value is a std::string with the reason.
     453              :       * If valid, the return value is a bool set to true.
     454              :       */
     455           62 :     virtual boolorerr_t valid()
     456              :     {
     457           62 :         boolorerr_t rv;
     458           62 :         if(m_property == nullptr)
     459              :         {
     460            0 :             rv = "property is null";
     461              :         }
     462           62 :         else if(!m_property->find(m_element))
     463              :         {
     464            0 :             rv = "element is not found";
     465              :         }
     466              :         else
     467              :         {
     468           62 :             rv = true;
     469              :         }
     470              : 
     471           62 :         return rv;
     472            0 :     }
     473              : };
     474              : 
     475              : /// A rule base class for testing elements in two properties
     476              : struct twoPropRule : public indiCompRule
     477              : {
     478              : 
     479              : protected:
     480              : 
     481              :     int m_type; ///< The property type, from pcf::IndiProperty::Type
     482              : 
     483              :     pcf::IndiProperty * m_property1 {nullptr}; ///< Pointer to the first property
     484              : 
     485              :     std::string m_element1; ///< The element name within the first property
     486              : 
     487              :     pcf::IndiProperty * m_property2 {nullptr}; ///< Pointer to the second property
     488              : 
     489              :     std::string m_element2; ///< The element name within the second property
     490              : 
     491              : public:
     492              : 
     493              :     //Default c'tor is deleted, you must supply the property type
     494              :     twoPropRule() = delete;
     495              : 
     496              :     /// Constructor.  You must provide the property type to construct a twoPropRule
     497           14 :     explicit twoPropRule( int type ) : m_type(type /**< The property type, from pcf::IndiProperty::Type*/)
     498           14 :     {}
     499              : 
     500              :     /// Set the first property pointer
     501              :     /**
     502              :       * \throws mx::err::invalidarg if \p property is nullptr
     503              :       * \throws mx::err::invalidconfig if the supplied property has the wrong type
     504              :       */
     505           14 :     void property1( pcf::IndiProperty * property /**< [in] the new property pointer*/)
     506              :     {
     507           14 :         if(property == nullptr)
     508              :         {
     509            0 :             mxThrowException(mx::err::invalidarg, "twoPropRule::property1", "property is nullptr");
     510              :         }
     511              : 
     512           14 :         if(property->getType() != m_type)
     513              :         {
     514            0 :             mxThrowException(mx::err::invalidconfig, "twoPropRule::property1", "property is not correct type");
     515              :         }
     516              : 
     517           14 :         m_property1 = property;
     518           14 :     }
     519              : 
     520              :     /// Get the first property pointer
     521              :     /**
     522              :       * \returns the current value of m_property1
     523              :       */
     524              :     const pcf::IndiProperty * property1()
     525              :     {
     526              :         return m_property1;
     527              :     }
     528              : 
     529              :     /// Set the first element name
     530           14 :     void element1(const std::string & el /**< [in] the new element name*/)
     531              :     {
     532           14 :         m_element1 = el;
     533           14 :     }
     534              : 
     535              :     /// Get the first element name
     536              :     /**
     537              :       * \returns the current value of m_element1
     538              :       */
     539              :     const std::string & element1()
     540              :     {
     541              :         return m_element1;
     542              :     }
     543              : 
     544              :     /// Set the second property pointer
     545              :     /**
     546              :       * \throws mx::err::invalidarg if \p property is nullptr
     547              :       * \throws mx::err::invalidconfig if the supplied property has the wrong type
     548              :       */
     549           14 :     void property2( pcf::IndiProperty * property /**< [in] the new property pointer*/)
     550              :     {
     551           14 :         if(property == nullptr)
     552              :         {
     553            0 :             mxThrowException(mx::err::invalidarg, "twoPropRule::property2", "property is nullptr");
     554              :         }
     555              : 
     556           14 :         if(property->getType() != m_type)
     557              :         {
     558            0 :             mxThrowException(mx::err::invalidconfig, "twoPropRule::property2", "property is not correct type");
     559              :         }
     560              : 
     561           14 :         m_property2 = property;
     562           14 :     }
     563              : 
     564              :     /// Get the second property pointer
     565              :     /**
     566              :       * \returns the current value of m_property2
     567              :       */
     568              :     const pcf::IndiProperty * property2()
     569              :     {
     570              :         return m_property2;
     571              :     }
     572              : 
     573              :     /// Set the second element name
     574           14 :     void element2(const std::string & el /**< [in] the new element name*/)
     575              :     {
     576           14 :         m_element2 = el;
     577           14 :     }
     578              : 
     579              :     /// Get the second element name
     580              :     /**
     581              :       * \returns the current value of m_element2
     582              :       */
     583              :     const std::string & element2()
     584              :     {
     585              :         return m_element2;
     586              :     }
     587              : 
     588              :     /// Check if this rule is valid
     589              :     /** The rule is valid if both property pointers are not null, and the elements
     590              :       * are contained within their respective properties.
     591              :       *
     592              :       * If not valid, the return value is a std::string with the reason.
     593              :       * If valid, the return value is a bool set to true.
     594              :       */
     595           14 :     virtual boolorerr_t valid()
     596              :     {
     597           14 :         boolorerr_t rv;
     598              : 
     599           14 :         if(m_property1 == nullptr)
     600              :         {
     601            0 :             rv = "property1 is null";
     602            0 :             return rv;
     603              :         }
     604              : 
     605           14 :         if(!m_property1->find(m_element1))
     606              :         {
     607            0 :             rv = "element1 is not found";
     608            0 :             return rv;
     609              :         }
     610              : 
     611           14 :         if(m_property2 == nullptr)
     612              :         {
     613            0 :             rv = "property2 is null";
     614            0 :             return rv;
     615              :         }
     616              : 
     617           14 :         if(!m_property2->find(m_element2))
     618              :         {
     619            0 :             rv = "element2 is not found";
     620            0 :             return rv;
     621              :         }
     622              : 
     623           14 :         rv = true;
     624              : 
     625           14 :         return rv;
     626            0 :     }
     627              : };
     628              : 
     629              : /// Compare the value of a number element to a target
     630              : /**
     631              :   */
     632              : struct numValRule : public onePropRule
     633              : {
     634              : 
     635              : public:
     636              : 
     637              :     /// Name of this rule, used by config system
     638              :     static constexpr char name[] = "numVal";
     639              : 
     640              : protected:
     641              : 
     642              :     double m_target {0}; ///< The target value for comparison
     643              :     double m_tol {1e-6}; ///< The tolerance for the comparison
     644              : 
     645              : public:
     646              : 
     647              :     /// Default c'tor.
     648           14 :     numValRule() : onePropRule(pcf::IndiProperty::Number)
     649           14 :     {}
     650              : 
     651              :     /// Set the target for the comparison
     652           14 :     void target( const double & tgt /**< [in] The new target*/)
     653              :     {
     654           14 :         m_target = tgt;
     655           14 :     }
     656              : 
     657              :     /// Get the target
     658              :     /**
     659              :       * \returns the current value of m_target
     660              :       */
     661            0 :     const double & target()
     662              :     {
     663            0 :         return m_target;
     664              :     }
     665              : 
     666              :     /// Set the tolerance
     667              :     /** This is used for equality comparison to allow for floating point precision
     668              :       * and text conversions in INDI.  Set to 0 for strict comparison.
     669              :       *
     670              :       * \throws mx::err:invalidarg if the new value is negative
     671              :       */
     672            1 :     void tol( const double & t /**< [in] the new tolerance*/)
     673              :     {
     674            1 :         if(t < 0)
     675              :         {
     676            0 :             mxThrowException(mx::err::invalidarg, "numValRule::tol", "tolerance can't be negative");
     677              :         }
     678              : 
     679            1 :         m_tol = t;
     680            1 :     }
     681              : 
     682              :     /// Get the tolerance
     683              :     /**
     684              :       * \returns the current value of m_tol
     685              :       */
     686            0 :     const double & tol()
     687              :     {
     688            0 :         return m_tol;
     689              :     }
     690              : 
     691              :     /// Get the value of this rule
     692              :     /** First checks if the rule is currently valid.  The performs the comparison and returns the result.
     693              :       *
     694              :       * \returns the value of the comparison, true or false
     695              :       *
     696              :       * \throws mx::err::invalidconfig if the rule is not currently valid
     697              :       * \throws mx::err::invalidconfig on an error from the comparison
     698              :       *
     699              :       */
     700           14 :     virtual bool value()
     701              :     {
     702           14 :         boolorerr_t rv = valid();
     703           14 :         if(isError(rv))
     704              :         {
     705            0 :             mxThrowException(mx::err::invalidconfig, "numValRule::value", std::get<std::string>(rv));
     706              :         }
     707              : 
     708           14 :         double val = (*m_property)[m_element].get<double>();
     709              : 
     710           14 :         rv = compNum(val, m_target, m_tol);
     711           14 :         if(isError(rv))
     712              :         {
     713            0 :             mxThrowException(mx::err::invalidconfig, "numValRule::value", std::get<std::string>(rv));
     714              :         }
     715              : 
     716           28 :         return std::get<bool>(rv);
     717           14 :     }
     718              : };
     719              : 
     720              : /// Compare the value of a text element to a target value
     721              : /** Can only be Eq or Neq.
     722              :   */
     723              : struct txtValRule : public onePropRule
     724              : {
     725              : 
     726              : public:
     727              : 
     728              :     /// Name of this rule, used by config system
     729              :     static constexpr char name[] = "txtVal";
     730              : 
     731              : protected:
     732              :     std::string m_target; ///< The target value for comparison
     733              : 
     734              : public:
     735              : 
     736              :     /// Default c'tor.
     737           18 :     txtValRule() : onePropRule(pcf::IndiProperty::Text)
     738           18 :     {}
     739              : 
     740              :     /// Set the target for the comparison
     741           18 :     void target(const std::string & target /**< [in] The new target*/)
     742              :     {
     743           18 :         m_target = target;
     744           18 :     }
     745              : 
     746              :     /// Get the target
     747              :     /**
     748              :       * \returns the current value of m_target
     749              :       */
     750            0 :     const std::string & target()
     751              :     {
     752            0 :         return m_target;
     753              :     }
     754              : 
     755              :     /// Get the value of this rule
     756              :     /** First checks if the rule is currently valid.  The performs the comparison and returns the result.
     757              :       *
     758              :       * \returns the value of the comparison, true or false
     759              :       *
     760              :       * \throws mx::err::invalidconfig if the rule is not currently valid
     761              :       * \throws mx::err::invalidconfig on an error from the comparison
     762              :       *
     763              :       */
     764           18 :     virtual bool value()
     765              :     {
     766           18 :         boolorerr_t rv = valid();
     767           18 :         if(isError(rv))
     768              :         {
     769            0 :             mxThrowException(mx::err::invalidconfig, "txtValRule::value", std::get<std::string>(rv));
     770              :         }
     771              : 
     772           18 :         rv = compTxt((*m_property)[m_element].get(), m_target);
     773           18 :         if(isError(rv))
     774              :         {
     775            0 :             mxThrowException(mx::err::invalidconfig, "txtValRule::value()", std::get<std::string>(rv));
     776              :         }
     777              : 
     778           36 :         return std::get<bool>(rv);
     779           18 :     }
     780              : };
     781              : 
     782              : /// Compare the value of a switch to a target value
     783              : /** Can only be Eq or Neq to On or Off.
     784              :   */
     785              : struct swValRule : public onePropRule
     786              : {
     787              : 
     788              : public:
     789              : 
     790              :     /// Name of this rule, used by config system
     791              :     static constexpr char name[] = "swVal";
     792              : 
     793              : protected:
     794              :     pcf::IndiElement::SwitchStateType m_target {pcf::IndiElement::UnknownSwitchState}; ///< The target value for comparison
     795              : 
     796              : public:
     797              : 
     798              :     /// Default c'tor.
     799            8 :     swValRule() : onePropRule(pcf::IndiProperty::Switch )
     800            8 :     {}
     801              : 
     802              :     /// Set the target for the comparison
     803              :     void target(const pcf::IndiElement::SwitchStateType & ss /**< [in] The new target*/)
     804              :     {
     805              :         m_target = ss;
     806              :     }
     807              : 
     808              :     /// Set the target for the comparison
     809              :     /** This version provided for config file processing.
     810              :       *
     811              :       * \throws mx::err::invalidarg if switchState is something other than "On" or Off
     812              :       */
     813            8 :     void target(const std::string & switchState /**< [in] The new target*/)
     814              :     {
     815            8 :         if(switchState == "On")
     816              :         {
     817            4 :             m_target = pcf::IndiElement::On;
     818              :         }
     819            4 :         else if(switchState == "Off")
     820              :         {
     821            4 :             m_target = pcf::IndiElement::Off;
     822              :         }
     823              :         else
     824              :         {
     825            0 :             mxThrowException(mx::err::invalidarg, "swValRule::target", "invalid switch state");
     826              :         }
     827            8 :     }
     828              : 
     829              :     /// Get the target
     830              :     /**
     831              :       * \returns the current value of m_target
     832              :       */
     833              :     const pcf::IndiElement::SwitchStateType & target()
     834              :     {
     835              :         return m_target;
     836              :     }
     837              : 
     838              :     /// Get the value of this rule
     839              :     /** First checks if the rule is currently valid.  The performs the comparison and returns the result.
     840              :       *
     841              :       * \returns the value of the comparison, true or false
     842              :       *
     843              :       * \throws mx::err::invalidconfig if the rule is not currently valid
     844              :       * \throws mx::err::invalidconfig on an error from the comparison
     845              :       *
     846              :       */
     847            8 :     virtual bool value()
     848              :     {
     849            8 :         boolorerr_t rv = valid();
     850            8 :         if(isError(rv))
     851              :         {
     852            0 :             mxThrowException(mx::err::invalidconfig, "swValRule::value", std::get<std::string>(rv));
     853              :         }
     854              : 
     855            8 :         rv = compSw((*m_property)[m_element].getSwitchState(), m_target);
     856            8 :         if(isError(rv))
     857              :         {
     858            0 :             mxThrowException(mx::err::invalidconfig, "elCompSwRule::value()", std::get<std::string>(rv));
     859              :         }
     860              : 
     861           16 :         return std::get<bool>(rv);
     862            8 :     }
     863              : };
     864              : 
     865              : /// Compare two elements based on their numeric values
     866              : struct elCompNumRule : public twoPropRule
     867              : {
     868              : 
     869              : public:
     870              : 
     871              :     /// Name of this rule, used by config system
     872              :     static constexpr char name[] = "elCompNum";
     873              : 
     874              : protected:
     875              :     double m_tol {1e-6}; ///< The tolerance for the comparison
     876              : 
     877              : public:
     878              : 
     879              :     /// Default c'tor.
     880            2 :     elCompNumRule() : twoPropRule(pcf::IndiProperty::Number)
     881            2 :     {}
     882              : 
     883              :     /// Set the tolerance
     884              :     /** This is used for equality comparison to allow for floating point precision
     885              :       * and text conversions in INDI.  Set to 0 for strict comparison.
     886              :       *
     887              :       * \throws mx::err:invalidarg if the new value is negative
     888              :       */
     889              :     void tol( const double & t /**< [in] the new tolerance*/)
     890              :     {
     891              :         if(t < 0)
     892              :         {
     893              :             mxThrowException(mx::err::invalidarg, "numValRule::tol", "tolerance can't be negative");
     894              :         }
     895              : 
     896              :         m_tol = t;
     897              :     }
     898              : 
     899              :     /// Get the tolerance
     900              :     /**
     901              :       * \returns the current value of m_tol
     902              :       */
     903              :     const double & tol()
     904              :     {
     905              :         return m_tol;
     906              :     }
     907              : 
     908              :     /// Get the value of this rule
     909              :     /** First checks if the rule is currently valid.  The performs the comparison and returns the result.
     910              :       *
     911              :       * \returns the value of the comparison, true or false
     912              :       *
     913              :       * \throws mx::err::invalidconfig if the rule is not currently valid
     914              :       * \throws mx::err::invalidconfig on an error from the comparison
     915              :       *
     916              :       */
     917            2 :     virtual bool value()
     918              :     {
     919            2 :         boolorerr_t rv = valid();
     920            2 :         if(isError(rv))
     921              :         {
     922            0 :             mxThrowException(mx::err::invalidconfig, "elCompNumRule::value", std::get<std::string>(rv));
     923              :         }
     924              : 
     925            2 :         rv = compNum((*m_property1)[m_element1].get<double>(), (*m_property2)[m_element2].get<double>(), m_tol);
     926            2 :         if(isError(rv))
     927              :         {
     928            0 :             mxThrowException(mx::err::invalidconfig, "elCompNumRule::value()", std::get<std::string>(rv));
     929              :         }
     930              : 
     931            4 :         return std::get<bool>(rv);
     932            2 :     }
     933              : };
     934              : 
     935              : /// Compare two elements based on their text values
     936              : struct elCompTxtRule : public twoPropRule
     937              : {
     938              : public:
     939              : 
     940              :     /// Name of this rule, used by config system
     941              :     static constexpr char name[] = "elCompTxt";
     942              : 
     943              :     /// Default c'tor.
     944            4 :     elCompTxtRule() : twoPropRule(pcf::IndiProperty::Text)
     945            4 :     {}
     946              : 
     947              :     /// Get the value of this rule
     948              :     /** First checks if the rule is currently valid.  The performs the comparison and returns the result.
     949              :       *
     950              :       * \returns the value of the comparison, true or false
     951              :       *
     952              :       * \throws mx::err::invalidconfig if the rule is not currently valid
     953              :       * \throws mx::err::invalidconfig on an error from the comparison
     954              :       *
     955              :       */
     956            4 :     virtual bool value()
     957              :     {
     958            4 :         boolorerr_t rv = valid();
     959            4 :         if(isError(rv))
     960              :         {
     961            0 :             mxThrowException(mx::err::invalidconfig, "elCompTxtRule::value", std::get<std::string>(rv));
     962              :         }
     963              : 
     964            4 :         rv = compTxt((*m_property1)[m_element1].get(), (*m_property2)[m_element2].get());
     965            4 :         if(isError(rv))
     966              :         {
     967            0 :             mxThrowException(mx::err::invalidconfig, "elCompTxtRule::value()", std::get<std::string>(rv));
     968              :         }
     969              : 
     970            8 :         return std::get<bool>(rv);
     971            4 :     }
     972              : };
     973              : 
     974              : /// Compare two elements based on their switch values
     975              : struct elCompSwRule : public twoPropRule
     976              : {
     977              : 
     978              : public:
     979              : 
     980              :     /// Name of this rule, used by config system
     981              :     static constexpr char name[] = "elCompSw";
     982              : 
     983              :     /// Default c'tor.
     984            8 :     elCompSwRule() : twoPropRule(pcf::IndiProperty::Switch)
     985            8 :     {}
     986              : 
     987              :     /// Get the value of this rule
     988              :     /** First checks if the rule is currently valid.  The performs the comparison and returns the result.
     989              :       *
     990              :       * \returns the value of the comparison, true or false
     991              :       *
     992              :       * \throws mx::err::invalidconfig if the rule is not currently valid
     993              :       * \throws mx::err::invalidconfig on an error from the comparison
     994              :       *
     995              :       */
     996            8 :     virtual bool value()
     997              :     {
     998            8 :         boolorerr_t rv = valid();
     999            8 :         if(isError(rv))
    1000              :         {
    1001            0 :             mxThrowException(mx::err::invalidconfig, "elCompSwRule::value", std::get<std::string>(rv));
    1002              :         }
    1003              : 
    1004            8 :         rv = compSw((*m_property1)[m_element1].getSwitchState(), (*m_property2)[m_element2].getSwitchState());
    1005            8 :         if(isError(rv))
    1006              :         {
    1007            0 :             mxThrowException(mx::err::invalidconfig, "elCompSwRule::value()", std::get<std::string>(rv));
    1008              :         }
    1009              : 
    1010           16 :         return std::get<bool>(rv);
    1011            8 :     }
    1012              : };
    1013              : 
    1014              : /// A rule to compare two rules
    1015              : /**
    1016              :   *
    1017              :   */
    1018              : struct ruleCompRule: public indiCompRule
    1019              : {
    1020              : 
    1021              : public:
    1022              : 
    1023              :     /// Name of this rule, used by config system
    1024              :     static constexpr char name[] = "ruleComp";
    1025              : 
    1026              : protected:
    1027              :     indiCompRule * m_rule1 {nullptr}; ///< rule one
    1028              :     indiCompRule * m_rule2 {nullptr}; ///< rule two
    1029              : 
    1030              : public:
    1031              : 
    1032              :     /// Default c'tor
    1033              :     /** Changes default comparison to And for ruleCompRule
    1034              :       */
    1035            9 :     ruleCompRule()
    1036            9 :     {
    1037            9 :         comparison(ruleComparison::And);
    1038            9 :     }
    1039              : 
    1040              :     /// Set the pointer to the first rule
    1041            9 :     void rule1( indiCompRule * r /**< [in] the new pointer to rule1*/)
    1042              :     {
    1043            9 :         m_rule1 = r;
    1044            9 :     }
    1045              : 
    1046              :     /// Get the pointer to the first rule
    1047              :     /**
    1048              :       * \returns the current value of m_rule1
    1049              :       */
    1050              :     const indiCompRule * rule1()
    1051              :     {
    1052              :         return m_rule1;
    1053              :     }
    1054              : 
    1055              :     /// Set the pointer to the second rule
    1056            9 :     void rule2( indiCompRule * r /**< [in] the new pointer to rule2*/)
    1057              :     {
    1058            9 :         m_rule2 = r;
    1059            9 :     }
    1060              : 
    1061              :     /// Get the pointer to the first rule
    1062              :     /**
    1063              :       * \returns the current value of m_rule2
    1064              :       */
    1065              :     const indiCompRule * rule2()
    1066              :     {
    1067              :         return m_rule2;
    1068              :     }
    1069              : 
    1070              :     /// Check if this rule is valid
    1071              :     /** The rule is valid if the rule pointers are not nullptr, and if each rule is itself valid.
    1072              :       *
    1073              :       * If not valid, the return value is a std::string with the reason.
    1074              :       * If valid, the return value is a bool set to true.
    1075              :       */
    1076           13 :     virtual boolorerr_t valid()
    1077              :     {
    1078           13 :         boolorerr_t rv;
    1079           13 :         if(m_rule1 == nullptr)
    1080              :         {
    1081            0 :             rv = "rule1 is nullptr";
    1082              :         }
    1083           13 :         else if(m_rule2 == nullptr)
    1084              :         {
    1085            0 :             rv = "rule2 is nullptr";
    1086              :         }
    1087              :         else
    1088              :         {
    1089           13 :             rv = m_rule1->valid();
    1090           13 :             if(isError(rv))
    1091              :             {
    1092            0 :                 return rv;
    1093              :             }
    1094              : 
    1095           13 :             rv = m_rule2->valid();
    1096           13 :             if(isError(rv))
    1097              :             {
    1098            0 :                 return rv;
    1099              :             }
    1100              : 
    1101           13 :             rv = true;
    1102              :         }
    1103              : 
    1104           13 :         return rv;
    1105            0 :     }
    1106              : 
    1107              :     /// Get the value of this rule
    1108              :     /** First checks if the rule is currently valid.  The performs the comparison and returns the result.
    1109              :       *
    1110              :       * \returns the value of the comparison, true or false
    1111              :       *
    1112              :       * \throws mx::err::invalidconfig if the rule is not currently valid
    1113              :       * \throws mx::err::invalidconfig on an error from the comparison
    1114              :       *
    1115              :       */
    1116            9 :     virtual bool value()
    1117              :     {
    1118            9 :         boolorerr_t rv = valid();
    1119            9 :         if(isError(rv))
    1120              :         {
    1121            0 :             mxThrowException(mx::err::invalidconfig, "ruleCompRule::value", std::get<std::string>(rv));
    1122              :         }
    1123              : 
    1124            9 :         rv = compBool(m_rule1->value(), m_rule2->value());
    1125            9 :         if(isError(rv))
    1126              :         {
    1127            0 :             mxThrowException(mx::err::invalidconfig, "ruleCompRule::value", std::get<std::string>(rv));
    1128              :         }
    1129              : 
    1130           18 :         return std::get<bool>(rv);
    1131            9 :     }
    1132              : };
    1133              : 
    1134              : #endif //stateRuleEngine_indiCompRules_hpp
        

Generated by: LCOV version 2.0-1