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 = mx::ioutils::getFileNames(m_configDir + "/" + m_ruleDir, "", "", ".conf");
159
160 for(auto & cnf : conffiles)
161 {
162 //Create a configurator and set it up to log
163 mx::app::appConfigurator fcfg;
164
165 fcfg.m_sources = true;
166 fcfg.configLog = configLog;
167
168 //now process the config file
169 if( fcfg.readConfig(cnf) < 0 )
170 {
171 return log<software_critical,-1>({__FILE__,__LINE__, "error reading rule config file: " + cnf});
172 }
173
174 try
175 {
176 //and finally add to our rule map
178 }
179 catch(mx::err::mxException & e)
180 {
181 return log<software_critical,-1>({__FILE__,__LINE__, std::string("Rule config exception caught from ") + cnf + ":\n" + e.what()});
182 }
183 }
184
185 try
186 {
188 }
189 catch(const std::exception& e)
190 {
191 return log<software_critical,-1>({__FILE__,__LINE__, std::string("Error finalizing rules:\n") + e.what()});
192 }
193
194 }
195
196 return 0;
197}
198
200{
201 if(loadConfigImpl(config) < 0)
202 {
203 log<software_critical>({__FILE__,__LINE__,"error in configuration"});
204 m_shutdown = true;
205 }
206}
207
209{
210 for(auto it = m_ruleMaps.rules.begin(); it != m_ruleMaps.rules.end(); ++it)
211 {
212 if(it->second->priority() == rulePriority::info)
213 {
214 if(m_indiP_info.getDevice() != m_configName)
215 {
216 if(registerIndiPropertyNew( m_indiP_info, "info", pcf::IndiProperty::Switch, pcf::IndiProperty::ReadOnly,
217 pcf::IndiProperty::Idle, pcf::IndiProperty::AnyOfMany, nullptr) < 0)
218 {
219 return log<software_critical,-1>({__FILE__, __LINE__});
220 }
221 }
222
223 pcf::IndiElement elem = pcf::IndiElement(it->first, pcf::IndiElement::Off);
224 m_indiP_info.add(elem);
225 }
226
227 if(it->second->priority() == rulePriority::caution)
228 {
229 if(m_indiP_caution.getDevice() != m_configName)
230 {
231 if(registerIndiPropertyNew( m_indiP_caution, "caution", pcf::IndiProperty::Switch, pcf::IndiProperty::ReadOnly,
232 pcf::IndiProperty::Idle, pcf::IndiProperty::AnyOfMany, nullptr) < 0)
233 {
234 return log<software_critical,-1>({__FILE__, __LINE__});
235 }
236 }
237
238 pcf::IndiElement elem = pcf::IndiElement(it->first, pcf::IndiElement::Off);
240 }
241
242 if(it->second->priority() == rulePriority::warning)
243 {
244 if(m_indiP_warning.getDevice() != m_configName)
245 {
246 if(registerIndiPropertyNew( m_indiP_warning, "warning", pcf::IndiProperty::Switch, pcf::IndiProperty::ReadOnly,
247 pcf::IndiProperty::Idle, pcf::IndiProperty::AnyOfMany, nullptr) < 0)
248 {
249 return log<software_critical,-1>({__FILE__, __LINE__});
250 }
251 }
252
253 pcf::IndiElement elem = pcf::IndiElement(it->first, pcf::IndiElement::Off);
255 }
256
257 if(it->second->priority() == rulePriority::alert)
258 {
259 if(m_indiP_alert.getDevice() != m_configName)
260 {
261 if(registerIndiPropertyNew( m_indiP_alert, "alert", pcf::IndiProperty::Switch, pcf::IndiProperty::ReadOnly,
262 pcf::IndiProperty::Idle, pcf::IndiProperty::AnyOfMany, nullptr) < 0)
263 {
264 return log<software_critical,-1>({__FILE__, __LINE__});
265 }
266 }
267
268 pcf::IndiElement elem = pcf::IndiElement(it->first, pcf::IndiElement::Off);
269 m_indiP_alert.add(elem);
270 }
271 }
272
273 for(auto it = m_ruleMaps.props.begin(); it != m_ruleMaps.props.end(); ++it)
274 {
275 if(it->second == nullptr) continue;
276
277 std::string devName, propName;
278
279 int rv = indi::parseIndiKey(devName, propName, it->first);
280 if(rv != 0)
281 {
282 log<software_error>({__FILE__, __LINE__, 0, rv, "error parsing INDI key: " + it->first});
283 return -1;
284 }
285
287 }
288
290
291 return 0;
292}
293
295{
296 for(auto it = m_ruleMaps.rules.begin(); it != m_ruleMaps.rules.end(); ++it)
297 {
298 #if 0
299 try
300 {
301 bool val = it->second->value();
302 std::cerr << it->first << " " << val << "\n";
303 }
304 catch(...){}
305 #endif
306
307 if(it->second->priority() != rulePriority::none)
308 {
309 try
310 {
311 bool val = it->second->value();
312
313 pcf::IndiElement::SwitchStateType onoff = pcf::IndiElement::Off;
314 if(val) onoff = pcf::IndiElement::On;
315
316 if(it->second->priority() == rulePriority::info)
317 {
319 }
320 else if(it->second->priority() == rulePriority::caution)
321 {
323 }
324 else if(it->second->priority() == rulePriority::warning)
325 {
327 }
328 else
329 {
331 }
332
333 }
334 catch(const std::exception & e)
335 {
336 ///\todo how to handle startup vs misconfiguration
337
338 /*
339 if(it->second->priority() == rulePriority::none)
340 {
341 updateSwitchIfChanged(m_indiP_info, it->first, pcf::IndiElement::Off);
342 }*/
343 }
344 }
345 }
346
347
348 return 0;
349}
350
352{
353 return 0;
354}
355
357 const pcf::IndiProperty &ipRecv
358 )
359{
360 stateRuleEngine * sre = static_cast<stateRuleEngine *>(app);
361
363
364 return 0;
365}
366
367int stateRuleEngine::newCallBack_ruleProp( const pcf::IndiProperty &ipRecv)
368{
369 std::string key = ipRecv.createUniqueKey();
370
371 if(m_ruleMaps.props.count(key) == 0)
372 {
373 return 0;
374 }
375
376 if(m_ruleMaps.props[key] == nullptr) //
377 {
378 return 0;
379 }
380
382
383 return 0;
384}
385
386} //namespace app
387} //namespace MagAOX
388
389#endif //stateRuleEngine_hpp
The base-class for MagAO-X applications.
Definition MagAOXApp.hpp:73
std::string m_configName
The name of the configuration file (minus .conf).
Definition MagAOXApp.hpp:83
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.
Definition MagAOXApp.hpp:85
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:24
Software CRITICAL log entry.
Structure to provide management of the rule and property maps.