API
 
Loading...
Searching...
No Matches
stateRuleEngine.hpp
Go to the documentation of this file.
1/** \file stateRuleEngine.hpp
2 * \brief The MagAO-X stateRuleEngine application header file
3 *
4 * \ingroup stateRuleEngine_files
5 */
6
7#ifndef stateRuleEngine_hpp
8#define stateRuleEngine_hpp
9
10
11#include "../../libMagAOX/libMagAOX.hpp" //Note this is included on command line to trigger pch
12#include "../../magaox_git_version.h"
13
15
16/** \defgroup stateRuleEngine
17 * \brief The MagAO-X stateRuleEngine application
18 *
19 * <a href="../handbook/operating/software/apps/stateRuleEngine.html">Application Documentation</a>
20 *
21 * \ingroup apps
22 *
23 */
24
25/** \defgroup stateRuleEngine_files
26 * \ingroup stateRuleEngine
27 */
28
29namespace MagAOX
30{
31namespace app
32{
33
34/// The MagAO-X stateRuleEngine
35/**
36 * \ingroup stateRuleEngine
37 */
38class stateRuleEngine : public MagAOXApp<true>
39{
40
41 //Give the test harness access.
43
44protected:
45
46 /** \name Configurable Parameters
47 *@{
48 */
49
50 std::string m_ruleDir; /**< Directory containing config files containing rules to load. Relative to config directory. If this is
51 set, then rules in the device config file are ignored*/
52
54
55 ///@}
56
57public:
58 /// Default c'tor.
60
61 /// D'tor, declared and defined for noexcept.
64
65 virtual void setupConfig();
66
67 /// Implementation of loadConfig logic, separated for testing.
68 /** This is called by loadConfig().
69 */
70 int loadConfigImpl( mx::app::appConfigurator & _config /**< [in] an application configuration from which to load values*/);
71
72 virtual void loadConfig();
73
74 /// Startup function
75 /**
76 *
77 */
78 virtual int appStartup();
79
80 /// Implementation of the FSM for stateRuleEngine.
81 /**
82 * \returns 0 on no critical error
83 * \returns -1 on an error requiring shutdown
84 */
85 virtual int appLogic();
86
87 /// Shutdown the app.
88 /**
89 *
90 */
91 virtual int appShutdown();
92
93
94 /// The static callback function to be registered for rule properties
95 /**
96 *
97 * \returns 0 on success.
98 * \returns -1 on error.
99 */
100 static int st_newCallBack_ruleProp( void * app, ///< [in] a pointer to this, will be static_cast-ed to derivedT.
101 const pcf::IndiProperty &ipRecv ///< [in] the INDI property sent with the the new property request.
102 );
103
104 /// Callback to process a NEW preset position request
105 /**
106 * \returns 0 on success.
107 * \returns -1 on error.
108 */
109 int newCallBack_ruleProp( const pcf::IndiProperty &ipRecv /**< [in] the INDI property sent with the the new property request.*/);
110
111
112 pcf::IndiProperty m_indiP_info;
113 pcf::IndiProperty m_indiP_caution;
114 pcf::IndiProperty m_indiP_warning;
115 pcf::IndiProperty m_indiP_alert;
116
117};
118
119stateRuleEngine::stateRuleEngine() : MagAOXApp(MAGAOX_CURRENT_SHA1, MAGAOX_REPO_MODIFIED)
120{
121 return;
122}
123
125{
126 config.add( "rules.dir",
127 "",
128 "rules.dir",
129 argType::Required,
130 "rules",
131 "dir",
132 false,
133 "string",
134 "Directory containing config files containing rules to load. Relative to config directory. If this is "
135 "set, then rules in the device config file are ignored" );
136}
137
138int stateRuleEngine::loadConfigImpl( mx::app::appConfigurator & _config )
139{
140 _config(m_ruleDir, "rules.dir");
141
142 std::map<std::string, ruleRuleKeys> rrkMap;
143
144 if(m_ruleDir == "")
145 {
146 try
147 {
150 }
151 catch(mx::err::mxException & e)
152 {
153 return log<software_critical,-1>({__FILE__,__LINE__, std::string("Rule config exception caught:\n") + e.what()});
154 }
155 }
156 else
157 {
158 std::vector<std::string> conffiles;
159 if(mx::ioutils::getFileNames(conffiles, m_configDir + "/" + m_ruleDir, "", "", ".conf") != mx::error_t::noerror)
160 {
161 return log<software_critical,-1>({__FILE__,__LINE__, "Error reading rules"});
162 }
163
164 for(auto & cnf : conffiles)
165 {
166 //Create a configurator and set it up to log
167 mx::app::appConfigurator fcfg;
168
169 fcfg.m_sources = true;
170 fcfg.configLog = configLog;
171
172 //now process the config file
173 if( fcfg.readConfig(cnf) < 0 )
174 {
175 return log<software_critical,-1>({__FILE__,__LINE__, "error reading rule config file: " + cnf});
176 }
177
178 try
179 {
180 //and finally add to our rule map
182 }
183 catch(mx::err::mxException & e)
184 {
185 return log<software_critical,-1>({__FILE__,__LINE__, std::string("Rule config exception caught from ") + cnf + ":\n" + e.what()});
186 }
187 }
188
189 try
190 {
192 }
193 catch(const std::exception& e)
194 {
195 return log<software_critical,-1>({__FILE__,__LINE__, std::string("Error finalizing rules:\n") + e.what()});
196 }
197
198 }
199
200 return 0;
201}
202
204{
205 if(loadConfigImpl(config) < 0)
206 {
207 log<software_critical>({__FILE__,__LINE__,"error in configuration"});
208 m_shutdown = true;
209 }
210}
211
213{
214 for(auto it = m_ruleMaps.rules.begin(); it != m_ruleMaps.rules.end(); ++it)
215 {
216 if(it->second->priority() == rulePriority::info)
217 {
218 if(m_indiP_info.getDevice() != m_configName)
219 {
220 if(registerIndiPropertyNew( m_indiP_info, "info", pcf::IndiProperty::Switch, pcf::IndiProperty::ReadOnly,
221 pcf::IndiProperty::Idle, pcf::IndiProperty::AnyOfMany, nullptr) < 0)
222 {
223 return log<software_critical,-1>({__FILE__, __LINE__});
224 }
225 }
226
227 m_indiP_info.add(pcf::IndiElement(it->first, pcf::IndiElement::Off));
228 m_indiP_info[it->first].setLabel(it->second->message());
229 }
230
231 if(it->second->priority() == rulePriority::caution)
232 {
233 if(m_indiP_caution.getDevice() != m_configName)
234 {
235 if(registerIndiPropertyNew( m_indiP_caution, "caution", pcf::IndiProperty::Switch, pcf::IndiProperty::ReadOnly,
236 pcf::IndiProperty::Idle, pcf::IndiProperty::AnyOfMany, nullptr) < 0)
237 {
238 return log<software_critical,-1>({__FILE__, __LINE__});
239 }
240 }
241
242 m_indiP_caution.add(pcf::IndiElement(it->first, pcf::IndiElement::Off));
243 m_indiP_caution[it->first].setLabel(it->second->message());
244 }
245
246 if(it->second->priority() == rulePriority::warning)
247 {
248 if(m_indiP_warning.getDevice() != m_configName)
249 {
250 if(registerIndiPropertyNew( m_indiP_warning, "warning", pcf::IndiProperty::Switch, pcf::IndiProperty::ReadOnly,
251 pcf::IndiProperty::Idle, pcf::IndiProperty::AnyOfMany, nullptr) < 0)
252 {
253 return log<software_critical,-1>({__FILE__, __LINE__});
254 }
255 }
256
257 m_indiP_warning.add(pcf::IndiElement(it->first, pcf::IndiElement::Off));
258 m_indiP_warning[it->first].setLabel(it->second->message());
259 }
260
261 if(it->second->priority() == rulePriority::alert)
262 {
263 if(m_indiP_alert.getDevice() != m_configName)
264 {
265 if(registerIndiPropertyNew( m_indiP_alert, "alert", pcf::IndiProperty::Switch, pcf::IndiProperty::ReadOnly,
266 pcf::IndiProperty::Idle, pcf::IndiProperty::AnyOfMany, nullptr) < 0)
267 {
268 return log<software_critical,-1>({__FILE__, __LINE__});
269 }
270 }
271
272 m_indiP_alert.add(pcf::IndiElement(it->first, pcf::IndiElement::Off));
273 m_indiP_alert[it->first].setLabel(it->second->message());
274
275 }
276 }
277
278 for(auto it = m_ruleMaps.props.begin(); it != m_ruleMaps.props.end(); ++it)
279 {
280 if(it->second == nullptr) continue;
281
282 std::string devName, propName;
283
284 int rv = indi::parseIndiKey(devName, propName, it->first);
285 if(rv != 0)
286 {
287 log<software_error>({__FILE__, __LINE__, 0, rv, "error parsing INDI key: " + it->first});
288 return -1;
289 }
290
292 }
293
295
296 return 0;
297}
298
300{
301 for(auto it = m_ruleMaps.rules.begin(); it != m_ruleMaps.rules.end(); ++it)
302 {
303 #if 0
304 try
305 {
306 bool val = it->second->value();
307 std::cerr << it->first << " " << val << "\n";
308 }
309 catch(...){}
310 #endif
311
312 if(it->second->priority() != rulePriority::none)
313 {
314 try
315 {
316 bool val = it->second->value();
317
318 pcf::IndiElement::SwitchStateType onoff = pcf::IndiElement::Off;
319 if(val) onoff = pcf::IndiElement::On;
320
321 if(it->second->priority() == rulePriority::info)
322 {
324 }
325 else if(it->second->priority() == rulePriority::caution)
326 {
328 }
329 else if(it->second->priority() == rulePriority::warning)
330 {
332 }
333 else
334 {
336 }
337
338 }
339 catch(const std::exception & e)
340 {
341 ///\todo how to handle startup vs misconfiguration
342
343 /*
344 if(it->second->priority() == rulePriority::none)
345 {
346 updateSwitchIfChanged(m_indiP_info, it->first, pcf::IndiElement::Off);
347 }*/
348 }
349 }
350 }
351
352
353 return 0;
354}
355
357{
358 return 0;
359}
360
362 const pcf::IndiProperty &ipRecv
363 )
364{
365 stateRuleEngine * sre = static_cast<stateRuleEngine *>(app);
366
368
369 return 0;
370}
371
372int stateRuleEngine::newCallBack_ruleProp( const pcf::IndiProperty &ipRecv)
373{
374 std::string key = ipRecv.createUniqueKey();
375
376 if(m_ruleMaps.props.count(key) == 0)
377 {
378 return 0;
379 }
380
381 if(m_ruleMaps.props[key] == nullptr) //
382 {
383 return 0;
384 }
385
386 *m_ruleMaps.props[key] = ipRecv;
387
388 return 0;
389}
390
391} //namespace app
392} //namespace MagAOX
393
394#endif //stateRuleEngine_hpp
The base-class for XWCTk applications.
std::string m_configName
The name of the configuration file (minus .conf).
stateCodes::stateCodeT state()
Get the current state code.
int registerIndiPropertyNew(pcf::IndiProperty &prop, int(*)(void *, const pcf::IndiProperty &))
Register an INDI property which is exposed for others to request a New Property for.
static void configLog(const std::string &name, const int &code, const std::string &value, const std::string &source)
Callback for config system logging.
int m_shutdown
Flag to signal it's time to shutdown. When not 0, the main loop exits.
void updateSwitchIfChanged(pcf::IndiProperty &p, const std::string &el, const pcf::IndiElement::SwitchStateType &newVal, pcf::IndiProperty::PropertyStateType ipState=pcf::IndiProperty::Ok)
Update an INDI switch element value if it has changed.
static int log(const typename logT::messageT &msg, logPrioT level=logPrio::LOG_DEFAULT)
Make a log entry.
std::string m_configDir
The path to configuration files for MagAOX.
int registerIndiPropertySet(pcf::IndiProperty &prop, const std::string &devName, const std::string &propName, int(*)(void *, const pcf::IndiProperty &))
Register an INDI property which is monitored for updates from others.
The MagAO-X stateRuleEngine.
int loadConfigImpl(mx::app::appConfigurator &_config)
Implementation of loadConfig logic, separated for testing.
virtual int appStartup()
Startup function.
~stateRuleEngine() noexcept
D'tor, declared and defined for noexcept.
virtual int appShutdown()
Shutdown the app.
static int st_newCallBack_ruleProp(void *app, const pcf::IndiProperty &ipRecv)
The static callback function to be registered for rule properties.
int newCallBack_ruleProp(const pcf::IndiProperty &ipRecv)
Callback to process a NEW preset position request.
virtual int appLogic()
Implementation of the FSM for stateRuleEngine.
@ READY
The device is ready for operation, but is not operating.
Configuration of rules for the MagAO-X stateRuleEngine.
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.
@ 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.
int parseIndiKey(std::string &devName, std::string &propName, const std::string &key)
Parse an INDI key into the device and property names.
const pcf::IndiProperty & ipRecv
Definition dm.hpp:19
Software CRITICAL log entry.
Structure to provide management of the rule and property maps.