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

Last change on this file since 13600 was 13585, checked in by tbretz, 13 years ago
Added two new states: trigger on and taking data
File size: 18.0 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 kStateReadyForDataTaking,
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
184 return GetCurrentState();
185 }
186
187 int StopRun(const EventImp &)
188 {
189 if (fStatusFTM.second==FTM::kTriggerOn)
190 {
191 Message("Stopping FTM");
192 Dim::SendCommand("FTM_CONTROL/STOP_TRIGGER");
193 }
194
195 // FIXME: Do step 2 only when FTM is stopped
196 if (fStatusFAD.second==FAD::kConnected)
197 {
198 //Dim::SendCommand("FAD_CONTROL/ENABLE_TRIGGER_LINE", bool(false));
199 Message("Stopping FAD");
200 Dim::SendCommand("FAD_CONTROL/ENABLE_CONTINOUS_TRIGGER", bool(false));
201 }
202
203 return GetCurrentState();
204 }
205
206 int Reset(const EventImp &)
207 {
208 fRunType = "";
209 Message("Reseting configuration states of FAD and FTM");
210 Dim::SendCommand("FTM_CONTROL/RESET_CONFIGURE");
211 Dim::SendCommand("FAD_CONTROL/RESET_CONFIGURE");
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 (fStatusFTM.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 && 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("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 ".");
477
478 AddStateName(kStateReadyForDataTaking, "ReadyForDataTaking",
479 ".");
480
481 AddStateName(kStateConfiguring1, "Configuring1",
482 ".");
483
484 AddStateName(kStateConfiguring2, "Configuring2",
485 "Waiting for FTM and Datalogger to get ready");
486
487 AddStateName(kStateConfiguring3, "Configuring3",
488 "Waiting for FADs and reate control to get ready");
489
490 AddStateName(kStateConfigured, "Configured",
491 "Everything is configured, trigger will be switched on now");
492
493 AddStateName(kStateTriggerOn, "TriggerOn",
494 "The trigger is switched on, waiting for FAD to receive data");
495
496 AddStateName(kStateTakingData, "TakingData",
497 "The trigger is switched on, FADs are sending data");
498
499
500 AddEvent("START", "X:2;C")//, kStateIdle)
501 (bind(&StateMachineMCP::StartRun, this, placeholders::_1))
502 ("");
503
504 AddEvent("STOP")
505 (bind(&StateMachineMCP::StopRun, this, placeholders::_1))
506 ("");
507
508 AddEvent("RESET", kStateConfiguring1, kStateConfiguring2, kStateConfiguring3, kStateConfigured)
509 (bind(&StateMachineMCP::Reset, this, placeholders::_1))
510 ("");
511
512 // Verbosity commands
513 AddEvent("SET_VERBOSE", "B:1")
514 (bind(&StateMachineMCP::SetVerbosity, this, placeholders::_1))
515 ("set verbosity state"
516 "|verbosity[bool]:disable or enable verbosity for received data (yes/no), except dynamic data");
517
518 AddEvent("PRINT")
519 (bind(&StateMachineMCP::Print, this))
520 ("");
521 }
522
523 int EvalOptions(Configuration &)
524 {
525 //SetEndpoint(conf.Get<string>("addr"));
526
527 //fFSC.SetVerbose(!conf.Get<bool>("quiet"));
528
529 return -1;
530 }
531};
532
533// ------------------------------------------------------------------------
534
535#include "Main.h"
536
537template<class T>
538int RunShell(Configuration &conf)
539{
540 return Main::execute<T, StateMachineMCP>(conf);
541}
542
543/*
544 Extract usage clause(s) [if any] for SYNOPSIS.
545 Translators: "Usage" and "or" here are patterns (regular expressions) which
546 are used to match the usage synopsis in program output. An example from cp
547 (GNU coreutils) which contains both strings:
548 Usage: cp [OPTION]... [-T] SOURCE DEST
549 or: cp [OPTION]... SOURCE... DIRECTORY
550 or: cp [OPTION]... -t DIRECTORY SOURCE...
551 */
552void PrintUsage()
553{
554 cout <<
555 "The ftmctrl controls the FSC (FACT Slow Control) board.\n"
556 "\n"
557 "The default is that the program is started without user intercation. "
558 "All actions are supposed to arrive as DimCommands. Using the -c "
559 "option, a local shell can be initialized. With h or help a short "
560 "help message about the usuage can be brought to the screen.\n"
561 "\n"
562 "Usage: fscctrl [-c type] [OPTIONS]\n"
563 " or: fscctrl [OPTIONS]\n";
564 cout << endl;
565}
566
567void PrintHelp()
568{
569 Main::PrintHelp<StateMachineMCP>();
570
571 /* Additional help text which is printed after the configuration
572 options goes here */
573
574 /*
575 cout << "bla bla bla" << endl << endl;
576 cout << endl;
577 cout << "Environment:" << endl;
578 cout << "environment" << endl;
579 cout << endl;
580 cout << "Examples:" << endl;
581 cout << "test exam" << endl;
582 cout << endl;
583 cout << "Files:" << endl;
584 cout << "files" << endl;
585 cout << endl;
586 */
587}
588
589int main(int argc, const char* argv[])
590{
591 Configuration conf(argv[0]);
592 conf.SetPrintUsage(PrintUsage);
593 Main::SetupConfiguration(conf);
594
595 if (!conf.DoParse(argc, argv, PrintHelp))
596 return -1;
597
598 //try
599 {
600 // No console access at all
601 if (!conf.Has("console"))
602 {
603// if (conf.Get<bool>("no-dim"))
604// return RunShell<LocalStream, StateMachine, ConnectionFSC>(conf);
605// else
606 return RunShell<LocalStream>(conf);
607 }
608 // Cosole access w/ and w/o Dim
609/* if (conf.Get<bool>("no-dim"))
610 {
611 if (conf.Get<int>("console")==0)
612 return RunShell<LocalShell, StateMachine, ConnectionFSC>(conf);
613 else
614 return RunShell<LocalConsole, StateMachine, ConnectionFSC>(conf);
615 }
616 else
617*/ {
618 if (conf.Get<int>("console")==0)
619 return RunShell<LocalShell>(conf);
620 else
621 return RunShell<LocalConsole>(conf);
622 }
623 }
624 /*catch (std::exception& e)
625 {
626 cerr << "Exception: " << e.what() << endl;
627 return -1;
628 }*/
629
630 return 0;
631}
Note: See TracBrowser for help on using the repository browser.