API
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 
14 #include "indiCompRuleConfig.hpp"
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 
29 namespace MagAOX
30 {
31 namespace app
32 {
33 
34 /// The MagAO-X stateRuleEngine
35 /**
36  * \ingroup stateRuleEngine
37  */
38 class stateRuleEngine : public MagAOXApp<true>
39 {
40 
41  //Give the test harness access.
42  friend class stateRuleEngine_test;
43 
44 protected:
45 
46  /** \name Configurable Parameters
47  *@{
48  */
49 
51 
52  ///@}
53 
54 public:
55  /// Default c'tor.
57 
58  /// D'tor, declared and defined for noexcept.
59  ~stateRuleEngine() noexcept
60  {}
61 
62  virtual void setupConfig();
63 
64  /// Implementation of loadConfig logic, separated for testing.
65  /** This is called by loadConfig().
66  */
67  int loadConfigImpl( mx::app::appConfigurator & _config /**< [in] an application configuration from which to load values*/);
68 
69  virtual void loadConfig();
70 
71  /// Startup function
72  /**
73  *
74  */
75  virtual int appStartup();
76 
77  /// Implementation of the FSM for stateRuleEngine.
78  /**
79  * \returns 0 on no critical error
80  * \returns -1 on an error requiring shutdown
81  */
82  virtual int appLogic();
83 
84  /// Shutdown the app.
85  /**
86  *
87  */
88  virtual int appShutdown();
89 
90 
91  /// The static callback function to be registered for rule properties
92  /**
93  *
94  * \returns 0 on success.
95  * \returns -1 on error.
96  */
97  static int st_newCallBack_ruleProp( void * app, ///< [in] a pointer to this, will be static_cast-ed to derivedT.
98  const pcf::IndiProperty &ipRecv ///< [in] the INDI property sent with the the new property request.
99  );
100 
101  /// Callback to process a NEW preset position request
102  /**
103  * \returns 0 on success.
104  * \returns -1 on error.
105  */
106  int newCallBack_ruleProp( const pcf::IndiProperty &ipRecv /**< [in] the INDI property sent with the the new property request.*/);
107 
108 
109  pcf::IndiProperty m_indiP_info;
110  pcf::IndiProperty m_indiP_caution;
111  pcf::IndiProperty m_indiP_warning;
112  pcf::IndiProperty m_indiP_alert;
113 
114 };
115 
116 stateRuleEngine::stateRuleEngine() : MagAOXApp(MAGAOX_CURRENT_SHA1, MAGAOX_REPO_MODIFIED)
117 {
118  return;
119 }
120 
122 {
123 }
124 
125 int stateRuleEngine::loadConfigImpl( mx::app::appConfigurator & _config )
126 {
127  loadRuleConfig(m_ruleMaps, _config);
128 
129  return 0;
130 }
131 
133 {
134  loadConfigImpl(config);
135 }
136 
138 {
139  for(auto it = m_ruleMaps.rules.begin(); it != m_ruleMaps.rules.end(); ++it)
140  {
141  if(it->second->priority() == rulePriority::info)
142  {
143  if(m_indiP_info.getDevice() != m_configName)
144  {
145  if(registerIndiPropertyNew( m_indiP_info, "info", pcf::IndiProperty::Switch, pcf::IndiProperty::ReadOnly,
146  pcf::IndiProperty::Idle, pcf::IndiProperty::AnyOfMany, nullptr) < 0)
147  {
148  return log<software_critical,-1>({__FILE__, __LINE__});
149  }
150  }
151 
152  pcf::IndiElement elem = pcf::IndiElement(it->first, pcf::IndiElement::Off);
153  m_indiP_info.add(elem);
154  }
155 
156  if(it->second->priority() == rulePriority::caution)
157  {
158  if(m_indiP_caution.getDevice() != m_configName)
159  {
160  if(registerIndiPropertyNew( m_indiP_caution, "caution", pcf::IndiProperty::Switch, pcf::IndiProperty::ReadOnly,
161  pcf::IndiProperty::Idle, pcf::IndiProperty::AnyOfMany, nullptr) < 0)
162  {
163  return log<software_critical,-1>({__FILE__, __LINE__});
164  }
165  }
166 
167  pcf::IndiElement elem = pcf::IndiElement(it->first, pcf::IndiElement::Off);
168  m_indiP_caution.add(elem);
169  }
170 
171  if(it->second->priority() == rulePriority::warning)
172  {
173  if(m_indiP_warning.getDevice() != m_configName)
174  {
175  if(registerIndiPropertyNew( m_indiP_warning, "warning", pcf::IndiProperty::Switch, pcf::IndiProperty::ReadOnly,
176  pcf::IndiProperty::Idle, pcf::IndiProperty::AnyOfMany, nullptr) < 0)
177  {
178  return log<software_critical,-1>({__FILE__, __LINE__});
179  }
180  }
181 
182  pcf::IndiElement elem = pcf::IndiElement(it->first, pcf::IndiElement::Off);
183  m_indiP_warning.add(elem);
184  }
185 
186  if(it->second->priority() == rulePriority::alert)
187  {
188  if(m_indiP_alert.getDevice() != m_configName)
189  {
190  if(registerIndiPropertyNew( m_indiP_alert, "alert", pcf::IndiProperty::Switch, pcf::IndiProperty::ReadOnly,
191  pcf::IndiProperty::Idle, pcf::IndiProperty::AnyOfMany, nullptr) < 0)
192  {
193  return log<software_critical,-1>({__FILE__, __LINE__});
194  }
195  }
196 
197  pcf::IndiElement elem = pcf::IndiElement(it->first, pcf::IndiElement::Off);
198  m_indiP_alert.add(elem);
199  }
200  }
201 
202  for(auto it = m_ruleMaps.props.begin(); it != m_ruleMaps.props.end(); ++it)
203  {
204  if(it->second == nullptr) continue;
205 
206  std::string devName, propName;
207 
208  int rv = indi::parseIndiKey(devName, propName, it->first);
209  if(rv != 0)
210  {
211  log<software_error>({__FILE__, __LINE__, 0, rv, "error parsing INDI key: " + it->first});
212  return -1;
213  }
214 
215  registerIndiPropertySet( *it->second, devName, propName, st_newCallBack_ruleProp);
216  }
217 
219 
220  return 0;
221 }
222 
224 {
225  for(auto it = m_ruleMaps.rules.begin(); it != m_ruleMaps.rules.end(); ++it)
226  {
227  if(it->second->priority() != rulePriority::none)
228  {
229  try
230  {
231  bool val = it->second->value();
232 
233  pcf::IndiElement::SwitchStateType onoff = pcf::IndiElement::Off;
234  if(val) onoff = pcf::IndiElement::On;
235 
236  if(it->second->priority() == rulePriority::info)
237  {
238  updateSwitchIfChanged(m_indiP_info, it->first, onoff);
239  }
240  else if(it->second->priority() == rulePriority::caution)
241  {
242  updateSwitchIfChanged(m_indiP_caution, it->first, onoff);
243  }
244  else if(it->second->priority() == rulePriority::warning)
245  {
246  updateSwitchIfChanged(m_indiP_warning, it->first, onoff);
247  }
248  else
249  {
250  updateSwitchIfChanged(m_indiP_alert, it->first, onoff);
251  }
252 
253  }
254  catch(const std::exception & e)
255  {
256  ///\todo how to handle startup vs misconfiguration
257 
258  /*
259  if(it->second->priority() == rulePriority::none)
260  {
261  updateSwitchIfChanged(m_indiP_info, it->first, pcf::IndiElement::Off);
262  }*/
263  }
264  }
265  }
266 
267 
268  return 0;
269 }
270 
272 {
273  return 0;
274 }
275 
277  const pcf::IndiProperty &ipRecv
278  )
279 {
280  stateRuleEngine * sre = static_cast<stateRuleEngine *>(app);
281 
283 
284  return 0;
285 }
286 
287 int stateRuleEngine::newCallBack_ruleProp( const pcf::IndiProperty &ipRecv)
288 {
289  std::string key = ipRecv.createUniqueKey();
290 
291  if(m_ruleMaps.props.count(key) == 0)
292  {
293  return 0;
294  }
295 
296  if(m_ruleMaps.props[key] == nullptr) //
297  {
298  return 0;
299  }
300 
301  *m_ruleMaps.props[key] = ipRecv;
302 
303  return 0;
304 }
305 
306 } //namespace app
307 } //namespace MagAOX
308 
309 #endif //stateRuleEngine_hpp
The base-class for MagAO-X applications.
Definition: MagAOXApp.hpp:75
std::string m_configName
The name of the configuration file (minus .conf).
Definition: MagAOXApp.hpp:88
stateCodes::stateCodeT state()
Get the current state code.
Definition: MagAOXApp.hpp:2082
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.
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.
Definition: MagAOXApp.hpp:2901
static int log(const typename logT::messageT &msg, logPrioT level=logPrio::LOG_DEFAULT)
Make a log entry.
Definition: MagAOXApp.hpp:1590
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.
Definition: MagAOXApp.hpp:2569
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.
Definition: stateCodes.hpp:51
Configuration of rules for the MagAO-X stateRuleEngine.
void loadRuleConfig(indiRuleMaps &maps, mx::app::appConfigurator &config)
Load the rule and properties maps for a rule engine from a configuration file.
@ 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.
Definition: indiUtils.hpp:311
const pcf::IndiProperty & ipRecv
Definition: dm.hpp:24
Software CRITICAL log entry.
Structure to provide management of the rule and property maps.