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