API
 
Loading...
Searching...
No Matches
indiCompRuleConfig.hpp
Go to the documentation of this file.
1/** \file indiCompRuleConfig.hpp
2 * \brief Configuration of rules for the MagAO-X stateRuleEngine
3 *
4 * \ingroup stateRuleEngine_files
5 */
6
7#ifndef stateRuleEngine_indiCompRuleConfig_hpp
8#define stateRuleEngine_indiCompRuleConfig_hpp
9
10#include <map>
11
12#include "indiCompRules.hpp"
13
14/// Structure to provide management of the rule and property maps
15/** This owns all pointers in the rule engine, and `delete`s them on destruction.
16 */
18{
19 typedef std::map<std::string, indiCompRule*> ruleMapT;
20 typedef std::map<std::string, pcf::IndiProperty*> propMapT;
21
24
26 {
27 auto rit = rules.begin();
28 while(rit != rules.end())
29 {
30 delete rit->second;
31 ++rit;
32 }
33
34 auto pit = props.begin();
35 while(pit != props.end())
36 {
37 delete pit->second;
38 ++pit;
39 }
40 }
41};
42
43/* Structure used to hold ruleVal rule keys aside for final processing
44 ruleVal rules can be created before the rules they link exist, so
45 we hold the keys aside and set the pointers after all rules are created.
46*/
48{
49 std::string rule1;
50 std::string rule2;
51};
52
53/// Extract a property from a rule configuration
54/** Reads the property and element, adding the property to the property map if necessary.
55 *
56 * \throws mx::err::invalidconfig if the property is already in the map but of a different type
57 */
58void extractRuleProp( pcf::IndiProperty ** prop, ///< [out] pointer to the property, newly created or existing, which is in the map.
59 std::string & element, ///< [out] the element name from the configuration
60 indiRuleMaps & maps, ///< [in] contains the property map to which the property is added
61 const std::string & section, ///< [in] name of the section for this rule
62 const std::string & propkey, ///< [in] the key for the property name
63 const std::string & elkey, ///< [in] the key for the element name
64 const pcf::IndiProperty::Type & type, ///< [in] the type of the property
65 mx::app::appConfigurator & config ///< [in] the application configuration structure
66 )
67{
68 std::string property;
69 config.configUnused(property, mx::app::iniFile::makeKey(section, propkey ));
70
71 if(maps.props.count(property) > 0)
72 {
73 //If the property already exists we just check if it's the right type
74 if(maps.props[property]->getType() != type)
75 {
76 mxThrowException(mx::err::invalidconfig, "extracPropRule", "property " + property + " exists but is not correct type");
77 }
78
79 *prop = maps.props[property];
80 }
81 else
82 {
83 //Otherwise we create it
84 *prop = new pcf::IndiProperty(type);
85 maps.props.insert(std::pair<std::string, pcf::IndiProperty*>({property, *prop}));
86
87 ///\todo have to split device and propertyName
88 }
89
90 config.configUnused(element, mx::app::iniFile::makeKey(section, elkey));
91
92}
93
94/// Load the rule and properties maps for a rule engine from a configuration file
95/** ///\todo check for insertion failure
96 * ///\todo add a constructor that has priority, message, and comparison, to reduce duplication
97 */
98void loadRuleConfig( indiRuleMaps & maps, ///< [out] contains the rule and property maps in which to place the items found in config
99 std::map<std::string, ruleRuleKeys> & rrkMap, ///< [out] Holds the ruleVal rule keys aside for later post-processing
100 mx::app::appConfigurator & config ///< [in] the application configuration structure
101 )
102{
103 std::vector<std::string> sections;
104
105 config.unusedSections(sections);
106
107 if( sections.size() == 0 )
108 {
109 mxThrowException(mx::err::invalidconfig, "loadRuleConfig", "no rules found in config");
110 }
111
112
113 for(size_t i=0; i< sections.size(); ++i)
114 {
115 bool ruleTypeSet = config.isSetUnused(mx::app::iniFile::makeKey(sections[i], "ruleType" ));
116
117 //If there is no ruleType then this isn't a rule
118 if( !ruleTypeSet ) continue;
119
120 //If the rule already exists this is an error
121 if(maps.rules.count(sections[i]) != 0)
122 {
123 mxThrowException(mx::err::invalidconfig, "loadRuleConfig", "duplicate rule: " + sections[i]);
124 }
125
126 std::string ruleType;
127 config.configUnused(ruleType, mx::app::iniFile::makeKey(sections[i], "ruleType" ));
128
129 std::string priostr="none";
130 config.configUnused(priostr, mx::app::iniFile::makeKey(sections[i], "priority" ));
131 rulePriority priority = string2priority(priostr);
132
133 std::string message;
134 config.configUnused(message, mx::app::iniFile::makeKey(sections[i], "message" ));
135
136 std::string compstr="Eq";
137 config.configUnused(compstr, mx::app::iniFile::makeKey(sections[i], "comp" ));
138 ruleComparison comparison = string2comp(compstr);
139
140 if(ruleType == numValRule::name)
141 {
142 numValRule * nvr = new numValRule;
143 maps.rules.insert(std::pair<std::string, indiCompRule*>({sections[i], nvr}));
144
145 nvr->priority(priority);
146 nvr->message(message);
147 nvr->comparison(comparison);
148
149 pcf::IndiProperty * prop = nullptr;
150 std::string element;
151
152 extractRuleProp( &prop, element, maps, sections[i], "property", "element", pcf::IndiProperty::Number, config );
153 nvr->property(prop);
154 nvr->element(element);
155
156 double target = nvr->target();
157 config.configUnused(target, mx::app::iniFile::makeKey(sections[i], "target" ));
158 nvr->target(target);
159
160 double tol = nvr->tol();
161 config.configUnused(tol, mx::app::iniFile::makeKey(sections[i], "tol" ));
162 nvr->tol(tol);
163 }
164 else if(ruleType == txtValRule::name)
165 {
166 txtValRule * tvr = new txtValRule;
167 maps.rules.insert(std::pair<std::string, indiCompRule*>({sections[i], tvr}));
168
169 tvr->priority(priority);
170 tvr->message(message);
171 tvr->comparison(comparison);
172
173 pcf::IndiProperty * prop = nullptr;
174 std::string element;
175
176 extractRuleProp( &prop, element, maps, sections[i], "property", "element", pcf::IndiProperty::Text, config );
177 tvr->property(prop);
178 tvr->element(element);
179
180
181 std::string target = tvr->target();
182 config.configUnused(target, mx::app::iniFile::makeKey(sections[i], "target" ));
183 tvr->target(target);
184
185 }
186 else if(ruleType == swValRule::name)
187 {
188 swValRule * svr = new swValRule;
189 maps.rules.insert(std::pair<std::string, indiCompRule*>({sections[i], svr}));
190
191 svr->priority(priority);
192 svr->message(message);
193 svr->comparison(comparison);
194
195 pcf::IndiProperty * prop = nullptr;
196 std::string element;
197
198 extractRuleProp( &prop, element, maps, sections[i], "property", "element", pcf::IndiProperty::Switch, config );
199 svr->property(prop);
200 svr->element(element);
201
202 std::string target = "On";
203 config.configUnused(target, mx::app::iniFile::makeKey(sections[i], "target" ));
204 svr->target(target);
205 }
206 else if(ruleType == elCompNumRule::name)
207 {
208 elCompNumRule * nvr = new elCompNumRule;
209 maps.rules.insert(std::pair<std::string, indiCompRule*>({sections[i], nvr}));
210
211 nvr->priority(priority);
212 nvr->message(message);
213 nvr->comparison(comparison);
214
215 pcf::IndiProperty * prop1;
216 std::string element1;
217
218 extractRuleProp( &prop1, element1, maps, sections[i], "property1", "element1", pcf::IndiProperty::Number, config );
219 nvr->property1(prop1);
220 nvr->element1(element1);
221
222 pcf::IndiProperty * prop2;
223 std::string element2;
224
225 extractRuleProp( &prop2, element2, maps, sections[i], "property2", "element2", pcf::IndiProperty::Number, config );
226 nvr->property2(prop2);
227 nvr->element2(element2);
228 }
229 else if(ruleType == elCompTxtRule::name)
230 {
231 elCompTxtRule * tvr = new elCompTxtRule;
232 maps.rules.insert(std::pair<std::string, indiCompRule*>({sections[i], tvr}));
233
234 tvr->priority(priority);
235 tvr->message(message);
236 tvr->comparison(comparison);
237
238 pcf::IndiProperty * prop1;
239 std::string element1;
240
241 extractRuleProp( &prop1, element1, maps, sections[i], "property1", "element1", pcf::IndiProperty::Text, config );
242 tvr->property1(prop1);
243 tvr->element1(element1);
244
245 pcf::IndiProperty * prop2;
246 std::string element2;
247
248 extractRuleProp( &prop2, element2, maps, sections[i], "property2", "element2", pcf::IndiProperty::Text, config );
249 tvr->property2(prop2);
250 tvr->element2(element2);
251 }
252 else if(ruleType == elCompSwRule::name)
253 {
254 elCompSwRule * svr = new elCompSwRule;
255 maps.rules.insert(std::pair<std::string, indiCompRule*>({sections[i], svr}));
256
257 svr->priority(priority);
258 svr->message(message);
259 svr->comparison(comparison);
260
261 pcf::IndiProperty * prop1;
262 std::string element1;
263
264 extractRuleProp( &prop1, element1, maps, sections[i], "property1", "element1", pcf::IndiProperty::Switch, config );
265 svr->property1(prop1);
266 svr->element1(element1);
267
268 pcf::IndiProperty * prop2;
269 std::string element2;
270
271 extractRuleProp( &prop2, element2, maps, sections[i], "property2", "element2", pcf::IndiProperty::Switch, config );
272 svr->property2(prop2);
273 svr->element2(element2);
274 }
275 else if(ruleType == ruleCompRule::name)
276 {
277 //Here we have to hold the ruleVal keys separately for later processing after all the rules are created.
278
279 if(rrkMap.count(sections[i]) > 0)
280 {
281 //This probably should be impossible, since we already checked maps.rules above...
282 mxThrowException(mx::err::invalidconfig, "loadRuleConfig", "duplicate ruleRule: " + sections[i]);
283 }
284
285 ruleCompRule * rcr = new ruleCompRule;
286 maps.rules.insert(std::pair<std::string, indiCompRule*>({sections[i], rcr}));
287
288 rcr->priority(priority);
289 rcr->comparison(comparison);
290
291 ruleRuleKeys rrk;
292
293 config.configUnused(rrk.rule1, mx::app::iniFile::makeKey(sections[i], "rule1" ));
294 if(rrk.rule1 == "")
295 {
296 mxThrowException(mx::err::invalidconfig, "loadRuleConfig", "rule1 for ruleVal rule " + sections[i] + " not found");
297 }
298 if(rrk.rule1 == sections[i])
299 {
300 mxThrowException(mx::err::invalidconfig, "loadRuleConfig", "rule1 for ruleVal rule " + sections[i] + " can't equal rule name");
301 }
302
303 config.configUnused(rrk.rule2, mx::app::iniFile::makeKey(sections[i], "rule2" ));
304 if(rrk.rule2 == "")
305 {
306 mxThrowException(mx::err::invalidconfig, "loadRuleConfig", "rule2 for ruleVal rule " + sections[i] + " not found");
307 }
308 if(rrk.rule2 == sections[i])
309 {
310 mxThrowException(mx::err::invalidconfig, "loadRuleConfig", "rule2 for ruleVal rule " + sections[i] + " can't equal rule name");
311 }
312
313 rrkMap.insert(std::pair<std::string, ruleRuleKeys>(sections[i], rrk));
314 }
315 else
316 {
317 mxThrowException(mx::err::notimpl, "loadRuleConfig", "unknown rule type " + ruleType + " in " + sections[i]);
318 }
319 }
320}
321
322/// Finalize ruleVal rules
323/** ///\todo check for insertion failure
324 * ///\todo add a constructor that has priority, message, and comparison, to reduce duplication
325 */
326void finalizeRuleValRules( indiRuleMaps & maps, /**< [in/out] contains the rule and property maps with rules ot finalize */
327 std::map<std::string, ruleRuleKeys> & rrkMap ///< [out] Holds the ruleVal rule keys aside for later post-processing
328 )
329{
330 //Now set the rule pointers for any ruleVal rules
331 auto it=rrkMap.begin();
332 while(it != rrkMap.end())
333 {
334 if( maps.rules.count(it->first) == 0 )
335 {
336 mxThrowException(mx::err::invalidconfig, "loadRuleConfig", "rule parsing error for " + it->first);
337 }
338
339 if( maps.rules.count(it->second.rule1) == 0 )
340 {
341 mxThrowException(mx::err::invalidconfig, "loadRuleConfig", "rule1 " + it->second.rule1 + " not found for ruleVal rule " + it->first );
342 }
343
344 if( maps.rules.count(it->second.rule2) == 0 )
345 {
346 mxThrowException(mx::err::invalidconfig, "loadRuleConfig", "rule2 " + it->second.rule2 + " not found for ruleVal rule " + it->first );
347 }
348
349 ruleCompRule * rcr = nullptr;
350
351 try
352 {
353 rcr = dynamic_cast<ruleCompRule *>(maps.rules[it->first]);
354 }
355 catch(const std::exception & e)
356 {
357 mxThrowException(mx::err::invalidconfig, "loadRuleConfig", "error casting " + it->first + ": " + e.what() );
358 }
359
360 if(rcr == nullptr)
361 {
362 mxThrowException(mx::err::invalidconfig, "loadRuleConfig", it->first + " is not a ruleVal rule but has rules" );
363 }
364
365 rcr->rule1(maps.rules[it->second.rule1]);
366 rcr->rule2(maps.rules[it->second.rule2]);
367
368 ++it;
369 }
370}
371
372#endif //stateRuleEngine_indiCompRuleConfig_hpp
void loadRuleConfig(indiRuleMaps &maps, std::map< std::string, ruleRuleKeys > &rrkMap, mx::app::appConfigurator &config)
Load the rule and properties maps for a rule engine from a configuration file.
void finalizeRuleValRules(indiRuleMaps &maps, std::map< std::string, ruleRuleKeys > &rrkMap)
Finalize ruleVal rules.
void extractRuleProp(pcf::IndiProperty **prop, std::string &element, indiRuleMaps &maps, const std::string &section, const std::string &propkey, const std::string &elkey, const pcf::IndiProperty::Type &type, mx::app::appConfigurator &config)
Extract a property from a rule configuration.
The rules for the MagAO-X stateRuleEngine.
ruleComparison
Logical comparisons for the INDI rules.
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.
Compare two elements based on their numeric values.
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.
Compare two elements based on their text values.
static constexpr char name[]
Name of this rule, used by config system.
void priority(const rulePriority &p)
Set priority of this rule.
void comparison(const ruleComparison &c)
Set the comparison for this rule.
void message(const std::string &m)
Set the message.
Structure to provide management of the rule and property maps.
std::map< std::string, pcf::IndiProperty * > propMapT
std::map< std::string, indiCompRule * > ruleMapT
Compare the value of a number element to a target.
void target(const double &tgt)
Set the target for the comparison.
void tol(const double &t)
Set the tolerance.
static constexpr char name[]
Name of this rule, used by config system.
void property(pcf::IndiProperty *property)
Set the property pointer.
void element(const std::string &el)
Set the element name.
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.
Compare the value of a switch to a target value.
void target(const pcf::IndiElement::SwitchStateType &ss)
Set the target for the comparison.
static constexpr char name[]
Name of this rule, used by config system.
void property1(pcf::IndiProperty *property)
Set the first property pointer.
void element2(const std::string &el)
Set the second element name.
void element1(const std::string &el)
Set the first element name.
void property2(pcf::IndiProperty *property)
Set the second property pointer.
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.