API
 
Loading...
Searching...
No Matches
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
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 */
36ruleComparison string2comp( const std::string & cstr )
37{
38 if(cstr == "Eq")
39 {
40 return ruleComparison::Eq;
41 }
42 else if(cstr == "Neq")
43 {
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 {
57 }
58 else if(cstr == "GtEq")
59 {
61 }
62 else if(cstr == "And")
63 {
65 }
66 else if(cstr == "Nand")
67 {
69 }
70 else if(cstr == "Or")
71 {
72 return ruleComparison::Or;
73 }
74 else if(cstr == "Nor")
75 {
77 }
78 else if(cstr == "Xor")
79 {
81 }
82 else if(cstr == "Xnor")
83 {
85 }
86 else
87 {
88 mxThrowException(mx::err::invalidarg, "string2comp", cstr + " is not a valid comparison");
89 }
90}
91
92/// Reporting priorities for rules
93enum 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 */
105rulePriority 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 {
118 }
119 else if(pstr == "warning")
120 {
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 implement valid() and value().
136 */
138{
139public:
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
150protected:
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
161public:
162
163 /// Virtual destructor
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 {
241 if(str1 == str2) rv = true;
242 break;
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 {
269 if(sw1 == sw2) rv = true;
270 break;
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 {
299 if( fabs(num1 - num2) <= tol ) rv = true;
300 break;
302 if( fabs(num1 - num2) > tol ) rv = true;
303 break;
305 if( num1 < num2) rv = true;
306 break;
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 {
340 if(b1 == b2) rv = true;
341 break;
343 if(b1 != b2) rv = true;
344 break;
346 if(b1 && b2) rv = true;
347 break;
349 if(!(b1 && b2)) rv = true;
350 break;
352 if(b1 || b2) rv = true;
353 break;
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
367{
368
369protected:
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
377public:
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 */
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
459{
460
461protected:
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
473public:
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 */
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 */
614struct numValRule : public onePropRule
615{
616
617public:
618
619 /// Name of this rule, used by config system
620 static constexpr char name[] = "numVal";
621
622protected:
623
624 double m_target {0}; ///< The target value for comparison
625 double m_tol {1e-6}; ///< The tolerance for the comparison
626
627public:
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 */
705struct txtValRule : public onePropRule
706{
707
708public:
709
710 /// Name of this rule, used by config system
711 static constexpr char name[] = "txtVal";
712
713protected:
714 std::string m_target; ///< The target value for comparison
715
716public:
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 {
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 */
767struct swValRule : public onePropRule
768{
769
770public:
771
772 /// Name of this rule, used by config system
773 static constexpr char name[] = "swVal";
774
775protected:
776 pcf::IndiElement::SwitchStateType m_target {pcf::IndiElement::UnknownSwitchState}; ///< The target value for comparison
777
778public:
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
849{
850
851public:
852
853 /// Name of this rule, used by config system
854 static constexpr char name[] = "elCompNum";
855
856protected:
857 double m_tol {1e-6}; ///< The tolerance for the comparison
858
859public:
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
919{
920public:
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
958{
959
960public:
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
1003public:
1004
1005 /// Name of this rule, used by config system
1006 static constexpr char name[] = "ruleComp";
1007
1008protected:
1009 indiCompRule * m_rule1 {nullptr}; ///< rule one
1010 indiCompRule * m_rule2 {nullptr}; ///< rule two
1011
1012public:
1013
1014 /// Default c'tor
1015 /** Changes default comparison to And for ruleCompRule
1016 */
1021
1022 /// Set the pointer to the first rule
1023 void rule1( indiCompRule * r /**< [in] the new pointer to rule1*/)
1024 {
1025 m_rule1 = r;
1026 }
1027
1028 /// Get the pointer to the first rule
1029 /**
1030 * \returns the current value of m_rule1
1031 */
1033 {
1034 return m_rule1;
1035 }
1036
1037 /// Set the pointer to the second rule
1038 void rule2( indiCompRule * r /**< [in] the new pointer to rule2*/)
1039 {
1040 m_rule2 = r;
1041 }
1042
1043 /// Get the pointer to the first rule
1044 /**
1045 * \returns the current value of m_rule2
1046 */
1048 {
1049 return m_rule2;
1050 }
1051
1052 /// Check if this rule is valid
1053 /** The rule is valid if the rule pointers are not nullptr, and if each rule is itself valid.
1054 *
1055 * If not valid, the return value is a std::string with the reason.
1056 * If valid, the return value is a bool set to true.
1057 */
1059 {
1060 boolorerr_t rv;
1061 if(m_rule1 == nullptr)
1062 {
1063 rv = "rule1 is nullptr";
1064 }
1065 else if(m_rule2 == nullptr)
1066 {
1067 rv = "rule2 is nullptr";
1068 }
1069 else
1070 {
1071 rv = m_rule1->valid();
1072 if(isError(rv))
1073 {
1074 return rv;
1075 }
1076
1077 rv = m_rule2->valid();
1078 if(isError(rv))
1079 {
1080 return rv;
1081 }
1082
1083 rv = true;
1084 }
1085
1086 return rv;
1087 }
1088
1089 /// Get the value of this rule
1090 /** First checks if the rule is currently valid. The performs the comparison and returns the result.
1091 *
1092 * \returns the value of the comparison, true or false
1093 *
1094 * \throws mx::err::invalidconfig if the rule is not currently valid
1095 * \throws mx::err::invalidconfig on an error from the comparison
1096 *
1097 */
1098 virtual bool value()
1099 {
1100 boolorerr_t rv = valid();
1101 if(isError(rv))
1102 {
1103 mxThrowException(mx::err::invalidconfig, "ruleCompRule::value", std::get<std::string>(rv));
1104 }
1105
1106 rv = compBool(m_rule1->value(), m_rule2->value());
1107 if(isError(rv))
1108 {
1109 mxThrowException(mx::err::invalidconfig, "ruleCompRule::value", std::get<std::string>(rv));
1110 }
1111
1112 return std::get<bool>(rv);
1113 }
1114};
1115
1116#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.
const double & tol()
Get the tolerance.
double m_tol
The tolerance for the comparison.
elCompNumRule()
Default c'tor.
void tol(const double &t)
Set 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.
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.
const ruleComparison & comparison()
Get the rule comparison.
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.
const std::string & message()
Get the message.
void message(const std::string &m)
Set the message.
const rulePriority & priority()
Get the rule priority.
boolorerr_t compBool(const bool &b1, const bool &b2)
Compare two booleans.
Compare the value of a number element to a target.
const double & target()
Get the target.
numValRule()
Default c'tor.
double m_tol
The tolerance for the comparison.
double m_target
The target value for comparison.
const double & tol()
Get the tolerance.
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.
A rule base class for testing an element in one property.
const pcf::IndiProperty * property()
Get the property pointer.
std::string m_element
The element name within the property.
int m_type
The property type, from pcf::IndiProperty::Type.
onePropRule()=delete
onePropRule(int type)
Constructor. You must provide the property type to construct a onePropRule.
const std::string & element()
Get the element name.
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.
ruleCompRule()
Default c'tor.
const indiCompRule * rule2()
Get the pointer to the first rule.
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.
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.
const pcf::IndiElement::SwitchStateType & target()
Get the target.
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.
static constexpr char name[]
Name of this rule, used by config system.
A rule base class for testing elements in two properties.
twoPropRule()=delete
int m_type
The property type, from pcf::IndiProperty::Type.
const std::string & element1()
Get the first element name.
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 * property2()
Get the second 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.
pcf::IndiProperty * m_property2
Pointer to the second property.
const pcf::IndiProperty * property1()
Get the first property pointer.
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.
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.
const std::string & target()
Get the target.