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

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