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

Last change on this file since 13717 was 13712, checked in by tbretz, 13 years ago
Added more command descriptions.
File size: 18.8 KB
Line 
1#include "Dim.h"
2#include "Event.h"
3#include "Shell.h"
4#include "StateMachineDim.h"
5#include "Connection.h"
6#include "Configuration.h"
7#include "Console.h"
8#include "Converter.h"
9#include "DimServiceInfoList.h"
10
11#include "tools.h"
12
13#include "LocalControl.h"
14
15#include "HeadersFTM.h"
16#include "HeadersFAD.h"
17
18
19namespace ba = boost::asio;
20namespace bs = boost::system;
21namespace dummy = ba::placeholders;
22
23using namespace std;
24
25// ------------------------------------------------------------------------
26
27#include "DimDescriptionService.h"
28
29// ------------------------------------------------------------------------
30
31class StateMachineMCP : public StateMachineDim, public DimInfoHandler
32{
33 /*
34 int Wrap(boost::function<void()> f)
35 {
36 f();
37 return T::GetCurrentState();
38 }
39
40 boost::function<int(const EventImp &)> Wrapper(boost::function<void()> func)
41 {
42 return bind(&StateMachineMCP::Wrap, this, func);
43 }*/
44
45private:
46 enum states_t
47 {
48 kStateDimNetworkNA = 1,
49 kStateDisconnected,
50 kStateConnecting,
51 kStateConnected,
52 kStateIdle,
53 kStateDumm, // Doesn't exist, kept to keep the numbers
54 kStateConfiguring1,
55 kStateConfiguring2,
56 kStateConfiguring3,
57 kStateConfigured,
58 kStateTriggerOn,
59 kStateTakingData,
60// kStateRunInProgress,
61 };
62
63 DimServiceInfoList fNetwork;
64
65 pair<Time, int> fStatusDim;
66 pair<Time, int> fStatusFTM;
67 pair<Time, int> fStatusFAD;
68 pair<Time, int> fStatusLog;
69 pair<Time, int> fStatusRC;
70
71 DimStampedInfo fDim;
72 DimStampedInfo fFTM;
73 DimStampedInfo fFAD;
74 DimStampedInfo fLog;
75 DimStampedInfo fRC;
76
77 DimDescribedService fService;
78
79 pair<Time, int> GetNewState(DimStampedInfo &info) const
80 {
81 const bool disconnected = info.getSize()==0;
82
83 // Make sure getTimestamp is called _before_ getTimestampMillisecs
84 const int tsec = info.getTimestamp();
85 const int tms = info.getTimestampMillisecs();
86
87 return make_pair(Time(tsec, tms*1000),
88 disconnected ? -2 : info.getQuality());
89 }
90
91 void infoHandler()
92 {
93 DimInfo *curr = getInfo(); // get current DimInfo address
94 if (!curr)
95 return;
96
97 if (curr==&fFTM)
98 {
99 fStatusFTM = GetNewState(fFTM);
100 return;
101 }
102
103 if (curr==&fFAD)
104 {
105 fStatusFAD = GetNewState(fFAD);
106 return;
107 }
108
109 if (curr==&fLog)
110 {
111 fStatusLog = GetNewState(fLog);
112 return;
113 }
114
115 if (curr==&fRC)
116 {
117 fStatusRC = GetNewState(fRC);
118 return;
119 }
120
121 if (curr==&fDim)
122 {
123 fStatusDim = GetNewState(fDim);
124 fStatusDim.second = curr->getSize()==4 ? curr->getInt() : 0;
125 return;
126 }
127 }
128
129 bool CheckEventSize(size_t has, const char *name, size_t size)
130 {
131 if (has==size)
132 return true;
133
134 ostringstream msg;
135 msg << name << " - Received event has " << has << " bytes, but expected " << size << ".";
136 Fatal(msg);
137 return false;
138 }
139
140 int SetVerbosity(const EventImp &)
141 {
142 /*
143 if (!CheckEventSize(evt.GetSize(), "SetVerbosity", 1))
144 return T::kSM_FatalError;
145
146 fFSC.SetVerbose(evt.GetBool());
147
148 */
149
150 return GetCurrentState();
151 }
152
153
154 void PrintState(const pair<Time,int> &state, const char *server)
155 {
156 const State rc = fNetwork.GetState(server, state.second);
157
158 Out() << state.first.GetAsStr("%H:%M:%S.%f").substr(0, 12) << " - ";
159 Out() << kBold << server << ": ";
160 Out() << rc.name << "[" << rc.index << "]";
161 Out() << kReset << " - " << kBlue << rc.comment << endl;
162 }
163
164 int Print()
165 {
166 Out() << fStatusDim.first.GetAsStr("%H:%M:%S.%f").substr(0, 12) << " - ";
167 Out() << kBold << "DIM_DNS: ";
168 if (fStatusDim.second==0)
169 Out() << "Offline" << endl;
170 else
171 Out() << "V" << fStatusDim.second/100 << 'r' << fStatusDim.second%100 << endl;
172
173 PrintState(fStatusFTM, "FTM_CONTROL");
174 PrintState(fStatusFAD, "FAD_CONTROL");
175 PrintState(fStatusLog, "DATA_LOGGER");
176 PrintState(fStatusRC, "RATE_CONTROL");
177
178 return GetCurrentState();
179 }
180
181 int GetReady()
182 {
183 return GetCurrentState();
184 }
185
186 int StopRun(const EventImp &)
187 {
188 if (fStatusFTM.second==FTM::kTriggerOn)
189 {
190 Message("Stopping FTM");
191 Dim::SendCommand("FTM_CONTROL/STOP_TRIGGER");
192 }
193
194 // FIXME: Do step 2 only when FTM is stopped
195 if (fStatusFAD.second==FAD::kConnected)
196 {
197 //Dim::SendCommand("FAD_CONTROL/ENABLE_TRIGGER_LINE", bool(false));
198 Message("Stopping FAD");
199 Dim::SendCommand("FAD_CONTROL/ENABLE_CONTINOUS_TRIGGER", bool(false));
200 }
201
202 return GetCurrentState();
203 }
204
205 int Reset(const EventImp &)
206 {
207 fRunType = "";
208 Message("Reseting configuration states of FAD and FTM");
209 Dim::SendCommand("FTM_CONTROL/RESET_CONFIGURE");
210 Dim::SendCommand("FAD_CONTROL/RESET_CONFIGURE");
211 return kStateIdle;
212 /*
213 // FIMXE: Handle error states!
214 if (fStatusLog.second>=20)//kSM_NightlyOpen
215 Dim::SendCommand("DATA_LOGGER/STOP");
216
217 if (fStatusLog.second==0)
218 Dim::SendCommand("DATA_LOGGER/WAIT_FOR_RUN_NUMBER");
219
220 if (fStatusFAD.second==FAD::kConnected)
221 {
222 Dim::SendCommand("FAD_CONTROL/ENABLE_TRIGGER_LINE", bool(false));
223 Dim::SendCommand("FAD_CONTROL/ENABLE_CONTINOUS_TRIGGER", bool(false));
224 }
225
226 if (fStatusFTM.second==FTM::kTakingData)
227 Dim::SendCommand("FTM_CONTROL/STOP");
228
229 return GetCurrentState(); */
230 }
231
232 int64_t fMaxTime;
233 int64_t fNumEvents;
234 string fRunType;
235
236 int StartRun(const EventImp &evt)
237 {
238 if (fStatusFTM.second==-2)
239 {
240 Error("No connection to ftmcontrol (see PRINT).");
241 return GetCurrentState();
242 }
243 if (fStatusFAD.second==-2)
244 {
245 Warn("No connection to fadcontrol (see PRINT).");
246 return GetCurrentState();
247 }
248 if (fStatusLog.second==-2)
249 {
250 Warn("No connection to datalogger (see PRINT).");
251 return GetCurrentState();
252 }
253 if (fStatusRC.second==-2)
254 {
255 Warn("No connection to ratecontrol (see PRINT).");
256 return GetCurrentState();
257 }
258
259 fMaxTime = evt.Get<int64_t>();
260 fNumEvents = evt.Get<int64_t>(8);
261 fRunType = evt.Ptr<char>(16);
262
263 ostringstream str;
264 str << "Starting configuration '" << fRunType << "' for new run";
265 if (fNumEvents>0 || fMaxTime>0)
266 str << " [";
267 if (fNumEvents>0)
268 str << fNumEvents << " events";
269 if (fNumEvents>0 && fMaxTime>0)
270 str << " / ";
271 if (fMaxTime>0)
272 str << fMaxTime << "s";
273 if (fNumEvents>0 || fMaxTime>0)
274 str << "]";
275 Message(str);
276
277 Update(kStateConfiguring1);
278
279 return kStateConfiguring1;
280 }
281
282 struct Value
283 {
284 uint64_t time;
285 uint64_t nevts;
286 char type[];
287 };
288
289 Value *GetBuffer()
290 {
291 const size_t len = sizeof(Value)+fRunType.length()+1;
292
293 char *buf = new char[len];
294
295 Value *val = reinterpret_cast<Value*>(buf);
296
297 val->time = fMaxTime;
298 val->nevts = fNumEvents;
299
300 strcpy(val->type, fRunType.c_str());
301
302 return val;
303 }
304
305 void Update(int newstate)
306 {
307 Value *buf = GetBuffer();
308 fService.setQuality(newstate);
309 fService.setData(buf, sizeof(Value)+fRunType.length()+1);
310 fService.Update();
311 delete buf;
312 }
313
314 void ConfigureFAD()
315 {
316 Value *buf = GetBuffer();
317
318 Message("Configuring FAD");
319 Dim::SendCommand("FAD_CONTROL/CONFIGURE", buf, sizeof(Value)+fRunType.length()+1);
320
321 delete buf;
322 }
323
324 int Execute()
325 {
326 // Dispatch (execute) at most one handler from the queue. In contrary
327 // to run_one(), it doesn't wait until a handler is available
328 // which can be dispatched, so poll_one() might return with 0
329 // handlers dispatched. The handlers are always dispatched/executed
330 // synchronously, i.e. within the call to poll_one()
331 //poll_one();
332
333 if (fStatusDim.second==0)
334 return kStateDimNetworkNA;
335
336 if (fStatusFTM.second >= FTM::kConnected &&
337 fStatusFAD.second >= FAD::kConnected &&
338 fStatusLog.second >= kSM_Ready)
339 {
340 if (GetCurrentState()==kStateConfiguring1)
341 {
342 if (fStatusLog.second<30/*kSM_WaitForRun*/)
343 {
344 Message("Starting datalogger");
345 Dim::SendCommand("DATA_LOGGER/START_RUN_LOGGING");
346 }
347 Message("Configuring Trigger (FTM)");
348 Dim::SendCommand("FTM_CONTROL/CONFIGURE", fRunType);
349 Update(kStateConfiguring2);
350 return kStateConfiguring2;
351 }
352
353 if (GetCurrentState()==kStateConfiguring2)
354 {
355 // FIMXE: Reset in case of error
356 if ((/*fStatusFTM.second != FTM::kConfiguring2 &&*/
357 fStatusFTM.second != FTM::kConfigured) ||
358 fStatusLog.second<30 || fStatusLog.second>0xff)
359 return GetCurrentState();
360
361 // FIMXE: This is to make sure that the rate control
362 // has received the correct trigger setup already...
363 //usleep(1000000);
364
365 Message("Starting Rate Control");
366 Dim::SendCommand("RATE_CONTROL/CALIBRATE");
367
368 ConfigureFAD();
369 Update(kStateConfiguring3);
370 return kStateConfiguring3;
371 }
372
373 if (GetCurrentState()==kStateConfiguring3)
374 {
375 if (fStatusFTM.second != FTM::kConfigured ||
376 fStatusFAD.second != FAD::kConfigured ||
377 fStatusRC.second < 6)
378 return GetCurrentState();
379
380 Message("Starting Trigger (FTM)");
381 Dim::SendCommand("FTM_CONTROL/START_TRIGGER");
382 Update(kStateConfigured);
383 return kStateConfigured;
384 }
385
386 if (GetCurrentState()==kStateConfigured)
387 {
388 if (fStatusFTM.second != FTM::kTriggerOn)
389 return GetCurrentState();
390
391 Update(kStateTriggerOn);
392
393 return kStateTriggerOn;
394 }
395
396 if (GetCurrentState()==kStateTriggerOn)
397 {
398 if (fStatusFAD.second != FAD::kWritingData)
399 return GetCurrentState();
400
401 Update(kStateTakingData);
402
403 return kStateTakingData;
404 }
405
406 if (GetCurrentState()==kStateTakingData)
407 {
408 if (fStatusFTM.second==FTM::kTriggerOn &&
409 fStatusFAD.second==FAD::kWritingData)
410 return kStateTakingData;
411
412 Update(kStateIdle);
413 }
414
415 return kStateIdle;
416 }
417
418 /*
419 if (fStatusFTM.second >= FTM::kConnected &&
420 fStatusFAD.second >= FAD::kConnected &&
421 fStatusLog.second >= kSM_Ready)
422 return kStateIdle;
423 */
424 if (fStatusFTM.second >-2 &&
425 fStatusFAD.second >-2 &&
426 fStatusLog.second >-2 &&
427 fStatusRC.second >-2)
428 return kStateConnected;
429
430 if (fStatusFTM.second >-2 ||
431 fStatusFAD.second >-2 ||
432 fStatusLog.second >-2 ||
433 fStatusRC.second >-2)
434 return kStateConnecting;
435
436 return kStateDisconnected;
437 }
438
439public:
440 StateMachineMCP(ostream &out=cout) : StateMachineDim(out, "MCP"),
441 fStatusDim(make_pair(Time(), -2)),
442 fStatusFTM(make_pair(Time(), -2)),
443 fStatusFAD(make_pair(Time(), -2)),
444 fStatusLog(make_pair(Time(), -2)),
445 fDim("DIS_DNS/VERSION_NUMBER", (void*)NULL, 0, this),
446 fFTM("FTM_CONTROL/STATE", (void*)NULL, 0, this),
447 fFAD("FAD_CONTROL/STATE", (void*)NULL, 0, this),
448 fLog("DATA_LOGGER/STATE", (void*)NULL, 0, this),
449 fRC("RATE_CONTROL/STATE", (void*)NULL, 0, this),
450 fService("MCP/CONFIGURATION", "X:1;X:1;C", "Run configuration information"
451 "|MaxTime[s]:Maximum time before the run gets stopped"
452 "|MaxEvents[num]:Maximum number of events before the run gets stopped"
453 "|Name[text]:Name of the chosen configuration")
454 {
455 // ba::io_service::work is a kind of keep_alive for the loop.
456 // It prevents the io_service to go to stopped state, which
457 // would prevent any consecutive calls to run()
458 // or poll() to do nothing. reset() could also revoke to the
459 // previous state but this might introduce some overhead of
460 // deletion and creation of threads and more.
461
462 // State names
463 AddStateName(kStateDimNetworkNA, "DimNetworkNotAvailable",
464 "DIM dns server not available.");
465
466 AddStateName(kStateDisconnected, "Disconnected",
467 "Neither ftmctrl, fadctrl, datalogger nor rate control online.");
468
469 AddStateName(kStateConnecting, "Connecting",
470 "Either ftmctrl, fadctrl, datalogger or rate control not online.");
471
472 AddStateName(kStateConnected, "Connected",
473 "All needed subsystems online.");
474
475 AddStateName(kStateIdle, "Idle",
476 "Waiting for next configuration command");
477
478 AddStateName(kStateConfiguring1, "Configuring1",
479 "Starting configuration procedure, checking Datalogger state");
480
481 AddStateName(kStateConfiguring2, "Configuring2",
482 "Waiting for FTM and Datalogger to get ready");
483
484 AddStateName(kStateConfiguring3, "Configuring3",
485 "Waiting for FADs and rate control to get ready");
486
487 AddStateName(kStateConfigured, "Configured",
488 "Everything is configured, trigger will be switched on now");
489
490 AddStateName(kStateTriggerOn, "TriggerOn",
491 "The trigger is switched on, waiting for FAD to receive data");
492
493 AddStateName(kStateTakingData, "TakingData",
494 "The trigger is switched on, FADs are sending data");
495
496
497 AddEvent("START", "X:2;C")//, kStateIdle)
498 (bind(&StateMachineMCP::StartRun, this, placeholders::_1))
499 ("Start the configuration and data taking for a run-type of a pre-defined setup"
500 "|TimeMax[s]:Maximum number of seconds before the run will be closed automatically"
501 "|NumMax[count]:Maximum number events before the run will be closed automatically"
502 "|Name[text]:Name of the configuration to be used for taking data");
503
504 AddEvent("STOP")
505 (bind(&StateMachineMCP::StopRun, this, placeholders::_1))
506 ("Stops the trigger (either disables the FTM trigger or the internal DRS trigger)");
507
508 AddEvent("RESET", kStateConfiguring1, kStateConfiguring2, kStateConfiguring3, kStateConfigured)
509 (bind(&StateMachineMCP::Reset, this, placeholders::_1))
510 ("If a configuration blockes because a system cannot configure itself properly, "
511 "this command can be called to leave the configuration procedure. The command "
512 "is also propagated to FTM and FAD");
513
514 // Verbosity commands
515 AddEvent("SET_VERBOSE", "B:1")
516 (bind(&StateMachineMCP::SetVerbosity, this, placeholders::_1))
517 ("set verbosity state"
518 "|verbosity[bool]:disable or enable verbosity for received data (yes/no), except dynamic data");
519
520 AddEvent("PRINT")
521 (bind(&StateMachineMCP::Print, this))
522 ("Print the states and connection status of all systems connected to the MCP.");
523 }
524
525 int EvalOptions(Configuration &)
526 {
527 //SetEndpoint(conf.Get<string>("addr"));
528
529 //fFSC.SetVerbose(!conf.Get<bool>("quiet"));
530
531 return -1;
532 }
533};
534
535// ------------------------------------------------------------------------
536
537#include "Main.h"
538
539template<class T>
540int RunShell(Configuration &conf)
541{
542 return Main::execute<T, StateMachineMCP>(conf);
543}
544
545/*
546 Extract usage clause(s) [if any] for SYNOPSIS.
547 Translators: "Usage" and "or" here are patterns (regular expressions) which
548 are used to match the usage synopsis in program output. An example from cp
549 (GNU coreutils) which contains both strings:
550 Usage: cp [OPTION]... [-T] SOURCE DEST
551 or: cp [OPTION]... SOURCE... DIRECTORY
552 or: cp [OPTION]... -t DIRECTORY SOURCE...
553 */
554void PrintUsage()
555{
556 cout <<
557 "The ftmctrl controls the FSC (FACT Slow Control) board.\n"
558 "\n"
559 "The default is that the program is started without user intercation. "
560 "All actions are supposed to arrive as DimCommands. Using the -c "
561 "option, a local shell can be initialized. With h or help a short "
562 "help message about the usuage can be brought to the screen.\n"
563 "\n"
564 "Usage: fscctrl [-c type] [OPTIONS]\n"
565 " or: fscctrl [OPTIONS]\n";
566 cout << endl;
567}
568
569void PrintHelp()
570{
571 Main::PrintHelp<StateMachineMCP>();
572
573 /* Additional help text which is printed after the configuration
574 options goes here */
575
576 /*
577 cout << "bla bla bla" << endl << endl;
578 cout << endl;
579 cout << "Environment:" << endl;
580 cout << "environment" << endl;
581 cout << endl;
582 cout << "Examples:" << endl;
583 cout << "test exam" << endl;
584 cout << endl;
585 cout << "Files:" << endl;
586 cout << "files" << endl;
587 cout << endl;
588 */
589}
590
591int main(int argc, const char* argv[])
592{
593 Configuration conf(argv[0]);
594 conf.SetPrintUsage(PrintUsage);
595 Main::SetupConfiguration(conf);
596
597 if (!conf.DoParse(argc, argv, PrintHelp))
598 return -1;
599
600 //try
601 {
602 // No console access at all
603 if (!conf.Has("console"))
604 {
605// if (conf.Get<bool>("no-dim"))
606// return RunShell<LocalStream, StateMachine, ConnectionFSC>(conf);
607// else
608 return RunShell<LocalStream>(conf);
609 }
610 // Cosole access w/ and w/o Dim
611/* if (conf.Get<bool>("no-dim"))
612 {
613 if (conf.Get<int>("console")==0)
614 return RunShell<LocalShell, StateMachine, ConnectionFSC>(conf);
615 else
616 return RunShell<LocalConsole, StateMachine, ConnectionFSC>(conf);
617 }
618 else
619*/ {
620 if (conf.Get<int>("console")==0)
621 return RunShell<LocalShell>(conf);
622 else
623 return RunShell<LocalConsole>(conf);
624 }
625 }
626 /*catch (std::exception& e)
627 {
628 cerr << "Exception: " << e.what() << endl;
629 return -1;
630 }*/
631
632 return 0;
633}
Note: See TracBrowser for help on using the repository browser.