source: trunk/FACT++/src/gcn.cc@ 19536

Last change on this file since 19536 was 19528, checked in by tbretz, 6 years ago
Minor changes, mainly added a name which is sent.
File size: 25.2 KB
Line 
1#include <functional>
2#include <boost/algorithm/string/join.hpp>
3
4#include "Dim.h"
5#include "Event.h"
6#include "Shell.h"
7#include "StateMachineDim.h"
8#include "StateMachineAsio.h"
9#include "Connection.h"
10#include "LocalControl.h"
11#include "Configuration.h"
12#include "Console.h"
13#include "Converter.h"
14
15#include "tools.h"
16#include "../externals/nova.h"
17
18#include "HeadersGCN.h"
19#include "HeadersToO.h"
20
21#include <QtXml/QDomDocument>
22
23namespace ba = boost::asio;
24namespace bs = boost::system;
25namespace dummy = ba::placeholders;
26
27using namespace std;
28using namespace GCN;
29
30// ------------------------------------------------------------------------
31
32class ConnectionGCN : public Connection
33{
34private:
35 map<uint16_t, GCN::PaketType_t> fTypes;
36
37 vector<string> fEndPoints;
38 int fEndPoint;
39
40 bool fIsVerbose;
41 bool fDebugRx;
42
43 uint32_t fRxSize;
44 vector<char> fRxData;
45
46 Time fLastKeepAlive;
47
48 QString GetParamValue(const QDomElement &what, const string &name)
49 {
50 const QDomNodeList param = what.elementsByTagName("Param");
51 for (int i=0; i<param.count(); i++)
52 {
53 const QDomElement elem = param.at(i).toElement();
54 if (elem.attribute("name").toStdString()==name)
55 return elem.attribute("value");
56 }
57
58 return "";
59 }
60
61 GCN::PaketPtr GetType(const QDomElement &what)
62 {
63 const auto value = GetParamValue(what, "Packet_Type");
64 if (value.isEmpty())
65 return GCN::PaketTypes.end();
66
67 const uint16_t val = value.toUInt();
68
69 const auto it = GCN::PaketTypes.find(val);
70
71 if (it==GCN::PaketTypes.end())
72 Warn("Unknown paket type "+to_string(val)+".");
73
74 return it;
75
76 }
77
78 int ProcessXml(const QDomElement &root)
79 {
80 if (root.isNull())
81 return -1;
82
83 const string role = root.attribute("role", "").toStdString();
84 const string trn = root.tagName().toStdString();
85
86 // A full description can be found at http://voevent.dc3.com/schema/default.html
87
88 if (trn=="trn:Transport")
89 {
90 if (role=="iamalive")
91 {
92 const QDomElement orig = root.firstChildElement("Origin");
93 const QDomElement time = root.firstChildElement("TimeStamp");
94 if (orig.isNull() || time.isNull())
95 return -1;
96
97 fLastKeepAlive = Time(time.text().toStdString());
98
99 if (fIsVerbose)
100 {
101 Out() << Time().GetAsStr() << " ----- " << trn << " [" << role << "] -----" << endl;
102 Out() << " " << time.tagName().toStdString() << " = " << fLastKeepAlive.GetAsStr() << '\n';
103 Out() << " " << orig.tagName().toStdString() << " = " << orig.text().toStdString() << '\n';
104 Out() << endl;
105 }
106
107 return true;
108 }
109
110 return false;
111 }
112
113 ofstream fout("gcn.stream", ios::app);
114 fout << "------------------------------------------------------------------------------\n" << fRxData.data() << endl;
115
116 if (trn=="voe:VOEvent")
117 {
118 // WHAT: http://gcn.gsfc.nasa.gov/tech_describe.html
119 const QDomElement who = root.firstChildElement("Who");
120 const QDomElement what = root.firstChildElement("What");
121 const QDomElement when = root.firstChildElement("WhereWhen");
122 //const QDomElement how = root.firstChildElement("How");
123 //const QDomElement why = root.firstChildElement("Why");
124 //const QDomElement cite = root.firstChildElement("Citations");
125 //const QDomElement desc = root.firstChildElement("Description");
126 //const QDomElement ref = root.firstChildElement("Reference");
127 if (who.isNull() || what.isNull() || when.isNull())
128 return -1;
129
130 const auto ptype = GetType(what);
131
132 const QDomElement date = who.firstChildElement("Date");
133 const QDomElement author = who.firstChildElement("Author");
134 const QDomElement sname = author.firstChildElement("shortName");
135 const QDomElement desc = what.firstChildElement("Description");
136
137 const QDomElement obsdat = when.firstChildElement("ObsDataLocation");
138 const QDomElement obsloc = obsdat.firstChildElement("ObservationLocation");
139 const QDomElement coord = obsloc.firstChildElement("AstroCoords");
140
141 const QDomElement time = coord.firstChildElement("Time").firstChildElement("TimeInstant").firstChildElement("ISOTime");
142 const QDomElement pos2d = coord.firstChildElement("Position2D");
143 const QDomElement name1 = pos2d.firstChildElement("Name1");
144 const QDomElement name2 = pos2d.firstChildElement("Name2");
145 const QDomElement val2 = pos2d.firstChildElement("Value2");
146 const QDomElement c1 = val2.firstChildElement("C1");
147 const QDomElement c2 = val2.firstChildElement("C2");
148 const QDomElement errad = pos2d.firstChildElement("Error2Radius");
149
150 const auto &id = ptype->first;
151
152 // Gravitational wave event
153 const bool is_gw = id==150 || id==151 || id==152 || id==153 || id==164;
154
155 // Required keywords
156 vector<string> missing;
157 if (date.isNull())
158 missing.emplace_back("Date");
159 if (author.isNull())
160 missing.emplace_back("Author");
161 if (sname.isNull() && !is_gw)
162 missing.emplace_back("shortName");
163 if (obsdat.isNull())
164 missing.emplace_back("ObsDataLocation");
165 if (obsloc.isNull())
166 missing.emplace_back("ObservationLocation");
167 if (coord.isNull())
168 missing.emplace_back("AstroCoords");
169 if (time.isNull())
170 missing.emplace_back("Time/TimeInstant/ISOTime");
171 if (pos2d.isNull() && !is_gw)
172 missing.emplace_back("Position2D");
173 if (name1.isNull() && !is_gw)
174 missing.emplace_back("Name1");
175 if (name1.isNull() && !is_gw)
176 missing.emplace_back("Name2");
177 if (val2.isNull() && !is_gw)
178 missing.emplace_back("Value2");
179 if (c1.isNull() && !is_gw)
180 missing.emplace_back("C1");
181 if (c2.isNull() && !is_gw)
182 missing.emplace_back("C2");
183 if (errad.isNull() && !is_gw)
184 missing.emplace_back("Error2Radius");
185
186 if (!missing.empty())
187 {
188 Warn("Missing elements: "+boost::algorithm::join(missing, ", "));
189 return -1;
190 }
191
192 // 59/31: Konus LC / IPN raw [observation]
193 // 110: Fermi GBM (ART) [observation] (Initial) // Stop data taking
194 // 111: Fermi GBM (FLT) [observation] (after ~2s) // Start pointing/run
195 // 112: Fermi GBM (GND) [observation] (after 2-20s) // Refine pointing
196 // 115: Fermi GBM position [observation] (final ~hours)
197 //
198 // 51: Intergal pointdir [utility]
199 // 83: Swift pointdir [utility]
200 // 129: Fermi pointdir [utility]
201 //
202 // 2: Test coord ( 1) [test]
203 // 44: HETE test ( 41- 43) [test]
204 // 52: Integral SPIACS [test]
205 // 53: Integral Wakeup [test]
206 // 54: Integral refined [test]
207 // 55: Integral Offline [test]
208 // 56: Integral Weak [test]
209 // 82: BAT GRB pos test ( 61) [test]
210 // 109: AGILE GRB pos test (100-103) [test]
211 // 119: Fermi GRB pos test (111-113) [test]
212 // 124: Fermi LAT pos upd test (120-122) [test]
213 // 136: MAXI coord test ( 134) [test]
214 //
215 // Integral: RA=1.2343, Dec=2.3456
216 //
217
218 /*
219 54
220 ==
221 <Group name="Test_mpos" >
222 <Param name="Test_Notice" value="true" />
223 </Group>
224
225
226 82
227 ==
228 <Group name="Solution_Status" >
229 <Param name="Test_Submission" value="false" />
230 </Group>
231
232
233 115
234 ===
235 2013-07-20 19:04:13: TIME = 2013-07-20 02:46:40
236
237 <Group name="Trigger_ID" >
238 <Param name="Test_Submission" value="false" />
239 </Group>
240 */
241
242 // ----------------------------- Create Name ----------------------
243
244 const auto &paket = ptype->second;
245
246 string name;
247 bool prefix = true;
248
249 switch (id)
250 {
251 case 60:
252 case 61:
253 case 62:
254
255 case 110:
256 case 111:
257 case 112:
258 case 115:
259 name = GetParamValue(what, "TRIGGER_NUM").toStdString();
260 break;
261
262 case 123:
263 name = GetParamValue(what, "REF_NUM").toStdString();
264 break;
265
266 case 125:
267 name = GetParamValue(what, "SourceName").toStdString();
268 prefix = false;
269 break;
270
271 case 157:
272 case 158:
273 {
274 const string event_id = GetParamValue(what, "event_id").toStdString();
275 const string run_id = GetParamValue(what, "run_id").toStdString();
276 name = event_id+"_"+run_id;
277 break;
278 }
279
280 // Missing ID
281 // case 51:
282 // case 83:
283 // case 119:
284 // case 129:
285 default:
286 name = GetParamValue(what, "TrigID").toStdString();
287 }
288
289 if (name.empty() || name=="0")
290 {
291 Warn("Missing ID... cannot create default source name... using date instead.");
292 name = Time().GetAsStr("%Y%m%d_%H%M%S");
293 prefix = true;
294 }
295
296 if (prefix)
297 name.insert(0, paket.instrument+"#");
298
299 // ----------------------------------------------------------------
300
301 const string unit = pos2d.attribute("unit").toStdString();
302
303 const double ra = c1.text().toDouble();
304 const double dec = c2.text().toDouble();
305 const double err = errad.text().toDouble();
306
307 const string n1 = name1.text().toStdString();
308 const string n2 = name2.text().toStdString();
309
310 const bool has_coordinates = n1=="RA" && n2=="Dec" && unit=="deg";
311
312 const std::set<int16_t> typelist =
313 {
314 51, // INTEGRAL_POINTDIR
315
316 53, // INTEGRAL_WAKEUP
317 54, // INTEGRAL_REFINED
318 55, // INTEGRAL_OFFLINE
319
320 // 56, // INTEGRAL_WEAK
321 // 59, // KONUS_LC
322
323 60, // SWIFT_BAT_GRB_ALERT
324 61, // SWIFT_BAT_GRB_POS_ACK
325 62, // SWIFT_BAT_GRB_POS_NACK
326
327 83, // SWIFT_POINTDIR
328
329 97, // SWIFT_BAT_QL_POS
330
331 100, // AGILE_GRB_WAKEUP
332 101, // AGILE_GRB_GROUND
333 102, // AGILE_GRB_REFINED
334
335 110, // FERMI_GBM_FLT_POS
336 111, // FERMI_GBM_GND_POS
337 112, // FERMI_GBM_LC
338 115, // FERMI_GBM_TRANS
339
340 123, // FERMI_LAT_TRANS
341 125, // FERMI_LAT_MONITOR
342
343 // 134, // MAXI_UNKNOWN
344 // 135, // MAXI_KNOWN
345 // 136, // MAXI_TEST
346
347 157, // AMON_ICECUBE_COINC
348 158, // AMON_ICECUBE_HESE
349
350 169, // AMON_ICECUBE_EHE
351 171, // HAWC_BURST_MONITOR
352 173, // ICECUBE_GOLD
353 174, // ICECUBE_BRONZE
354 };
355
356 const bool integral_test = role=="test" && id>=53 && id<=56;
357
358 const bool valid_id = typelist.find(id)!=typelist.end();
359
360 if (valid_id && has_coordinates && !integral_test)
361 {
362 const ToO::DataGRB data =
363 {
364 .type = id,
365 .ra = ra,
366 .dec = dec,
367 .err = err,
368 };
369
370 vector<char> dim(sizeof(ToO::DataGRB) + name.size() + 1);
371
372 memcpy(dim.data(), &data, sizeof(ToO::DataGRB));
373 memcpy(dim.data()+sizeof(ToO::DataGRB), name.c_str(), name.size());
374
375 Dim::SendCommandNB("SCHEDULER/GCN", dim);
376 Info("Sent ToO '"+name+"' ["+role+"]");
377 }
378
379 Out() << Time(date.text().toStdString()).GetAsStr() << " ----- " << sname.text().toStdString() << " [" << role << "]\n";
380 if (!desc.isNull())
381 Out() << "[" << desc.text().toStdString() << "]\n";
382 Out() << name << ": " << paket.name << "[" << id << "]: " << paket.description << endl;
383 Out() << left;
384 Out() << " " << setw(5) << "TIME" << "= " << Time(time.text().toStdString()).GetAsStr() << '\n';
385 Out() << " " << setw(5) << n1 << "= " << ra << unit << '\n';
386 Out() << " " << setw(5) << n2 << "= " << dec << unit << '\n';
387 Out() << " " << setw(5) << "ERR" << "= " << err << unit << '\n';
388 Out() << endl;
389
390 if (role=="observation")
391 {
392 return true;
393 }
394
395 if (role=="test")
396 {
397 return true;
398 }
399
400 if (role=="retraction")
401 {
402 return true;
403 }
404
405 if (role=="utility")
406 {
407 return true;
408 }
409
410 return false;
411 }
412
413 Out() << Time().GetAsStr() << " ----- " << trn << " [" << role << "] -----" << endl;
414
415 return false;
416 }
417
418 void HandleReceivedData(const bs::error_code& err, size_t bytes_received, int type)
419 {
420 // Do not schedule a new read if the connection failed.
421 if (bytes_received==0 || err)
422 {
423 if (err==ba::error::eof)
424 Warn("Connection closed by remote host (GCN).");
425
426 // 107: Transport endpoint is not connected (bs::error_code(107, bs::system_category))
427 // 125: Operation canceled
428 if (err && err!=ba::error::eof && // Connection closed by remote host
429 err!=ba::error::basic_errors::not_connected && // Connection closed by remote host
430 err!=ba::error::basic_errors::operation_aborted) // Connection closed by us
431 {
432 ostringstream str;
433 str << "Reading from " << URL() << ": " << err.message() << " (" << err << ")";// << endl;
434 Error(str);
435 }
436 PostClose(err!=ba::error::basic_errors::operation_aborted);
437 return;
438 }
439
440 if (type==0)
441 {
442 fRxSize = ntohl(fRxSize);
443 fRxData.assign(fRxSize+1, 0);
444 ba::async_read(*this, ba::buffer(fRxData, fRxSize),
445 boost::bind(&ConnectionGCN::HandleReceivedData, this,
446 dummy::error, dummy::bytes_transferred, 1));
447 return;
448 }
449
450 if (fDebugRx)
451 {
452 Out() << "------------------------------------------------------\n";
453 Out() << fRxData.data() << '\n';
454 Out() << "------------------------------------------------------" << endl;
455 }
456
457 QDomDocument doc;
458 if (!doc.setContent(QString(fRxData.data()), false))
459 {
460 Warn("Parsing of xml failed [0].");
461 Out() << "------------------------------------------------------\n";
462 Out() << fRxData.data() << '\n';
463 Out() << "------------------------------------------------------" << endl;
464 PostClose(false);
465 return;
466 }
467
468 if (fDebugRx)
469 Out() << "Parsed:\n-------\n" << doc.toString().toStdString() << endl;
470
471 const int rc = ProcessXml(doc.documentElement());
472 if (rc<0)
473 {
474 Warn("Parsing of xml failed [1].");
475 Out() << "------------------------------------------------------\n";
476 Out() << fRxData.data() << '\n';
477 Out() << "------------------------------------------------------" << endl;
478 PostClose(false);
479 return;
480 }
481
482 if (!rc)
483 {
484 Out() << "------------------------------------------------------\n";
485 Out() << doc.toString().toStdString() << '\n';
486 Out() << "------------------------------------------------------" << endl;
487 }
488
489 StartRead();
490 }
491
492 void StartRead()
493 {
494 ba::async_read(*this, ba::buffer(&fRxSize, 4),
495 boost::bind(&ConnectionGCN::HandleReceivedData, this,
496 dummy::error, dummy::bytes_transferred, 0));
497 }
498
499 // This is called when a connection was established
500 void ConnectionEstablished()
501 {
502 StartRead();
503 }
504
505public:
506 ConnectionGCN(ba::io_service& ioservice, MessageImp &imp) : Connection(ioservice, imp()),
507 fIsVerbose(false), fDebugRx(false), fLastKeepAlive(Time::none)
508 {
509 SetLogStream(&imp);
510 }
511
512 void SetVerbose(bool b)
513 {
514 fIsVerbose = b;
515 }
516
517 void SetDebugRx(bool b)
518 {
519 fDebugRx = b;
520 Connection::SetVerbose(b);
521 }
522
523 void SetEndPoints(const vector<string> &v)
524 {
525 fEndPoints = v;
526 fEndPoint = 0;
527 }
528
529 void StartConnect()
530 {
531 if (fEndPoints.size()>0)
532 SetEndpoint(fEndPoints[fEndPoint++%fEndPoints.size()]);
533 Connection::StartConnect();
534 }
535
536 bool IsValid()
537 {
538 return fLastKeepAlive.IsValid() ? Time()-fLastKeepAlive<boost::posix_time::minutes(2) : false;
539 }
540};
541
542// ------------------------------------------------------------------------
543
544#include "DimDescriptionService.h"
545
546class ConnectionDimGCN : public ConnectionGCN
547{
548private:
549
550public:
551 ConnectionDimGCN(ba::io_service& ioservice, MessageImp &imp) : ConnectionGCN(ioservice, imp)
552 {
553 }
554};
555
556// ------------------------------------------------------------------------
557
558template <class T, class S>
559class StateMachineGCN : public StateMachineAsio<T>
560{
561private:
562 S fGCN;
563
564 int Disconnect()
565 {
566 // Close all connections
567 fGCN.PostClose(false);
568
569 return T::GetCurrentState();
570 }
571
572 int Reconnect(const EventImp &evt)
573 {
574 // Close all connections to supress the warning in SetEndpoint
575 fGCN.PostClose(false);
576
577 // Now wait until all connection have been closed and
578 // all pending handlers have been processed
579 ba::io_service::poll();
580
581 if (evt.GetBool())
582 fGCN.SetEndpoint(evt.GetString());
583
584 // Now we can reopen the connection
585 fGCN.PostClose(true);
586
587 return T::GetCurrentState();
588 }
589
590 int Execute()
591 {
592 if (!fGCN.IsConnected())
593 return State::kDisconnected;
594
595 return fGCN.IsValid() ? State::kValid : State::kConnected;
596 }
597
598 bool CheckEventSize(size_t has, const char *name, size_t size)
599 {
600 if (has==size)
601 return true;
602
603 ostringstream msg;
604 msg << name << " - Received event has " << has << " bytes, but expected " << size << ".";
605 T::Fatal(msg);
606 return false;
607 }
608
609 int SetVerbosity(const EventImp &evt)
610 {
611 if (!CheckEventSize(evt.GetSize(), "SetVerbosity", 1))
612 return T::kSM_FatalError;
613
614 fGCN.SetVerbose(evt.GetBool());
615
616 return T::GetCurrentState();
617 }
618
619 int SetDebugRx(const EventImp &evt)
620 {
621 if (!CheckEventSize(evt.GetSize(), "SetDebugRx", 1))
622 return T::kSM_FatalError;
623
624 fGCN.SetDebugRx(evt.GetBool());
625
626 return T::GetCurrentState();
627 }
628
629public:
630 StateMachineGCN(ostream &out=cout) :
631 StateMachineAsio<T>(out, "GCN"), fGCN(*this, *this)
632 {
633 // State names
634 T::AddStateName(State::kDisconnected, "Disconnected",
635 "No connection to GCN.");
636 T::AddStateName(State::kConnected, "Connected",
637 "Connection to GCN established.");
638 T::AddStateName(State::kValid, "Valid",
639 "Connection valid (keep alive received within past 2min)");
640
641 // Verbosity commands
642 T::AddEvent("SET_VERBOSE", "B:1")
643 (bind(&StateMachineGCN::SetVerbosity, this, placeholders::_1))
644 ("set verbosity state"
645 "|verbosity[bool]:disable or enable verbosity for received data (yes/no), except dynamic data");
646 T::AddEvent("SET_DEBUG_RX", "B:1")
647 (bind(&StateMachineGCN::SetDebugRx, this, placeholders::_1))
648 ("Set debux-rx state"
649 "|debug[bool]:dump received text and parsed text to console (yes/no)");
650
651
652 // Conenction commands
653 T::AddEvent("DISCONNECT", State::kConnected)
654 (bind(&StateMachineGCN::Disconnect, this))
655 ("disconnect from ethernet");
656 T::AddEvent("RECONNECT", "O", State::kDisconnected, State::kConnected)
657 (bind(&StateMachineGCN::Reconnect, this, placeholders::_1))
658 ("(Re)connect ethernet connection to FTM, a new address can be given"
659 "|[host][string]:new ethernet address in the form <host:port>");
660
661 fGCN.StartConnect();
662 }
663
664 void SetEndpoint(const string &url)
665 {
666 vector<string> v;
667 v.push_back(url);
668 fGCN.SetEndPoints(v);
669 }
670
671 int EvalOptions(Configuration &conf)
672 {
673 fGCN.SetVerbose(!conf.Get<bool>("quiet"));
674 fGCN.SetEndPoints(conf.Vec<string>("addr"));
675
676 return -1;
677 }
678};
679
680// ------------------------------------------------------------------------
681
682#include "Main.h"
683
684template<class T, class S, class R>
685int RunShell(Configuration &conf)
686{
687 return Main::execute<T, StateMachineGCN<S, R>>(conf);
688}
689
690void SetupConfiguration(Configuration &conf)
691{
692 po::options_description control("FTM control options");
693 control.add_options()
694 ("no-dim", po_bool(), "Disable dim services")
695 ("addr,a", vars<string>(), "Network addresses of GCN server")
696 ("quiet,q", po_bool(true), "Disable printing contents of all received messages (except dynamic data) in clear text.")
697 ;
698
699 conf.AddOptions(control);
700}
701
702/*
703 Extract usage clause(s) [if any] for SYNOPSIS.
704 Translators: "Usage" and "or" here are patterns (regular expressions) which
705 are used to match the usage synopsis in program output. An example from cp
706 (GNU coreutils) which contains both strings:
707 Usage: cp [OPTION]... [-T] SOURCE DEST
708 or: cp [OPTION]... SOURCE... DIRECTORY
709 or: cp [OPTION]... -t DIRECTORY SOURCE...
710 */
711void PrintUsage()
712{
713 cout <<
714 "The gcn reads and evaluates alerts from the GCN network.\n"
715 "\n"
716 "The default is that the program is started without user intercation. "
717 "All actions are supposed to arrive as DimCommands. Using the -c "
718 "option, a local shell can be initialized. With h or help a short "
719 "help message about the usuage can be brought to the screen.\n"
720 "\n"
721 "Usage: gcn [-c type] [OPTIONS]\n"
722 " or: gcn [OPTIONS]\n";
723 cout << endl;
724}
725
726void PrintHelp()
727{
728 Main::PrintHelp<StateMachineGCN<StateMachine, ConnectionGCN>>();
729
730 /* Additional help text which is printed after the configuration
731 options goes here */
732
733 /*
734 cout << "bla bla bla" << endl << endl;
735 cout << endl;
736 cout << "Environment:" << endl;
737 cout << "environment" << endl;
738 cout << endl;
739 cout << "Examples:" << endl;
740 cout << "test exam" << endl;
741 cout << endl;
742 cout << "Files:" << endl;
743 cout << "files" << endl;
744 cout << endl;
745 */
746}
747
748int main(int argc, const char* argv[])
749{
750 Configuration conf(argv[0]);
751 conf.SetPrintUsage(PrintUsage);
752 Main::SetupConfiguration(conf);
753 SetupConfiguration(conf);
754
755 if (!conf.DoParse(argc, argv, PrintHelp))
756 return 127;
757
758 //try
759 {
760 // No console access at all
761 if (!conf.Has("console"))
762 {
763 if (conf.Get<bool>("no-dim"))
764 return RunShell<LocalStream, StateMachine, ConnectionGCN>(conf);
765 else
766 return RunShell<LocalStream, StateMachineDim, ConnectionDimGCN>(conf);
767 }
768 // Cosole access w/ and w/o Dim
769 if (conf.Get<bool>("no-dim"))
770 {
771 if (conf.Get<int>("console")==0)
772 return RunShell<LocalShell, StateMachine, ConnectionGCN>(conf);
773 else
774 return RunShell<LocalConsole, StateMachine, ConnectionGCN>(conf);
775 }
776 else
777 {
778 if (conf.Get<int>("console")==0)
779 return RunShell<LocalShell, StateMachineDim, ConnectionDimGCN>(conf);
780 else
781 return RunShell<LocalConsole, StateMachineDim, ConnectionDimGCN>(conf);
782 }
783 }
784 /*catch (std::exception& e)
785 {
786 cerr << "Exception: " << e.what() << endl;
787 return -1;
788 }*/
789
790 return 0;
791}
Note: See TracBrowser for help on using the repository browser.