API
 
Loading...
Searching...
No Matches
xInstGraph.hpp
Go to the documentation of this file.
1/** \file xInstGraph.hpp
2 * \brief The MagAO-X Instrument Graph header file
3 *
4 * \ingroup instGraph_files
5 */
6
7#ifndef xInstGraph_hpp
8#define xInstGraph_hpp
9
10#include <instGraph/instGraphXML.hpp>
11using namespace ingr;
12
13#include "../../libMagAOX/libMagAOX.hpp" //Note this is included on command line to trigger pch
14#include "../../magaox_git_version.h"
15
17#include "xigNodes/fsmNode.hpp"
21
22/** \defgroup instGraph
23 * \brief The XXXXXX application to do YYYYYYY
24 *
25 * <a href="../handbook/operating/software/apps/XXXXXX.html">Application Documentation</a>
26 *
27 * \ingroup apps
28 *
29 */
30
31/** \defgroup instGraph_files
32 * \ingroup instGraph
33 */
34
35//forward for test harness
36namespace xInstGraph_test
37{
38 class xInstGraph;
39}
40
41namespace MagAOX
42{
43namespace app
44{
45
46/// The MagAO-X xxxxxxxx
47/**
48 * \ingroup instGraph
49 */
50class xInstGraph : public MagAOXApp<true>
51{
52 // Give the test harness access.
54
55 protected:
56 /** \name Configurable Parameters
57 *@{
58 */
59
60 // here add parameters which will be config-able at runtime
61
62 ///@}
63
64 ingr::instGraphXML m_graph;
65
66 std::map<std::string, xigNode *> m_nodes;
67
68 std::vector<pcf::IndiProperty *> m_nodeProps; ///< The node INDI properties to register for SetProperty
69
70 std::multimap<std::string, xigNode *> m_nodeHandleSets; /**< Map from propery keys to nodes which
71 have registered for them*/
72
73 public:
74 /// Default c'tor.
75 xInstGraph();
76
77 /// D'tor
79
80 virtual void setupConfig();
81
82 /// Implementation of loadConfig logic, separated for testing.
83 /** This is called by loadConfig().
84 */
85 int loadConfigImpl( mx::app::appConfigurator &_config /**< [in] an application configuration from
86 which to load values*/
87 );
88
89 virtual void loadConfig();
90
91 /// Startup function
92 /**
93 *
94 */
95 virtual int appStartup();
96
97 /// Implementation of the FSM for xInstGraph.
98 /**
99 * \returns 0 on no critical error
100 * \returns -1 on an error requiring shutdown
101 */
102 virtual int appLogic();
103
104 /// Shutdown the app.
105 /**
106 *
107 */
108 virtual int appShutdown();
109
110 static int st_igHandleSetProperty( void *igapp, /**< [in] this pointer */
111 const pcf::IndiProperty &ipRecv /**< [in] the INDI property sent with
112 the the set property message.*/
113 );
114
115 int igHandleSetProperty( const pcf::IndiProperty &ipRecv /**< [in] the INDI property sent with
116 the the set property message.*/
117 );
118};
119
124
126{
127 for( auto p : m_nodeProps )
128 {
129 delete p;
130 }
131}
132
134{
135 config.add( "graph.file",
136 "",
137 "graph.file",
138 argType::Required,
139 "graph",
140 "file",
141 false,
142 "string",
143 "name of input graph drawio file, including extension, in the config directory" );
144
145 config.add( "graph.outputPath",
146 "",
147 "graph.outputPath",
148 argType::Required,
149 "graph",
150 "outputPath",
151 false,
152 "string",
153 "path to the output graph .drawio file" );
154}
155
156int xInstGraph::loadConfigImpl( mx::app::appConfigurator &_config )
157{
158 ///\todo this should be relative to config path
159 std::string file;
160 _config( file, "graph.file" );
161
162 if( file == "" )
163 {
164 return log<software_error, -1>( { __FILE__, __LINE__, "no graph file in configuration (graph.file)" } );
165 }
166
167 file = m_configDir + '/' + file;
168
169
170 std::string outputPath = m_graph.outputPath();
171 _config( outputPath, "graph.outputPath" );
172 m_graph.outputPath( outputPath );
173
174 std::string emsg;
175 if( m_graph.loadXMLFile( emsg, file ) < 0 )
176 {
177 return log<software_error, -1>( { __FILE__, __LINE__, "error loading graph file: " + emsg } );
178 }
179
180 std::vector<std::string> sections;
181
182 _config.unusedSections( sections );
183
184 if( sections.size() == 0 )
185 {
186 return log<software_error, -1>( { __FILE__, __LINE__, "no nodes found in configuration" } );
187 }
188
189 for( size_t i = 0; i < sections.size(); ++i )
190 {
191 bool isNode = config.isSetUnused( mx::app::iniFile::makeKey( sections[i], "type" ) );
192
193 if( !isNode )
194 {
195 continue;
196 }
197
198 std::string type;
199 _config.configUnused( type, mx::app::iniFile::makeKey( sections[i], "type" ) );
200
201 // std::cerr << "found node " << sections[i] << ": " << type << "\n";
202
203 xigNode *xn = nullptr;
204
205 if( type == "indiProp" )
206 {
207 indiPropNode *ip = nullptr;
208 try
209 {
210 ip = new indiPropNode( sections[i], &m_graph );
211 }
212 catch( const std::exception &e )
213 {
214 std::string msg = XIGN_EXCEPTION( "indiGraph::loadConfigImpl", "exception caught" );
215 msg += ": ";
216 msg += e.what();
217 throw std::runtime_error( msg );
218 }
219
220 if( ip == nullptr )
221 {
222 std::string msg = XIGN_EXCEPTION( "indiGraph::loadConfigImpl", "failed to allocate node" );
223 throw std::runtime_error( msg );
224 }
225
226 try
227 {
228 ip->loadConfig( _config );
229 }
230 catch( const std::exception &e )
231 {
232 std::string msg = XIGN_EXCEPTION( "indiGraph::loadConfigImpl", "exception caught" );
233 msg += ": ";
234 msg += e.what();
235 throw std::runtime_error( msg );
236 }
237
238 xn = ip;
239 }
240 else if( type == "pwrOnOff" )
241 {
242 pwrOnOffNode *nn = nullptr;
243
244 try
245 {
246 nn = new pwrOnOffNode( sections[i], &m_graph );
247 }
248 catch( const std::exception &e )
249 {
250 std::string msg = XIGN_EXCEPTION( "indiGraph::loadConfigImpl", "exception caught" );
251 msg += ": ";
252 msg += e.what();
253 throw std::runtime_error( msg );
254 }
255
256 if( nn == nullptr )
257 {
258 std::string msg = XIGN_EXCEPTION( "indiGraph::loadConfigImpl", "failed to allocate node" );
259 throw std::runtime_error( msg );
260 }
261
262 try
263 {
264 nn->loadConfig( _config );
265 }
266 catch( const std::exception &e )
267 {
268 std::string msg = XIGN_EXCEPTION( "indiGraph::loadConfigImpl", "exception caught" );
269 msg += ": ";
270 msg += e.what();
271 throw std::runtime_error( msg );
272 }
273
274 xn = nn;
275 }
276 else if( type == "fsm" )
277 {
278 fsmNode *nn = nullptr;
279
280 try
281 {
282 nn = new fsmNode( sections[i], &m_graph );
283 }
284 catch( const std::exception &e )
285 {
286 std::string msg = XIGN_EXCEPTION( "indiGraph::loadConfigImpl", "exception caught" );
287 msg += ": ";
288 msg += e.what();
289 throw std::runtime_error( msg );
290 }
291
292 if( nn == nullptr )
293 {
294 std::string msg = XIGN_EXCEPTION( "indiGraph::loadConfigImpl", "failed to allocate node" );
295 throw std::runtime_error( msg );
296 }
297
298 try
299 {
300 nn->loadConfig( _config );
301 }
302 catch( const std::exception &e )
303 {
304 std::string msg = XIGN_EXCEPTION( "indiGraph::loadConfigImpl", "exception caught" );
305 msg += ": ";
306 msg += e.what();
307 throw std::runtime_error( msg );
308 }
309
310 xn = nn;
311 }
312 else if( type == "stdMotion" )
313 {
314 stdMotionNode *nn = nullptr;
315
316 try
317 {
318 nn = new stdMotionNode( sections[i], &m_graph );
319 }
320 catch( const std::exception &e )
321 {
322 std::string msg = XIGN_EXCEPTION( "indiGraph::loadConfigImpl", "exception caught" );
323 msg += ": ";
324 msg += e.what();
325 throw std::runtime_error( msg );
326 }
327
328 if( nn == nullptr )
329 {
330 std::string msg = XIGN_EXCEPTION( "indiGraph::loadConfigImpl", "failed to allocate node" );
331 throw std::runtime_error( msg );
332 }
333
334 try
335 {
336 nn->loadConfig( _config );
337 }
338 catch( const std::exception &e )
339 {
340 std::string msg = XIGN_EXCEPTION( "indiGraph::loadConfigImpl", "exception caught" );
341 msg += ": ";
342 msg += e.what();
343 throw std::runtime_error( msg );
344 }
345
346 xn = nn;
347 }
348 else if( type == "static" )
349 {
350 staticNode *nn = nullptr;
351
352 try
353 {
354 nn = new staticNode( sections[i], &m_graph );
355 }
356 catch( const std::exception &e )
357 {
358 std::string msg = XIGN_EXCEPTION( "indiGraph::loadConfigImpl", "exception caught" );
359 msg += ": ";
360 msg += e.what();
361 throw std::runtime_error( msg );
362 }
363
364 if( nn == nullptr )
365 {
366 std::string msg = XIGN_EXCEPTION( "indiGraph::loadConfigImpl", "failed to allocate node" );
367 throw std::runtime_error( msg );
368 }
369
370 try
371 {
372 nn->loadConfig( _config );
373 }
374 catch( const std::exception &e )
375 {
376 std::string msg = XIGN_EXCEPTION( "indiGraph::loadConfigImpl", "exception caught" );
377 msg += ": ";
378 msg += e.what();
379 throw std::runtime_error( msg );
380 }
381
382 xn = nn;
383 }
384
385 if( xn != nullptr )
386 {
387 try
388 {
389 m_nodes.insert( { xn->node()->name(), xn } );
390 }
391 catch( const std::exception &e )
392 {
393 std::string msg = e.what();
394 msg += "\ncaught at ";
395 msg += __FILE__;
396 msg += " " + std::to_string( __LINE__ );
397 throw std::runtime_error( msg );
398 }
399 }
400 }
401
402 m_graph.hideLinks();
403 m_graph.hidePuts();
404
405 return 0;
406}
407
409{
410 if( loadConfigImpl( config ) < 0 )
411 {
412 log<software_error>( { __FILE__, __LINE__, "error loading configuration" } );
413 m_shutdown = true;
414 }
415}
416
417std::string deviceFromKey( const std::string &key )
418{
419 size_t dot = key.find( '.' );
420
421 if( dot == std::string::npos )
422 {
423 return "";
424 }
425
426 return key.substr( 0, dot );
427}
428
429std::string nameFromKey( const std::string &key )
430{
431 size_t dot = key.find( '.' );
432 if( dot == std::string::npos )
433 {
434 return "";
435 }
436
437 return key.substr( dot + 1 );
438}
439
441{
442 for( auto it = m_nodes.begin(); it != m_nodes.end(); ++it )
443 {
444 for( auto kit = it->second->keys().begin(); kit != it->second->keys().end(); ++kit )
445 {
446 try
447 {
448 std::string devName = deviceFromKey( *kit );
449 std::string propName = nameFromKey( *kit );
450
451 if( devName == "" )
452 {
453 return log<software_error, -1>(
454 { __FILE__, __LINE__, "bad devName from key: " + it->second->name() } );
455 }
456
457 if( propName == "" )
458 {
459 return log<software_error, -1>(
460 { __FILE__, __LINE__, "bad propName from key: " + it->second->name() } );
461 }
462
463 m_nodeHandleSets.insert( { *kit, it->second } );
464
465 pcf::IndiProperty *p = new pcf::IndiProperty;
466
467 p->setDevice( devName );
468 p->setName( propName );
469
470 m_nodeProps.push_back( p );
471
472 if( !m_indiSetCallBacks.contains( *kit ) )
473 {
476
477 if( !result.second )
478 {
479 return log<software_error, -1>(
480 { __FILE__, __LINE__, "failed to insert INDI property: " + p->createUniqueKey() } );
481 }
482 }
483 }
484 catch( std::exception &e )
485 {
486 return log<software_error, -1>(
487 { __FILE__, __LINE__, std::string( "Exception caught: " ) + e.what() } );
488 }
489 catch( ... )
490 {
491 return log<software_error, -1>( { __FILE__, __LINE__, "Unknown exception caught." } );
492 }
493 }
494 }
495
497
498 return 0;
499}
500
502{
503 return 0;
504}
505
507{
508 //remove the output file so that it is clear there is no valid graph
509 std::filesystem::remove(m_graph.outputPath());
510
511 return 0;
512}
513
514int xInstGraph::st_igHandleSetProperty( void *igapp, const pcf::IndiProperty &ipRecv )
515{
516 if( igapp == nullptr )
517 {
518 return -1;
519 }
520
521 return reinterpret_cast<xInstGraph *>( igapp )->igHandleSetProperty( ipRecv );
522}
523
524int xInstGraph::igHandleSetProperty( const pcf::IndiProperty &ipRecv )
525{
526 std::cerr << ipRecv.createUniqueKey() << '\n';
527 try
528 {
529 auto range = m_nodeHandleSets.equal_range( ipRecv.createUniqueKey() );
530
531 for( auto it = range.first; it != range.second; ++it )
532 {
533 std::cerr << it->second->name() << '\n';
534
535 int rv = it->second->handleSetProperty( ipRecv );
536 if( rv != 0 )
537 {
538 return log<software_error, -1>(
539 { __FILE__, __LINE__, "error from handleSetProperty for " + it->second->name() } );
540 }
541 }
542
543 return 0;
544 }
545 catch( std::exception &e )
546 {
547 return log<software_error, -1>( { __FILE__, __LINE__, std::string( "Exception caught: " ) + e.what() } );
548 }
549 catch( ... )
550 {
551 return log<software_error, -1>( { __FILE__, __LINE__, "Unknown exception caught." } );
552 }
553}
554
555} // namespace app
556} // namespace MagAOX
557
558#endif // xInstGraph_hpp
The base-class for XWCTk applications.
void handleSetProperty(const pcf::IndiProperty &ipRecv)
Handler for the set INDI property request.
stateCodes::stateCodeT state()
Get the current state code.
int m_shutdown
Flag to signal it's time to shutdown. When not 0, the main loop exits.
std::pair< std::string, indiCallBack > callBackValueType
Value type of the indiCallBack map.
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.
std::pair< callBackIterator, bool > callBackInsertResult
Return type of insert on the indiCallBack map.
std::unordered_map< std::string, indiCallBack > m_indiSetCallBacks
Map to hold the SetProperty indiCallBacks for this App, with fast lookup by property name.
The MagAO-X xxxxxxxx.
int loadConfigImpl(mx::app::appConfigurator &_config)
Implementation of loadConfig logic, separated for testing.
std::vector< pcf::IndiProperty * > m_nodeProps
The node INDI properties to register for SetProperty.
ingr::instGraphXML m_graph
virtual int appStartup()
Startup function.
int igHandleSetProperty(const pcf::IndiProperty &ipRecv)
virtual void setupConfig()
std::multimap< std::string, xigNode * > m_nodeHandleSets
static int st_igHandleSetProperty(void *igapp, const pcf::IndiProperty &ipRecv)
virtual int appShutdown()
Shutdown the app.
virtual void loadConfig()
friend class xInstGraph_test::xInstGraph
virtual int appLogic()
Implementation of the FSM for xInstGraph.
~xInstGraph() noexcept
D'tor.
std::map< std::string, xigNode * > m_nodes
Implementation of an instGraph node interface for a MagAO-X Finite State Machine (FSM)
Definition fsmNode.hpp:69
An instGraph node which tracks a specific INDI property and element of that property.
An instGraph node which is static, with status set at config time and not changing.
Implementation of basic instGraph node interface for MagAO-X.
Definition xigNode.hpp:31
The MagAO-X Instrument Graph fsmNode header file.
@ READY
The device is ready for operation, but is not operating.
The MagAO-X Instrument Graph indiPropNode header file.
std::stringstream msg
const pcf::IndiProperty & ipRecv
std::string deviceFromKey(const std::string &key)
std::string nameFromKey(const std::string &key)
Definition dm.hpp:19
The MagAO-X Instrument Graph pwrOnOffNode header file.
The MagAO-X Instrument Graph staticNode header file.
The MagAO-X Instrument Graph stdMotionNode header file.
Software ERR log entry.
#define XIGN_EXCEPTION(src, expl)
Definition xigNode.hpp:24