source: trunk/FACT++/src/mcp.cc@ 11439

Last change on this file since 11439 was 11384, checked in by tbretz, 13 years ago
File size: 17.0 KB
Line 
1#include <boost/bind.hpp>
2#include <boost/array.hpp>
3#include <boost/asio/error.hpp>
4#include <boost/asio/deadline_timer.hpp>
5
6#include "Dim.h"
7#include "Event.h"
8#include "Shell.h"
9#include "StateMachineDim.h"
10#include "Connection.h"
11#include "Configuration.h"
12#include "Console.h"
13#include "Converter.h"
14#include "DimServiceInfoList.h"
15
16#include "tools.h"
17
18#include "LocalControl.h"
19
20#include "HeadersFTM.h"
21#include "HeadersFAD.h"
22
23
24namespace ba = boost::asio;
25namespace bs = boost::system;
26namespace dummy = ba::placeholders;
27
28using namespace std;
29
30// ------------------------------------------------------------------------
31
32#include "DimDescriptionService.h"
33
34// ------------------------------------------------------------------------
35
36class StateMachineMCP : public StateMachineDim, public DimInfoHandler
37{
38 /*
39 int Wrap(boost::function<void()> f)
40 {
41 f();
42 return T::GetCurrentState();
43 }
44
45 boost::function<int(const EventImp &)> Wrapper(boost::function<void()> func)
46 {
47 return boost::bind(&StateMachineMCP::Wrap, this, func);
48 }*/
49
50private:
51 enum states_t
52 {
53 kStateDimNetworkNA = 1,
54 kStateDisconnected,
55 kStateConnecting,
56 kStateConnected,
57 kStateIdle,
58 kStateReadyForDataTaking,
59 kStateConfiguring1,
60 kStateConfiguring2,
61 kStateConfiguring3,
62 kStateConfigured,
63 };
64
65 DimServiceInfoList fNetwork;
66
67 pair<Time, int> fStatusDim;
68 pair<Time, int> fStatusFTM;
69 pair<Time, int> fStatusFAD;
70 pair<Time, int> fStatusLog;
71
72 DimStampedInfo fDim;
73 DimStampedInfo fFTM;
74 DimStampedInfo fFAD;
75 DimStampedInfo fLog;
76
77 pair<Time, int> GetNewState(DimStampedInfo &info) const
78 {
79 const bool disconnected = info.getSize()==0;
80
81 // Make sure getTimestamp is called _before_ getTimestampMillisecs
82 const int tsec = info.getTimestamp();
83 const int tms = info.getTimestampMillisecs();
84
85 return make_pair(Time(tsec, tms*1000),
86 disconnected ? -2 : info.getQuality());
87 }
88
89 void infoHandler()
90 {
91 DimInfo *curr = getInfo(); // get current DimInfo address
92 if (!curr)
93 return;
94
95 if (curr==&fFTM)
96 {
97 fStatusFTM = GetNewState(fFTM);
98 return;
99 }
100
101 if (curr==&fFAD)
102 {
103 fStatusFAD = GetNewState(fFAD);
104 return;
105 }
106
107 if (curr==&fLog)
108 {
109 fStatusLog = GetNewState(fLog);
110 return;
111 }
112
113 if (curr==&fDim)
114 {
115 fStatusDim = GetNewState(fDim);
116 fStatusDim.second = curr->getSize()==4 ? curr->getInt() : 0;
117 return;
118 }
119
120 }
121
122 bool CheckEventSize(size_t has, const char *name, size_t size)
123 {
124 if (has==size)
125 return true;
126
127 ostringstream msg;
128 msg << name << " - Received event has " << has << " bytes, but expected " << size << ".";
129 Fatal(msg);
130 return false;
131 }
132
133 int SetVerbosity(const EventImp &evt)
134 {
135 /*
136 if (!CheckEventSize(evt.GetSize(), "SetVerbosity", 1))
137 return T::kSM_FatalError;
138
139 fFSC.SetVerbose(evt.GetBool());
140
141 */
142
143 return GetCurrentState();
144 }
145
146
147 void PrintState(const pair<Time,int> &state, const char *server)
148 {
149 const State rc = fNetwork.GetState(server, state.second);
150
151 Out() << state.first.GetAsStr("%H:%M:%S.%f").substr(0, 12) << " - ";
152 Out() << kBold << server << ": ";
153 Out() << rc.name << "[" << rc.index << "]";
154 Out() << kReset << " - " << kBlue << rc.comment << endl;
155 }
156
157 int Print()
158 {
159 Out() << fStatusDim.first.GetAsStr("%H:%M:%S.%f").substr(0, 12) << " - ";
160 Out() << kBold << "DIM_DNS: ";
161 if (fStatusDim.second==0)
162 Out() << "Offline" << endl;
163 else
164 Out() << "V" << fStatusDim.second/100 << 'r' << fStatusDim.second%100 << endl;
165
166 PrintState(fStatusFTM, "FTM_CONTROL");
167 PrintState(fStatusFAD, "FAD_CONTROL");
168 PrintState(fStatusLog, "DATA_LOGGER");
169
170 return GetCurrentState();
171 }
172
173 int GetReady()
174 {
175
176 return GetCurrentState();
177 }
178
179 int StopRun(const EventImp &evt)
180 {
181 return GetCurrentState();
182 }
183
184 int Reset(const EventImp &evt)
185 {
186 return kStateIdle;
187 /*
188 // FIMXE: Handle error states!
189 if (fStatusLog.second>=20)//kSM_NightlyOpen
190 Dim::SendCommand("DATA_LOGGER/STOP");
191
192 if (fStatusLog.second==0)
193 Dim::SendCommand("DATA_LOGGER/WAIT_FOR_RUN_NUMBER");
194
195 if (fStatusFAD.second==FAD::kConnected)
196 {
197 Dim::SendCommand("FAD_CONTROL/ENABLE_TRIGGER_LINE", bool(false));
198 Dim::SendCommand("FAD_CONTROL/ENABLE_CONTINOUS_TRIGGER", bool(false));
199 }
200
201 if (fStatusFTM.second==FTM::kTakingData)
202 Dim::SendCommand("FTM_CONTROL/STOP");
203
204 return GetCurrentState(); */
205 }
206
207 int StartRun(const EventImp &evt)
208 {
209 return kStateConfiguring1;
210 }
211
212 int Execute()
213 {
214 // Dispatch (execute) at most one handler from the queue. In contrary
215 // to run_one(), it doesn't wait until a handler is available
216 // which can be dispatched, so poll_one() might return with 0
217 // handlers dispatched. The handlers are always dispatched/executed
218 // synchronously, i.e. within the call to poll_one()
219 //poll_one();
220
221 if (fStatusDim.second==0)
222 return kStateDimNetworkNA;
223
224 if (fStatusFTM.second >= FTM::kConnected &&
225 fStatusFAD.second >= FAD::kConnected &&
226 fStatusLog.second >= kSM_Ready)
227 {
228 if (GetCurrentState()==kStateConfiguring1)
229 {
230 if (fStatusLog.second!=30/*kSM_WaitForRun*/)
231 Dim::SendCommand("DATA_LOGGER/WAIT_FOR_RUN_NUMBER");
232 Dim::SendCommand("FTM_CONTROL/CONFIGURE", "data");
233 return kStateConfiguring2;
234 }
235
236 if (GetCurrentState()==kStateConfiguring2)
237 {
238 if ((fStatusFTM.second != FTM::kConfiguring2 &&
239 fStatusFTM.second != FTM::kConfigured) ||
240 fStatusLog.second != 30/*kSM_WaitForRun*/)
241 return GetCurrentState();
242
243 Dim::SendCommand("FAD_CONTROL/CONFIGURE", "data");
244 return kStateConfiguring3;
245 }
246
247 if (GetCurrentState()==kStateConfiguring3)
248 {
249 if (fStatusFTM.second != FTM::kConfigured ||
250 fStatusFAD.second != FAD::kConfigured)
251 return GetCurrentState();
252
253 Message("START DATA TAKING");
254 Fatal("Distribute run-number to start datalogger!");
255 Fatal("fadctrl should go out of Configured after first event received!");
256 Fatal("Must configure if FTM should be started or not?");
257 Dim::SendCommand("FTM_CONTROL/START_RUN");
258 return kStateConfigured;
259 }
260
261 if (GetCurrentState()==kStateConfigured)
262 return GetCurrentState();
263
264 return kStateIdle;
265 }
266
267 /*
268 if (fStatusFTM.second >= FTM::kConnected &&
269 fStatusFAD.second >= FAD::kConnected &&
270 fStatusLog.second >= kSM_Ready)
271 return kStateIdle;
272 */
273 if (fStatusFTM.second >-2 &&
274 fStatusFAD.second >-2 &&
275 fStatusLog.second >-2)
276 return kStateConnected;
277
278 if (fStatusFTM.second >-2 ||
279 fStatusFAD.second >-2 ||
280 fStatusLog.second >-2)
281 return kStateConnecting;
282
283 return kStateDisconnected;
284 }
285
286public:
287 StateMachineMCP(ostream &out=cout) : StateMachineDim(out, "MCP"),
288 fStatusDim(make_pair(Time(), -2)),
289 fStatusFTM(make_pair(Time(), -2)),
290 fStatusFAD(make_pair(Time(), -2)),
291 fStatusLog(make_pair(Time(), -2)),
292 fDim("DIS_DNS/VERSION_NUMBER", (void*)NULL, 0, this),
293 fFTM("FTM_CONTROL/STATE", (void*)NULL, 0, this),
294 fFAD("FAD_CONTROL/STATE", (void*)NULL, 0, this),
295 fLog("DATA_LOGGER/STATE", (void*)NULL, 0, this)
296 {
297 // ba::io_service::work is a kind of keep_alive for the loop.
298 // It prevents the io_service to go to stopped state, which
299 // would prevent any consecutive calls to run()
300 // or poll() to do nothing. reset() could also revoke to the
301 // previous state but this might introduce some overhead of
302 // deletion and creation of threads and more.
303
304 // State names
305 AddStateName(kStateDimNetworkNA, "DimNetworkNotAvailable",
306 ".");
307
308 AddStateName(kStateDisconnected, "Disconnected",
309 ".");
310
311 AddStateName(kStateConnecting, "Connecting",
312 ".");
313
314 AddStateName(kStateConnected, "Connected",
315 ".");
316
317 AddStateName(kStateIdle, "Idle",
318 ".");
319
320 AddStateName(kStateReadyForDataTaking, "ReadyForDataTaking",
321 ".");
322
323 AddStateName(kStateConfiguring1, "Configuring1",
324 ".");
325
326 AddStateName(kStateConfiguring2, "Configuring2",
327 ".");
328
329 AddStateName(kStateConfiguring3, "Configuring3",
330 ".");
331
332 AddStateName(kStateConfigured, "Configured",
333 ".");
334
335
336 AddEvent("START", kStateIdle)
337 (boost::bind(&StateMachineMCP::StartRun, this, _1))
338 ("");
339
340 AddEvent("STOP")
341 (boost::bind(&StateMachineMCP::StopRun, this, _1))
342 ("");
343
344 AddEvent("RESET", kStateConfiguring1, kStateConfiguring2, kStateConfigured)
345 (boost::bind(&StateMachineMCP::Reset, this, _1))
346 ("");
347
348 // Verbosity commands
349 AddEvent("SET_VERBOSE", "B:1")
350 (boost::bind(&StateMachineMCP::SetVerbosity, this, _1))
351 ("set verbosity state"
352 "|verbosity[bool]:disable or enable verbosity for received data (yes/no), except dynamic data");
353
354 AddEvent("PRINT")
355 (boost::bind(&StateMachineMCP::Print, this))
356 ("");
357 }
358
359 int EvalConfiguration(const Configuration &conf)
360 {
361 //SetEndpoint(conf.Get<string>("addr"));
362
363 //fFSC.SetVerbose(!conf.Get<bool>("quiet"));
364
365 return -1;
366 }
367};
368
369// ------------------------------------------------------------------------
370
371#include "Main.h"
372
373/*
374void RunThread(StateMachineImp *io_service)
375{
376 // This is necessary so that the StateMachien Thread can signal the
377 // Readline to exit
378 io_service->Run();
379 Readline::Stop();
380}
381*/
382/*
383template<class S, class T>
384int RunDim(Configuration &conf)
385{
386 WindowLog wout;
387
388 ReadlineColor::PrintBootMsg(wout, conf.GetName(), false);
389
390
391 if (conf.Has("log"))
392 if (!wout.OpenLogFile(conf.Get<string>("log")))
393 wout << kRed << "ERROR - Couldn't open log-file " << conf.Get<string>("log") << ": " << strerror(errno) << endl;
394
395 // Start io_service.Run to use the StateMachineImp::Run() loop
396 // Start io_service.run to only use the commandHandler command detaching
397 StateMachineMCP<S, T> io_service(wout);
398 if (!io_service.EvalConfiguration(conf))
399 return -1;
400
401 io_service.Run();
402
403 return 0;
404}
405*/
406
407template<class T>
408int RunShell(const Configuration &conf)
409{
410 return Main<T, StateMachineMCP>(conf);
411/*
412 static T shell(conf.GetName().c_str(), conf.Get<int>("console")!=1);
413
414 WindowLog &win = shell.GetStreamIn();
415 WindowLog &wout = shell.GetStreamOut();
416
417 if (conf.Has("log"))
418 if (!wout.OpenLogFile(conf.Get<string>("log")))
419 win << kRed << "ERROR - Couldn't open log-file " << conf.Get<string>("log") << ": " << strerror(errno) << endl;
420
421 StateMachineMCP<S, R> io_service(wout);
422 if (!io_service.EvalConfiguration(conf))
423 return -1;
424
425 shell.SetReceiver(io_service);
426
427 boost::thread t(boost::bind(RunThread, &io_service));
428 // boost::thread t(boost::bind(&StateMachineMCP<S>::Run, &io_service));
429
430 if (conf.Has("cmd"))
431 {
432 const vector<string> v = conf.Get<vector<string>>("cmd");
433 for (vector<string>::const_iterator it=v.begin(); it!=v.end(); it++)
434 shell.ProcessLine(*it);
435 }
436
437 if (conf.Has("exec"))
438 {
439 const vector<string> v = conf.Get<vector<string>>("exec");
440 for (vector<string>::const_iterator it=v.begin(); it!=v.end(); it++)
441 shell.Execute(*it);
442 }
443
444 if (conf.Get<bool>("quit"))
445 shell.Stop();
446
447 shell.Run(); // Run the shell
448 io_service.Stop(); // Signal Loop-thread to stop
449 // io_service.Close(); // Obsolete, done by the destructor
450
451 // Wait until the StateMachine has finished its thread
452 // before returning and destroying the dim objects which might
453 // still be in use.
454 t.join();
455
456 return 0;
457*/
458}
459
460void SetupConfiguration(Configuration &conf)
461{
462 const string n = conf.GetName()+".log";
463
464 po::options_description config("Program options");
465 config.add_options()
466 ("dns", var<string>("localhost"), "Dim nameserver host name (Overwites DIM_DNS_NODE environment variable)")
467 ("log,l", var<string>(n), "Write log-file")
468// ("no-dim,d", po_bool(), "Disable dim services")
469 ("console,c", var<int>(), "Use console (0=shell, 1=simple buffered, X=simple unbuffered)")
470 ("cmd", vars<string>(), "Execute one or more commands at startup")
471 ("exec,e", vars<string>(), "Execute one or more scrips at startup")
472 ("quit,q", po_switch(), "Quit after startup");
473 ;
474/*
475 po::options_description control("FTM control options");
476 control.add_options()
477 ("addr,a", var<string>("localhost:5000"), "Network address of FTM")
478 ("quiet,q", po_bool(), "Disable printing contents of all received messages (except dynamic data) in clear text.")
479 ;
480*/
481 conf.AddEnv("dns", "DIM_DNS_NODE");
482
483 conf.AddOptions(config);
484// conf.AddOptions(control);
485}
486
487/*
488 Extract usage clause(s) [if any] for SYNOPSIS.
489 Translators: "Usage" and "or" here are patterns (regular expressions) which
490 are used to match the usage synopsis in program output. An example from cp
491 (GNU coreutils) which contains both strings:
492 Usage: cp [OPTION]... [-T] SOURCE DEST
493 or: cp [OPTION]... SOURCE... DIRECTORY
494 or: cp [OPTION]... -t DIRECTORY SOURCE...
495 */
496void PrintUsage()
497{
498 cout <<
499 "The ftmctrl controls the FSC (FACT Slow Control) board.\n"
500 "\n"
501 "The default is that the program is started without user intercation. "
502 "All actions are supposed to arrive as DimCommands. Using the -c "
503 "option, a local shell can be initialized. With h or help a short "
504 "help message about the usuage can be brought to the screen.\n"
505 "\n"
506 "Usage: fscctrl [-c type] [OPTIONS]\n"
507 " or: fscctrl [OPTIONS]\n";
508 cout << endl;
509}
510
511void PrintHelp()
512{
513 /* Additional help text which is printed after the configuration
514 options goes here */
515
516 /*
517 cout << "bla bla bla" << endl << endl;
518 cout << endl;
519 cout << "Environment:" << endl;
520 cout << "environment" << endl;
521 cout << endl;
522 cout << "Examples:" << endl;
523 cout << "test exam" << endl;
524 cout << endl;
525 cout << "Files:" << endl;
526 cout << "files" << endl;
527 cout << endl;
528 */
529}
530
531int main(int argc, const char* argv[])
532{
533 Configuration conf(argv[0]);
534 conf.SetPrintUsage(PrintUsage);
535 SetupConfiguration(conf);
536
537 po::variables_map vm;
538 try
539 {
540 vm = conf.Parse(argc, argv);
541 }
542#if BOOST_VERSION > 104000
543 catch (po::multiple_occurrences &e)
544 {
545 cerr << "Program options invalid due to: " << e.what() << " of '" << e.get_option_name() << "'." << endl;
546 return -1;
547 }
548#endif
549 catch (exception& e)
550 {
551 cerr << "Program options invalid due to: " << e.what() << endl;
552 return -1;
553 }
554
555 if (conf.HasVersion() || conf.HasPrint())
556 return -1;
557
558 if (conf.HasHelp())
559 {
560 PrintHelp();
561 return -1;
562 }
563
564 Dim::Setup(conf.Get<string>("dns"));
565
566 //try
567 {
568 // No console access at all
569 if (!conf.Has("console"))
570 {
571// if (conf.Get<bool>("no-dim"))
572// return RunShell<LocalStream, StateMachine, ConnectionFSC>(conf);
573// else
574 return RunShell<LocalStream>(conf);
575 }
576 // Cosole access w/ and w/o Dim
577/* if (conf.Get<bool>("no-dim"))
578 {
579 if (conf.Get<int>("console")==0)
580 return RunShell<LocalShell, StateMachine, ConnectionFSC>(conf);
581 else
582 return RunShell<LocalConsole, StateMachine, ConnectionFSC>(conf);
583 }
584 else
585*/ {
586 if (conf.Get<int>("console")==0)
587 return RunShell<LocalShell>(conf);
588 else
589 return RunShell<LocalConsole>(conf);
590 }
591 }
592 /*catch (std::exception& e)
593 {
594 cerr << "Exception: " << e.what() << endl;
595 return -1;
596 }*/
597
598 return 0;
599}
Note: See TracBrowser for help on using the repository browser.