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

Last change on this file since 13830 was 13794, checked in by tbretz, 13 years ago
Also propagate the new Idle state when resetted.
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 kStateDummy, // 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 Update(kStateIdle);
212 return kStateIdle;
213 /*
214 // FIMXE: Handle error states!
215 if (fStatusLog.second>=20)//kSM_NightlyOpen
216 Dim::SendCommand("DATA_LOGGER/STOP");
217
218 if (fStatusLog.second==0)
219 Dim::SendCommand("DATA_LOGGER/WAIT_FOR_RUN_NUMBER");
220
221 if (fStatusFAD.second==FAD::kConnected)
222 {
223 Dim::SendCommand("FAD_CONTROL/ENABLE_TRIGGER_LINE", bool(false));
224 Dim::SendCommand("FAD_CONTROL/ENABLE_CONTINOUS_TRIGGER", bool(false));
225 }
226
227 if (fStatusFTM.second==FTM::kTakingData)
228 Dim::SendCommand("FTM_CONTROL/STOP");
229
230 return GetCurrentState(); */
231 }
232
233 int64_t fMaxTime;
234 int64_t fNumEvents;
235 string fRunType;
236
237 int StartRun(const EventImp &evt)
238 {
239 if (fStatusFTM.second==-2)
240 {
241 Error("No connection to ftmcontrol (see PRINT).");
242 return GetCurrentState();
243 }
244 if (fStatusFAD.second==-2)
245 {
246 Warn("No connection to fadcontrol (see PRINT).");
247 return GetCurrentState();
248 }
249 if (fStatusLog.second==-2)
250 {
251 Warn("No connection to datalogger (see PRINT).");
252 return GetCurrentState();
253 }
254 if (fStatusRC.second==-2)
255 {
256 Warn("No connection to ratecontrol (see PRINT).");
257 return GetCurrentState();
258 }
259
260 fMaxTime = evt.Get<int64_t>();
261 fNumEvents = evt.Get<int64_t>(8);
262 fRunType = evt.Ptr<char>(16);
263
264 ostringstream str;
265 str << "Starting configuration '" << fRunType << "' for new run";
266 if (fNumEvents>0 || fMaxTime>0)
267 str << " [";
268 if (fNumEvents>0)
269 str << fNumEvents << " events";
270 if (fNumEvents>0 && fMaxTime>0)
271 str << " / ";
272 if (fMaxTime>0)
273 str << fMaxTime << "s";
274 if (fNumEvents>0 || fMaxTime>0)
275 str << "]";
276 Message(str);
277
278 Update(kStateConfiguring1);
279
280 return kStateConfiguring1;
281 }
282
283 struct Value
284 {
285 uint64_t time;
286 uint64_t nevts;
287 char type[];
288 };
289
290 Value *GetBuffer()
291 {
292 const size_t len = sizeof(Value)+fRunType.length()+1;
293
294 char *buf = new char[len];
295
296 Value *val = reinterpret_cast<Value*>(buf);
297
298 val->time = fMaxTime;
299 val->nevts = fNumEvents;
300
301 strcpy(val->type, fRunType.c_str());
302
303 return val;
304 }
305
306 void Update(int newstate)
307 {
308 Value *buf = GetBuffer();
309 fService.setQuality(newstate);
310 fService.setData(buf, sizeof(Value)+fRunType.length()+1);
311 fService.Update();
312 delete buf;
313 }
314
315 void ConfigureFAD()
316 {
317 Value *buf = GetBuffer();
318
319 Message("Configuring FAD");
320 Dim::SendCommand("FAD_CONTROL/CONFIGURE", buf, sizeof(Value)+fRunType.length()+1);
321
322 delete buf;
323 }
324
325 int Execute()
326 {
327 // Dispatch (execute) at most one handler from the queue. In contrary
328 // to run_one(), it doesn't wait until a handler is available
329 // which can be dispatched, so poll_one() might return with 0
330 // handlers dispatched. The handlers are always dispatched/executed
331 // synchronously, i.e. within the call to poll_one()
332 //poll_one();
333
334 if (fStatusDim.second==0)
335 return kStateDimNetworkNA;
336
337 if (fStatusFTM.second >= FTM::kConnected &&
338 fStatusFAD.second >= FAD::kConnected &&
339 fStatusLog.second >= kSM_Ready)
340 {
341 if (GetCurrentState()==kStateConfiguring1)
342 {
343 if (fStatusLog.second<30/*kSM_WaitForRun*/)
344 {
345 Message("Starting datalogger");
346 Dim::SendCommand("DATA_LOGGER/START_RUN_LOGGING");
347 }
348 Message("Configuring Trigger (FTM)");
349 Dim::SendCommand("FTM_CONTROL/CONFIGURE", fRunType);
350 Update(kStateConfiguring2);
351 return kStateConfiguring2;
352 }
353
354 if (GetCurrentState()==kStateConfiguring2)
355 {
356 // FIMXE: Reset in case of error
357 if ((/*fStatusFTM.second != FTM::kConfiguring2 &&*/
358 fStatusFTM.second != FTM::kConfigured) ||
359 fStatusLog.second<30 || fStatusLog.second>0xff)
360 return GetCurrentState();
361
362 // FIMXE: This is to make sure that the rate control
363 // has received the correct trigger setup already...
364 //usleep(1000000);
365
366 Message("Starting Rate Control");
367 Dim::SendCommand("RATE_CONTROL/CALIBRATE");
368
369 ConfigureFAD();
370 Update(kStateConfiguring3);
371 return kStateConfiguring3;
372 }
373
374 if (GetCurrentState()==kStateConfiguring3)
375 {
376 if (fStatusFTM.second != FTM::kConfigured ||
377 fStatusFAD.second != FAD::kConfigured ||
378 fStatusRC.second < 6)
379 return GetCurrentState();
380
381 Message("Starting Trigger (FTM)");
382 Dim::SendCommand("FTM_CONTROL/START_TRIGGER");
383 Update(kStateConfigured);
384 return kStateConfigured;
385 }
386
387 if (GetCurrentState()==kStateConfigured)
388 {
389 if (fStatusFTM.second != FTM::kTriggerOn)
390 return GetCurrentState();
391
392 Update(kStateTriggerOn);
393
394 return kStateTriggerOn;
395 }
396
397 if (GetCurrentState()==kStateTriggerOn)
398 {
399 if (fStatusFAD.second != FAD::kWritingData)
400 return GetCurrentState();
401
402 Update(kStateTakingData);
403
404 return kStateTakingData;
405 }
406
407 if (GetCurrentState()==kStateTakingData)
408 {
409 if (fStatusFTM.second==FTM::kTriggerOn &&
410 fStatusFAD.second==FAD::kWritingData)
411 return kStateTakingData;
412
413 Update(kStateIdle);
414 }
415
416 return kStateIdle;
417 }
418
419 /*
420 if (fStatusFTM.second >= FTM::kConnected &&
421 fStatusFAD.second >= FAD::kConnected &&
422 fStatusLog.second >= kSM_Ready)
423 return kStateIdle;
424 */
425 if (fStatusFTM.second >-2 &&
426 fStatusFAD.second >-2 &&
427 fStatusLog.second >-2 &&
428 fStatusRC.second >-2)
429 return kStateConnected;
430
431 if (fStatusFTM.second >-2 ||
432 fStatusFAD.second >-2 ||
433 fStatusLog.second >-2 ||
434 fStatusRC.second >-2)
435 return kStateConnecting;
436
437 return kStateDisconnected;
438 }
439
440public:
441 StateMachineMCP(ostream &out=cout) : StateMachineDim(out, "MCP"),
442 fStatusDim(make_pair(Time(), -2)),
443 fStatusFTM(make_pair(Time(), -2)),
444 fStatusFAD(make_pair(Time(), -2)),
445 fStatusLog(make_pair(Time(), -2)),
446 fDim("DIS_DNS/VERSION_NUMBER", (void*)NULL, 0, this),
447 fFTM("FTM_CONTROL/STATE", (void*)NULL, 0, this),
448 fFAD("FAD_CONTROL/STATE", (void*)NULL, 0, this),
449 fLog("DATA_LOGGER/STATE", (void*)NULL, 0, this),
450 fRC("RATE_CONTROL/STATE", (void*)NULL, 0, this),
451 fService("MCP/CONFIGURATION", "X:1;X:1;C", "Run configuration information"
452 "|MaxTime[s]:Maximum time before the run gets stopped"
453 "|MaxEvents[num]:Maximum number of events before the run gets stopped"
454 "|Name[text]:Name of the chosen configuration")
455 {
456 // ba::io_service::work is a kind of keep_alive for the loop.
457 // It prevents the io_service to go to stopped state, which
458 // would prevent any consecutive calls to run()
459 // or poll() to do nothing. reset() could also revoke to the
460 // previous state but this might introduce some overhead of
461 // deletion and creation of threads and more.
462
463 // State names
464 AddStateName(kStateDimNetworkNA, "DimNetworkNotAvailable",
465 "DIM dns server not available.");
466
467 AddStateName(kStateDisconnected, "Disconnected",
468 "Neither ftmctrl, fadctrl, datalogger nor rate control online.");
469
470 AddStateName(kStateConnecting, "Connecting",
471 "Either ftmctrl, fadctrl, datalogger or rate control not online.");
472
473 AddStateName(kStateConnected, "Connected",
474 "All needed subsystems online.");
475
476 AddStateName(kStateIdle, "Idle",
477 "Waiting for next configuration command");
478
479 AddStateName(kStateConfiguring1, "Configuring1",
480 "Starting configuration procedure, checking Datalogger state");
481
482 AddStateName(kStateConfiguring2, "Configuring2",
483 "Waiting for FTM and Datalogger to get ready");
484
485 AddStateName(kStateConfiguring3, "Configuring3",
486 "Waiting for FADs and rate control to get ready");
487
488 AddStateName(kStateConfigured, "Configured",
489 "Everything is configured, trigger will be switched on now");
490
491 AddStateName(kStateTriggerOn, "TriggerOn",
492 "The trigger is switched on, waiting for FAD to receive data");
493
494 AddStateName(kStateTakingData, "TakingData",
495 "The trigger is switched on, FADs are sending data");
496
497
498 AddEvent("START", "X:2;C")//, kStateIdle)
499 (bind(&StateMachineMCP::StartRun, this, placeholders::_1))
500 ("Start the configuration and data taking for a run-type of a pre-defined setup"
501 "|TimeMax[s]:Maximum number of seconds before the run will be closed automatically"
502 "|NumMax[count]:Maximum number events before the run will be closed automatically"
503 "|Name[text]:Name of the configuration to be used for taking data");
504
505 AddEvent("STOP")
506 (bind(&StateMachineMCP::StopRun, this, placeholders::_1))
507 ("Stops the trigger (either disables the FTM trigger or the internal DRS trigger)");
508
509 AddEvent("RESET", kStateConfiguring1, kStateConfiguring2, kStateConfiguring3, kStateConfigured)
510 (bind(&StateMachineMCP::Reset, this, placeholders::_1))
511 ("If a configuration blockes because a system cannot configure itself properly, "
512 "this command can be called to leave the configuration procedure. The command "
513 "is also propagated to FTM and FAD");
514
515 // Verbosity commands
516 AddEvent("SET_VERBOSE", "B:1")
517 (bind(&StateMachineMCP::SetVerbosity, this, placeholders::_1))
518 ("set verbosity state"
519 "|verbosity[bool]:disable or enable verbosity for received data (yes/no), except dynamic data");
520
521 AddEvent("PRINT")
522 (bind(&StateMachineMCP::Print, this))
523 ("Print the states and connection status of all systems connected to the MCP.");
524 }
525
526 int EvalOptions(Configuration &)
527 {
528 //SetEndpoint(conf.Get<string>("addr"));
529
530 //fFSC.SetVerbose(!conf.Get<bool>("quiet"));
531
532 return -1;
533 }
534};
535
536// ------------------------------------------------------------------------
537
538#include "Main.h"
539
540template<class T>
541int RunShell(Configuration &conf)
542{
543 return Main::execute<T, StateMachineMCP>(conf);
544}
545
546/*
547 Extract usage clause(s) [if any] for SYNOPSIS.
548 Translators: "Usage" and "or" here are patterns (regular expressions) which
549 are used to match the usage synopsis in program output. An example from cp
550 (GNU coreutils) which contains both strings:
551 Usage: cp [OPTION]... [-T] SOURCE DEST
552 or: cp [OPTION]... SOURCE... DIRECTORY
553 or: cp [OPTION]... -t DIRECTORY SOURCE...
554 */
555void PrintUsage()
556{
557 cout <<
558 "The ftmctrl controls the FSC (FACT Slow Control) board.\n"
559 "\n"
560 "The default is that the program is started without user intercation. "
561 "All actions are supposed to arrive as DimCommands. Using the -c "
562 "option, a local shell can be initialized. With h or help a short "
563 "help message about the usuage can be brought to the screen.\n"
564 "\n"
565 "Usage: fscctrl [-c type] [OPTIONS]\n"
566 " or: fscctrl [OPTIONS]\n";
567 cout << endl;
568}
569
570void PrintHelp()
571{
572 Main::PrintHelp<StateMachineMCP>();
573
574 /* Additional help text which is printed after the configuration
575 options goes here */
576
577 /*
578 cout << "bla bla bla" << endl << endl;
579 cout << endl;
580 cout << "Environment:" << endl;
581 cout << "environment" << endl;
582 cout << endl;
583 cout << "Examples:" << endl;
584 cout << "test exam" << endl;
585 cout << endl;
586 cout << "Files:" << endl;
587 cout << "files" << endl;
588 cout << endl;
589 */
590}
591
592int main(int argc, const char* argv[])
593{
594 Configuration conf(argv[0]);
595 conf.SetPrintUsage(PrintUsage);
596 Main::SetupConfiguration(conf);
597
598 if (!conf.DoParse(argc, argv, PrintHelp))
599 return -1;
600
601 //try
602 {
603 // No console access at all
604 if (!conf.Has("console"))
605 {
606// if (conf.Get<bool>("no-dim"))
607// return RunShell<LocalStream, StateMachine, ConnectionFSC>(conf);
608// else
609 return RunShell<LocalStream>(conf);
610 }
611 // Cosole access w/ and w/o Dim
612/* if (conf.Get<bool>("no-dim"))
613 {
614 if (conf.Get<int>("console")==0)
615 return RunShell<LocalShell, StateMachine, ConnectionFSC>(conf);
616 else
617 return RunShell<LocalConsole, StateMachine, ConnectionFSC>(conf);
618 }
619 else
620*/ {
621 if (conf.Get<int>("console")==0)
622 return RunShell<LocalShell>(conf);
623 else
624 return RunShell<LocalConsole>(conf);
625 }
626 }
627 /*catch (std::exception& e)
628 {
629 cerr << "Exception: " << e.what() << endl;
630 return -1;
631 }*/
632
633 return 0;
634}
Note: See TracBrowser for help on using the repository browser.