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 pcf::IndiElement elem = pcf::IndiElement(it->first, pcf::IndiElement::Off);
228 m_indiP_info.add(elem);
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 pcf::IndiElement elem = pcf::IndiElement(it->first, pcf::IndiElement::Off);
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 pcf::IndiElement elem = pcf::IndiElement(it->first, pcf::IndiElement::Off);
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 pcf::IndiElement elem = pcf::IndiElement(it->first, pcf::IndiElement::Off);
273 m_indiP_alert.add(elem);
274 }
275 }
276
277 for(auto it = m_ruleMaps.props.begin(); it != m_ruleMaps.props.end(); ++it)
278 {
279 if(it->second == nullptr) continue;
280
281 std::string devName, propName;
282
283 int rv = indi::parseIndiKey(devName, propName, it->first);
284 if(rv != 0)
285 {
286 log<software_error>({__FILE__, __LINE__, 0, rv, "error parsing INDI key: " + it->first});
287 return -1;
288 }
289
291 }
292
294
295 return 0;
296}
297
299{
300 for(auto it = m_ruleMaps.rules.begin(); it != m_ruleMaps.rules.end(); ++it)
301 {
302 #if 0
303 try
304 {
305 bool val = it->second->value();
306 std::cerr << it->first << " " << val << "\n";
307 }
308 catch(...){}
309 #endif
310
311 if(it->second->priority() != rulePriority::none)
312 {
313 try
314 {
315 bool val = it->second->value();
316
317 pcf::IndiElement::SwitchStateType onoff = pcf::IndiElement::Off;
318 if(val) onoff = pcf::IndiElement::On;
319
320 if(it->second->priority() == rulePriority::info)
321 {
323 }
324 else if(it->second->priority() == rulePriority::caution)
325 {
327 }
328 else if(it->second->priority() == rulePriority::warning)
329 {
331 }
332 else
333 {
335 }
336
337 }
338 catch(const std::exception & e)
339 {
340 ///\todo how to handle startup vs misconfiguration
341
342 /*
343 if(it->second->priority() == rulePriority::none)
344 {
345 updateSwitchIfChanged(m_indiP_info, it->first, pcf::IndiElement::Off);
346 }*/
347 }
348 }
349 }
350
351
352 return 0;
353}
354
356{
357 return 0;
358}
359
361 const pcf::IndiProperty &ipRecv
362 )
363{
364 stateRuleEngine * sre = static_cast<stateRuleEngine *>(app);
365
367
368 return 0;
369}
370
371int stateRuleEngine::newCallBack_ruleProp( const pcf::IndiProperty &ipRecv)
372{
373 std::string key = ipRecv.createUniqueKey();
374
375 if(m_ruleMaps.props.count(key) == 0)
376 {
377 return 0;
378 }
379
380 if(m_ruleMaps.props[key] == nullptr) //
381 {
382 return 0;
383 }
384
386
387 return 0;
388}
389
390} //namespace app
391} //namespace MagAOX
392
393#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:28
Software CRITICAL log entry.
Structure to provide management of the rule and property maps.