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
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
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 */
38ruleComparison string2comp( const std::string & cstr )
39{
40 if(cstr == "Eq")
41 {
42 return ruleComparison::Eq;
43 }
44 else if(cstr == "Neq")
45 {
47 }
48 else if(cstr == "Lt")
49 {
50 return ruleComparison::Lt;
51 }
52 else if(cstr == "Gt")
53 {
54 return ruleComparison::Gt;
55 }
56 else if(cstr == "LtEq")
57 {
59 }
60 else if(cstr == "GtEq")
61 {
63 }
64 else if(cstr == "And")
65 {
67 }
68 else if(cstr == "Nand")
69 {
71 }
72 else if(cstr == "Or")
73 {
74 return ruleComparison::Or;
75 }
76 else if(cstr == "Nor")
77 {
79 }
80 else if(cstr == "Xor")
81 {
83 }
84 else if(cstr == "Xnor")
85 {
87 }
88 else if(cstr == "Imply")
89 {
91 }
92 else if(cstr == "Nimply")
93 {
95 }
96 else
97 {
98 mxThrowException(mx::err::invalidarg, "string2comp", cstr + " is not a valid comparison");
99 }
100}
101
102/// Reporting priorities for rules
103enum 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 */
115rulePriority string2priority(const std::string & pstr)
116{
117 if(pstr == "none")
118 {
119 return rulePriority::none;
120 }
121 else if(pstr == "info")
122 {
123 return rulePriority::info;
124 }
125 else if(pstr == "caution")
126 {
128 }
129 else if(pstr == "warning")
130 {
132 }
133 else if(pstr == "alert")
134 {
135 return rulePriority::alert;
136 }
137 else
138 {
139 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 */
148{
149public:
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 bool isError(boolorerr_t rv /**< [in] the return value to check*/)
156 {
157 return (rv.index() > 0);
158 }
159
160protected:
161
162 /// The reporting priority for this rule
164
165 /// The message used for notifications
166 std::string m_message;
167
168 /// The comparison for this rule
170
171public:
172
173 /// Virtual destructor
175 {}
176
177 /// Set priority of this rule
178 void priority( const rulePriority & p /**< [in] the new priority */)
179 {
180 m_priority = p;
181 }
182
183 /// Get the rule priority
184 /**
185 * \returns the current rule priority
186 */
188 {
189 return m_priority;
190 }
191
192 /// Set the message
193 void message(const std::string & m /**< [in] the new message*/)
194 {
195 m_message = m;
196 }
197
198 /// Get the message
199 /**
200 * \returns the current message
201 */
202 const std::string & message()
203 {
204 return m_message;
205 }
206
207 /// Set the comparison for this rule
208 void comparison( const ruleComparison & c /**< [in] the new comparison*/)
209 {
210 m_comparison = c;
211 }
212
213 /// Get the rule comparison
214 /**
215 * \returns the current rule comparison
216 *
217 */
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 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 boolorerr_t rv = false;
247
248 switch(m_comparison)
249 {
251 if(str1 == str2) rv = true;
252 break;
254 if(str1 != str2) rv = true;
255 break;
256 default:
257 rv = "operator not valid for string comparison";
258 }
259
260 return rv;
261 }
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 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 boolorerr_t rv = false;
275
276 switch(m_comparison)
277 {
279 if(sw1 == sw2) rv = true;
280 break;
282 if(sw1 != sw2) rv = true;
283 break;
284 default:
285 rv = "operator not valid for switch comparison";
286 }
287
288 return rv;
289 }
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 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 boolorerr_t rv = false;
305
306 switch(m_comparison)
307 {
309 if( fabs(num1 - num2) <= tol ) rv = true;
310 break;
312 if( fabs(num1 - num2) > tol ) rv = true;
313 break;
315 if( num1 < num2) rv = true;
316 break;
318 if( num1 > num2) rv = true;
319 break;
321 if( fabs(num1 - num2) <= tol ) rv = true;
322 else if (num1 < num2) rv = true;
323 break;
325 if( fabs(num1 - num2) <= tol ) rv = true;
326 else if (num1 > num2) rv = true;
327 break;
328 default:
329 rv = "operator not valid for compNum";
330 }
331
332 return rv;
333 }
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 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 boolorerr_t rv = false;
346
347 switch(m_comparison)
348 {
350 if(b1 == b2) rv = true;
351 break;
353 if(b1 != b2) rv = true;
354 break;
356 if(b1 && b2) rv = true;
357 break;
359 if(!(b1 && b2)) rv = true;
360 break;
362 if(b1 || b2) rv = true;
363 break;
365 if(!b1 && !b2) rv = true;
366 break;
368 // https://en.wikipedia.org/wiki/Material_conditional
369 if(!b1 || b2) rv=true;
370 break;
372 // https://en.wikipedia.org/wiki/Material_nonimplication
373 if(b1 && !b2) rv=true;
374 break;
375 default:
376 rv = "operator not valid for ruleCompRule";
377 }
378
379 return rv;
380 }
381};
382
383/// A rule base class for testing an element in one property
385{
386
387protected:
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
395public:
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 explicit onePropRule( int type ) : m_type(type /**< The property type, from pcf::IndiProperty::Type*/)
402 {}
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 void property( pcf::IndiProperty * property /**< [in] the new property pointer*/)
410 {
411 if(property == nullptr)
412 {
413 mxThrowException(mx::err::invalidarg, "onePropRule::property", "property is nullptr");
414 }
415
416 if(property->getType() != m_type)
417 {
418 mxThrowException(mx::err::invalidconfig, "onePropRule::property", "property is not correct type");
419 }
420
422 }
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 void element(const std::string & el /**< [in] the new element name*/)
435 {
436 m_element = el;
437 }
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 */
456 {
457 boolorerr_t rv;
458 if(m_property == nullptr)
459 {
460 rv = "property is null";
461 }
462 else if(!m_property->find(m_element))
463 {
464 rv = "element is not found";
465 }
466 else
467 {
468 rv = true;
469 }
470
471 return rv;
472 }
473};
474
475/// A rule base class for testing elements in two properties
477{
478
479protected:
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
491public:
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 explicit twoPropRule( int type ) : m_type(type /**< The property type, from pcf::IndiProperty::Type*/)
498 {}
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 void property1( pcf::IndiProperty * property /**< [in] the new property pointer*/)
506 {
507 if(property == nullptr)
508 {
509 mxThrowException(mx::err::invalidarg, "twoPropRule::property1", "property is nullptr");
510 }
511
512 if(property->getType() != m_type)
513 {
514 mxThrowException(mx::err::invalidconfig, "twoPropRule::property1", "property is not correct type");
515 }
516
517 m_property1 = property;
518 }
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 void element1(const std::string & el /**< [in] the new element name*/)
531 {
532 m_element1 = el;
533 }
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 void property2( pcf::IndiProperty * property /**< [in] the new property pointer*/)
550 {
551 if(property == nullptr)
552 {
553 mxThrowException(mx::err::invalidarg, "twoPropRule::property2", "property is nullptr");
554 }
555
556 if(property->getType() != m_type)
557 {
558 mxThrowException(mx::err::invalidconfig, "twoPropRule::property2", "property is not correct type");
559 }
560
561 m_property2 = property;
562 }
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 void element2(const std::string & el /**< [in] the new element name*/)
575 {
576 m_element2 = el;
577 }
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 */
596 {
597 boolorerr_t rv;
598
599 if(m_property1 == nullptr)
600 {
601 rv = "property1 is null";
602 return rv;
603 }
604
605 if(!m_property1->find(m_element1))
606 {
607 rv = "element1 is not found";
608 return rv;
609 }
610
611 if(m_property2 == nullptr)
612 {
613 rv = "property2 is null";
614 return rv;
615 }
616
617 if(!m_property2->find(m_element2))
618 {
619 rv = "element2 is not found";
620 return rv;
621 }
622
623 rv = true;
624
625 return rv;
626 }
627};
628
629/// Compare the value of a number element to a target
630/**
631 */
632struct numValRule : public onePropRule
633{
634
635public:
636
637 /// Name of this rule, used by config system
638 static constexpr char name[] = "numVal";
639
640protected:
641
642 double m_target {0}; ///< The target value for comparison
643 double m_tol {1e-6}; ///< The tolerance for the comparison
644
645public:
646
647 /// Default c'tor.
648 numValRule() : onePropRule(pcf::IndiProperty::Number)
649 {}
650
651 /// Set the target for the comparison
652 void target( const double & tgt /**< [in] The new target*/)
653 {
654 m_target = tgt;
655 }
656
657 /// Get the target
658 /**
659 * \returns the current value of m_target
660 */
661 const double & target()
662 {
663 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 void tol( const double & t /**< [in] the new tolerance*/)
673 {
674 if(t < 0)
675 {
676 mxThrowException(mx::err::invalidarg, "numValRule::tol", "tolerance can't be negative");
677 }
678
679 m_tol = t;
680 }
681
682 /// Get the tolerance
683 /**
684 * \returns the current value of m_tol
685 */
686 const double & tol()
687 {
688 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 virtual bool value()
701 {
702 boolorerr_t rv = valid();
703 if(isError(rv))
704 {
705 mxThrowException(mx::err::invalidconfig, "numValRule::value", std::get<std::string>(rv));
706 }
707
708 double val = (*m_property)[m_element].get<double>();
709
710 rv = compNum(val, m_target, m_tol);
711 if(isError(rv))
712 {
713 mxThrowException(mx::err::invalidconfig, "numValRule::value", std::get<std::string>(rv));
714 }
715
716 return std::get<bool>(rv);
717 }
718};
719
720/// Compare the value of a text element to a target value
721/** Can only be Eq or Neq.
722 */
723struct txtValRule : public onePropRule
724{
725
726public:
727
728 /// Name of this rule, used by config system
729 static constexpr char name[] = "txtVal";
730
731protected:
732 std::string m_target; ///< The target value for comparison
733
734public:
735
736 /// Default c'tor.
737 txtValRule() : onePropRule(pcf::IndiProperty::Text)
738 {}
739
740 /// Set the target for the comparison
741 void target(const std::string & target /**< [in] The new target*/)
742 {
744 }
745
746 /// Get the target
747 /**
748 * \returns the current value of m_target
749 */
750 const std::string & target()
751 {
752 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 virtual bool value()
765 {
766 boolorerr_t rv = valid();
767 if(isError(rv))
768 {
769 mxThrowException(mx::err::invalidconfig, "txtValRule::value", std::get<std::string>(rv));
770 }
771
772 rv = compTxt((*m_property)[m_element].get(), m_target);
773 if(isError(rv))
774 {
775 mxThrowException(mx::err::invalidconfig, "txtValRule::value()", std::get<std::string>(rv));
776 }
777
778 return std::get<bool>(rv);
779 }
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 */
785struct swValRule : public onePropRule
786{
787
788public:
789
790 /// Name of this rule, used by config system
791 static constexpr char name[] = "swVal";
792
793protected:
794 pcf::IndiElement::SwitchStateType m_target {pcf::IndiElement::UnknownSwitchState}; ///< The target value for comparison
795
796public:
797
798 /// Default c'tor.
799 swValRule() : onePropRule(pcf::IndiProperty::Switch )
800 {}
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 void target(const std::string & switchState /**< [in] The new target*/)
814 {
815 if(switchState == "On")
816 {
817 m_target = pcf::IndiElement::On;
818 }
819 else if(switchState == "Off")
820 {
821 m_target = pcf::IndiElement::Off;
822 }
823 else
824 {
825 mxThrowException(mx::err::invalidarg, "swValRule::target", "invalid switch state");
826 }
827 }
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 virtual bool value()
848 {
849 boolorerr_t rv = valid();
850 if(isError(rv))
851 {
852 mxThrowException(mx::err::invalidconfig, "swValRule::value", std::get<std::string>(rv));
853 }
854
855 rv = compSw((*m_property)[m_element].getSwitchState(), m_target);
856 if(isError(rv))
857 {
858 mxThrowException(mx::err::invalidconfig, "elCompSwRule::value()", std::get<std::string>(rv));
859 }
860
861 return std::get<bool>(rv);
862 }
863};
864
865/// Compare two elements based on their numeric values
867{
868
869public:
870
871 /// Name of this rule, used by config system
872 static constexpr char name[] = "elCompNum";
873
874protected:
875 double m_tol {1e-6}; ///< The tolerance for the comparison
876
877public:
878
879 /// Default c'tor.
880 elCompNumRule() : twoPropRule(pcf::IndiProperty::Number)
881 {}
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 virtual bool value()
918 {
919 boolorerr_t rv = valid();
920 if(isError(rv))
921 {
922 mxThrowException(mx::err::invalidconfig, "elCompNumRule::value", std::get<std::string>(rv));
923 }
924
925 rv = compNum((*m_property1)[m_element1].get<double>(), (*m_property2)[m_element2].get<double>(), m_tol);
926 if(isError(rv))
927 {
928 mxThrowException(mx::err::invalidconfig, "elCompNumRule::value()", std::get<std::string>(rv));
929 }
930
931 return std::get<bool>(rv);
932 }
933};
934
935/// Compare two elements based on their text values
937{
938public:
939
940 /// Name of this rule, used by config system
941 static constexpr char name[] = "elCompTxt";
942
943 /// Default c'tor.
944 elCompTxtRule() : twoPropRule(pcf::IndiProperty::Text)
945 {}
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 virtual bool value()
957 {
958 boolorerr_t rv = valid();
959 if(isError(rv))
960 {
961 mxThrowException(mx::err::invalidconfig, "elCompTxtRule::value", std::get<std::string>(rv));
962 }
963
964 rv = compTxt((*m_property1)[m_element1].get(), (*m_property2)[m_element2].get());
965 if(isError(rv))
966 {
967 mxThrowException(mx::err::invalidconfig, "elCompTxtRule::value()", std::get<std::string>(rv));
968 }
969
970 return std::get<bool>(rv);
971 }
972};
973
974/// Compare two elements based on their switch values
976{
977
978public:
979
980 /// Name of this rule, used by config system
981 static constexpr char name[] = "elCompSw";
982
983 /// Default c'tor.
984 elCompSwRule() : twoPropRule(pcf::IndiProperty::Switch)
985 {}
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 virtual bool value()
997 {
998 boolorerr_t rv = valid();
999 if(isError(rv))
1000 {
1001 mxThrowException(mx::err::invalidconfig, "elCompSwRule::value", std::get<std::string>(rv));
1002 }
1003
1004 rv = compSw((*m_property1)[m_element1].getSwitchState(), (*m_property2)[m_element2].getSwitchState());
1005 if(isError(rv))
1006 {
1007 mxThrowException(mx::err::invalidconfig, "elCompSwRule::value()", std::get<std::string>(rv));
1008 }
1009
1010 return std::get<bool>(rv);
1011 }
1012};
1013
1014/// A rule to compare two rules
1015/**
1016 *
1017 */
1019{
1020
1021public:
1022
1023 /// Name of this rule, used by config system
1024 static constexpr char name[] = "ruleComp";
1025
1026protected:
1027 indiCompRule * m_rule1 {nullptr}; ///< rule one
1028 indiCompRule * m_rule2 {nullptr}; ///< rule two
1029
1030public:
1031
1032 /// Default c'tor
1033 /** Changes default comparison to And for ruleCompRule
1034 */
1039
1040 /// Set the pointer to the first rule
1041 void rule1( indiCompRule * r /**< [in] the new pointer to rule1*/)
1042 {
1043 m_rule1 = r;
1044 }
1045
1046 /// Get the pointer to the first rule
1047 /**
1048 * \returns the current value of m_rule1
1049 */
1051 {
1052 return m_rule1;
1053 }
1054
1055 /// Set the pointer to the second rule
1056 void rule2( indiCompRule * r /**< [in] the new pointer to rule2*/)
1057 {
1058 m_rule2 = r;
1059 }
1060
1061 /// Get the pointer to the first rule
1062 /**
1063 * \returns the current value of m_rule2
1064 */
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 */
1077 {
1078 boolorerr_t rv;
1079 if(m_rule1 == nullptr)
1080 {
1081 rv = "rule1 is nullptr";
1082 }
1083 else if(m_rule2 == nullptr)
1084 {
1085 rv = "rule2 is nullptr";
1086 }
1087 else
1088 {
1089 rv = m_rule1->valid();
1090 if(isError(rv))
1091 {
1092 return rv;
1093 }
1094
1095 rv = m_rule2->valid();
1096 if(isError(rv))
1097 {
1098 return rv;
1099 }
1100
1101 rv = true;
1102 }
1103
1104 return rv;
1105 }
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 virtual bool value()
1117 {
1118 boolorerr_t rv = valid();
1119 if(isError(rv))
1120 {
1121 mxThrowException(mx::err::invalidconfig, "ruleCompRule::value", std::get<std::string>(rv));
1122 }
1123
1124 rv = compBool(m_rule1->value(), m_rule2->value());
1125 if(isError(rv))
1126 {
1127 mxThrowException(mx::err::invalidconfig, "ruleCompRule::value", std::get<std::string>(rv));
1128 }
1129
1130 return std::get<bool>(rv);
1131 }
1132};
1133
1134#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.