API
 
Loading...
Searching...
No Matches
indiPropNode.hpp
Go to the documentation of this file.
1/** \file indiPropNode.hpp
2 * \brief The MagAO-X Instrument Graph indiPropNode header file
3 *
4 * \ingroup instGraph_files
5 */
6
7#ifndef indiPropNode_hpp
8#define indiPropNode_hpp
9
10#include "fsmNode.hpp"
11
12/// An instGraph node which tracks a specific INDI property and element of that property.
13/** When the element matches the target value all puts are turned on. All puts are off
14 * otherwise.
15 */
16class indiPropNode : public fsmNode
17{
18
19 protected:
20 std::string m_propKey; ///< unique key, device.name, of the property tp track
21 std::string m_propEl; ///< the element of the property to track
22
23 std::string m_propValStr; ///< the target value of the element. This is always set.
24
25 double m_propValNum{ std::numeric_limits<double>::lowest() }; /**< the numeric target value, set from
26 m_propValStr if the property is a number.*/
27
28 /** The switch target value, set from m_propValStr if the property is a switch. In this case
29 * m_propValStr can have values `On` or `Off`. The comparison is made insensitive to case (ON and off
30 * are valid).
31 */
32 pcf::IndiElement::SwitchStateType m_propValSw{ pcf::IndiElement::SwitchStateType::UnknownSwitchState };
33
34 /// The property type. Discovered introspectively on first call to \ref handleSetProperty.
35 pcf::IndiProperty::Type m_type{ pcf::IndiProperty::Unknown };
36
37 double m_tol{ 1e-7 }; ///< The tolerance for floating point comparison. Default is 1e-7.
38
39 bool m_state{ false }; ///< The current state of the comparison.
40
41 bool m_first{ true }; ///< Flag indicating if it's the first call to \ref handleSetProperty
42
43 std::string m_onStr {"ON"};
44 std::string m_offStr {"OFF"};
45
46 public:
47 /// Only c'tor. Must be constructed with node name and a parent graph.
48 indiPropNode( const std::string &name, /** [in] the name of this node*/
49 ingr::instGraphXML *parentGraph /** [in] the graph which this node belongs to*/
50 );
51
52 /// Set the unique key of the INDI property to track
53 void propKey( const std::string &pk /** [in] */ );
54
55 /// Get the unique key of the INDI property to track
56 /**
57 * \returns the value of m_propKey
58 */
59 const std::string &propKey() const;
60
61 /// Set the element of the INDI property to track
62 void propEl( const std::string &pe /** [in] */ );
63
64 /// Get the element of the INDI property to track
65 /**
66 * \returns the value of m_propEl
67 */
68 const std::string &propEl() const;
69
70 /// Set the target value of the INDI element.
71 /** Always set in its string form and converted as needed
72 */
73 void propValStr( const std::string &pv /** [in] */ );
74
75 /// Get the target value of the INDI element.
76 /**
77 * \returns the value of m_propValStr
78 */
79 const std::string &propValStr() const;
80
81 /// Get the target value of the INDI element if it's a number.
82 /**
83 * \returns the value of m_propValNum
84 */
85 const double &propValNum() const;
86
87 /// Get the target value of the INDI element if it's a switch.
88 /**
89 * \returns the value of m_propValSw
90 */
91 const pcf::IndiElement::SwitchStateType &propValSw();
92
93 /// Get the type of the INDI property being tracked
94 /**
95 * \returns the value of m_type
96 */
97 const pcf::IndiProperty::Type &type() const;
98
99 /// Get the tolerance used for numeric comparison
100 /**
101 * \returns the value of m_tol
102 */
103 const double &tol() const;
104
105 /// Get the current value of the comparison
106 /**
107 * \returns the value of m_state
108 */
109 const bool &state() const;
110
111 protected:
112 /// On first call to handleSetProperty we find the property type and convert the target value
113 virtual int firstSetProperty( const pcf::IndiProperty &ipRecv /**< [in] the received INDI property*/ );
114
115 public:
116 /// INDI SetProperty callback
117 virtual int handleSetProperty( const pcf::IndiProperty &ipRecv /**< [in] the received INDI property to handle*/ );
118
119 /// Toggle all puts on
120 virtual void toggleOn();
121
122 /// Toggle all puts off
123 virtual void toggleOff();
124
125 /// Configure this node form an appConfigurator.
126 void loadConfig( mx::app::appConfigurator &config /**< [in] the loaded configuration */ );
127};
128
129indiPropNode::indiPropNode( const std::string &name, ingr::instGraphXML *parentGraph ) : fsmNode( name, parentGraph )
130{
131 if( m_parentGraph )
132 {
133 m_parentGraph->valueExtra( m_node->name(), "fsmstate", "" );
134 }
135}
136
137inline void indiPropNode::propKey( const std::string &pk )
138{
139 m_propKey = pk;
140
141 key( m_propKey );
142}
143
144const std::string &indiPropNode::propKey() const
145{
146 return m_propKey;
147}
148
149inline void indiPropNode::propEl( const std::string &pe )
150{
151 m_propEl = pe;
152}
153
154const std::string &indiPropNode::propEl() const
155{
156 return m_propEl;
157}
158
159inline void indiPropNode::propValStr( const std::string &pv )
160{
161 m_propValStr = pv;
162}
163
164const std::string &indiPropNode::propValStr() const
165{
166 return m_propValStr;
167}
168
169const double &indiPropNode::propValNum() const
170{
171 return m_propValNum;
172}
173
174const pcf::IndiElement::SwitchStateType &indiPropNode::propValSw()
175{
176 return m_propValSw;
177}
178
179const pcf::IndiProperty::Type &indiPropNode::type() const
180{
181 return m_type;
182}
183
184const double &indiPropNode::tol() const
185{
186 return m_tol;
187}
188
189const bool &indiPropNode::state() const
190{
191 return m_state;
192}
193
194inline int indiPropNode::firstSetProperty( const pcf::IndiProperty &ipRecv )
195{
196 // On first call we figure what type it is and convert the value
197
198 if( ipRecv.getType() == pcf::IndiProperty::Type::Number )
199 {
200 m_type = pcf::IndiProperty::Type::Number;
201 try
202 {
203 m_propValNum = std::stod( m_propValStr );
204 }
205 catch( const std::exception &e )
206 {
207 std::string msg = XIGN_EXCEPTION( "indiPropNode::firstSetProperty", "exception caught" );
208 msg += ": ";
209 msg += e.what();
210
211 throw std::runtime_error( msg );
212 }
213 }
214 else if( ipRecv.getType() == pcf::IndiProperty::Type::Switch )
215 {
216 m_type = pcf::IndiProperty::Type::Switch;
217 try
218 {
219 std::string ustr = m_propValStr;
220 std::transform( m_propValStr.begin(), m_propValStr.end(), ustr.begin(), ::toupper );
221
222 if( ustr == "ON" )
223 {
224 m_propValSw = pcf::IndiElement::SwitchStateType::On;
225 }
226 else if( ustr == "OFF" )
227 {
228 m_propValSw = pcf::IndiElement::SwitchStateType::Off;
229 }
230 else
231 {
232 std::string msg = XIGN_EXCEPTION( "indiPropNode::firstSetProperty", "invalid switch state" );
233 throw std::invalid_argument( msg );
234 }
235 }
236 catch( const std::exception &e )
237 {
238 std::string msg = XIGN_EXCEPTION( "indiPropNode::firstSetProperty", "exception caught" );
239 msg += ": ";
240 msg += e.what();
241
242 throw std::runtime_error( msg );
243 }
244 }
245 else if( ipRecv.getType() == pcf::IndiProperty::Type::Text )
246 {
247 m_type = pcf::IndiProperty::Type::Text;
248 }
249 else
250 {
251 std::string msg = XIGN_EXCEPTION( "indiPropNode::firstSetProperty", "INDI property of type not implemented" );
252 throw std::runtime_error( msg );
253 }
254
255 return 0;
256}
257
258inline int indiPropNode::handleSetProperty( const pcf::IndiProperty &ipRecv )
259{
260 bool actionTaken = false;
261
262 int rv = fsmNode::handleSetProperty( actionTaken, ipRecv );
263 if( rv < 0 )
264 {
265 std::cerr << "Error from fsmNode::handleSetProperty\n";
266 return rv;
267 }
268
269 if( actionTaken )
270 {
271 return 0;
272 }
273
274 if( ipRecv.createUniqueKey() != m_propKey )
275 {
276 return 0;
277 }
278
279 if( !ipRecv.find( m_propEl ) )
280 {
281 std::cerr << "!ipRecv.find( m_propEl )\n";
282 return -1;
283 }
284
285 if( m_first )
286 {
287 try
288 {
289 int rv = firstSetProperty( ipRecv );
290 if(rv < 0)
291 {
292 std::cerr << "Error from firstSetProperty\n";
293 return rv;
294 }
295 }
296 catch( const std::exception &e )
297 {
298 std::string msg = XIGN_EXCEPTION( "indiPropNode::handleSetProperty", "exception caught" );
299 msg += ": ";
300 msg += e.what();
301
302 throw std::runtime_error( msg );
303 }
304 }
305
306 bool on = false;
307
308 if( m_type == pcf::IndiProperty::Type::Number )
309 {
310 if( fabs( ipRecv[m_propEl].get<double>() - m_propValNum ) <= m_tol )
311 {
312 on = true;
313 }
314 }
315 else if( m_type == pcf::IndiProperty::Type::Switch )
316 {
317 if( ipRecv[m_propEl].getSwitchState() == m_propValSw )
318 {
319 on = true;
320 }
321 }
322 else if( m_type == pcf::IndiProperty::Type::Text )
323 {
324 if( ipRecv[m_propEl].get() == m_propValStr )
325 {
326 on = true;
327 }
328 }
329 else
330 {
331 std::string msg = XIGN_EXCEPTION( "indiPropNode::handleSetProperty", "type not implemented" );
332 throw std::runtime_error( msg );
333 }
334
335 if( m_first )
336 {
337 // trigger the change on the first run.
338 if( on )
339 {
340 m_state = false;
341 }
342 else
343 {
344 m_state = true;
345 }
346
347 // made this it's own branch so we don't do this every time:
348 m_first = false;
349 }
350
351 if( on != m_state )
352 {
353 ++m_changes;
354 m_state = on;
355 if( on )
356 {
357 toggleOn();
358 m_parentGraph->valueExtra( m_node->name(), "state", m_onStr );
359 return 0;
360 }
361 else
362 {
363 toggleOff();
364 m_parentGraph->valueExtra( m_node->name(), "state", m_offStr );
365 return 0;
366 }
367 }
368
369 return 0;
370}
371
373{
374 togglePutsOn();
375}
376
378{
380}
381
382inline void indiPropNode::loadConfig( mx::app::appConfigurator &config )
383{
384 if( !m_parentGraph )
385 {
386 std::string msg = XIGN_EXCEPTION( "indiPropNode::loadConfig", "parent graph is null" );
387 throw std::runtime_error( msg );
388 }
389
390 std::string type;
391 config.configUnused( type, mx::app::iniFile::makeKey( name(), "type" ) );
392
393 if( type != "indiProp" )
394 {
395 std::string msg = XIGN_EXCEPTION( "indiPropNode::loadConfig", "node type is not indiProp" );
396 throw std::runtime_error( msg );
397 }
398
400
401 std::string pk;
402 config.configUnused( pk, mx::app::iniFile::makeKey( name(), "propKey" ) );
403
404 if( pk == "" )
405 {
406 std::string msg = XIGN_EXCEPTION( "indiPropNode::loadConfig", "propKey can not be empty" );
407 throw std::runtime_error( msg );
408 }
409
410 std::string pe;
411 config.configUnused( pe, mx::app::iniFile::makeKey( name(), "propEl" ) );
412
413 if( pe == "" )
414 {
415 std::string msg = XIGN_EXCEPTION( "indiPropNode::loadConfig", "propEl can not be empty" );
416 throw std::runtime_error( msg );
417 }
418
419 std::string pv;
420 config.configUnused( pv, mx::app::iniFile::makeKey( name(), "propVal" ) );
421
422 if( pv == "" )
423 {
424 std::string msg = XIGN_EXCEPTION( "indiPropNode::loadConfig", "propVal can not be empty" );
425 throw std::runtime_error( msg );
426 }
427
428 config.configUnused( m_tol, mx::app::iniFile::makeKey( name(), "tol" ) );
429
430 // Add propEl and propVal
431 propKey( pk );
432 m_propEl = pe;
433 m_propValStr = pv;
434
435 config.configUnused( m_onStr, mx::app::iniFile::makeKey( name(), "onStr" ) );
436 config.configUnused( m_offStr, mx::app::iniFile::makeKey( name(), "offStr" ) );
437}
438
439#endif // indiPropNode_hpp
Implementation of an instGraph node interface for a MagAO-X Finite State Machine (FSM)
Definition fsmNode.hpp:69
virtual int handleSetProperty(const pcf::IndiProperty &ipRecv)
INDI SetProperty callback.
Definition fsmNode.hpp:375
void loadConfigDerived(mx::app::appConfigurator &config)
Load this specific node's settings from an application configuration of a derived class.
Definition fsmNode.hpp:336
An instGraph node which tracks a specific INDI property and element of that property.
const std::string & propEl() const
Get the element of the INDI property to track.
const pcf::IndiProperty::Type & type() const
Get the type of the INDI property being tracked.
std::string m_propKey
unique key, device.name, of the property tp track
const pcf::IndiElement::SwitchStateType & propValSw()
Get the target value of the INDI element if it's a switch.
void loadConfig(mx::app::appConfigurator &config)
Configure this node form an appConfigurator.
bool m_state
The current state of the comparison.
bool m_first
Flag indicating if it's the first call to handleSetProperty.
std::string m_offStr
virtual int handleSetProperty(const pcf::IndiProperty &ipRecv)
INDI SetProperty callback.
indiPropNode(const std::string &name, ingr::instGraphXML *parentGraph)
Only c'tor. Must be constructed with node name and a parent graph.
const bool & state() const
Get the current value of the comparison.
const std::string & propValStr() const
Get the target value of the INDI element.
virtual void toggleOff()
Toggle all puts off.
std::string m_propValStr
the target value of the element. This is always set.
double m_tol
The tolerance for floating point comparison. Default is 1e-7.
double m_propValNum
pcf::IndiProperty::Type m_type
The property type. Discovered introspectively on first call to handleSetProperty.
pcf::IndiElement::SwitchStateType m_propValSw
const std::string & propKey() const
Get the unique key of the INDI property to track.
std::string m_propEl
the element of the property to track
virtual void toggleOn()
Toggle all puts on.
virtual int firstSetProperty(const pcf::IndiProperty &ipRecv)
On first call to handleSetProperty we find the property type and convert the target value.
std::string m_onStr
const double & tol() const
Get the tolerance used for numeric comparison.
const double & propValNum() const
Get the target value of the INDI element if it's a number.
void key(const std::string &nkey)
Add a key to the set.
Definition xigNode.hpp:116
ingr::instNode * m_node
The underlying instGraph node.
Definition xigNode.hpp:37
virtual void togglePutsOn()
Change the state of all inputs and all outputs to on.
Definition xigNode.hpp:126
int m_changes
Counter that can be incremented when changes are detected. Set to 0 when graph is updated.
Definition xigNode.hpp:39
ingr::instGraphXML * m_parentGraph
The parent instGraph that this node is a part of.
Definition xigNode.hpp:35
std::string name()
Get the name of this node.
Definition xigNode.hpp:106
virtual void togglePutsOff()
Change the state of all inputs and all outputs to off.
Definition xigNode.hpp:141
The MagAO-X Instrument Graph fsmNode header file.
#define XIGN_EXCEPTION(src, expl)
Definition xigNode.hpp:24