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

Last change on this file since 14362 was 14350, checked in by tbretz, 12 years ago
It is not necessary to check the rate control only for the timeout of the FADs. Before starting the trigger we have to wait until the state of the rate control is GlobalThresholdSet
File size: 21.6 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
10#include "tools.h"
11
12#include "LocalControl.h"
13
14#include "HeadersFTM.h"
15#include "HeadersFAD.h"
16#include "HeadersMCP.h"
17#include "HeadersRateControl.h"
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#include "DimState.h"
29
30// ------------------------------------------------------------------------
31
32class StateMachineMCP : public StateMachineDim
33{
34private:
35 vector<bool> fFadConnected;
36 vector<bool> fFadNeedsReset;
37
38 vector<bool> fFadCratesForReset;
39 vector<bool> fFadBoardsForConnection;
40
41 uint16_t fNumConnectedFtu;
42 uint16_t fNumConnectedFad;
43
44 uint16_t fNumReset;
45
46 DimVersion fDim;
47 DimDescribedState fDimFTM;
48 DimDescribedState fDimFAD;
49 DimDescribedState fDimLog;
50 DimDescribedState fDimRC;
51
52 DimDescribedService fService;
53
54 Time fFadTimeout;
55
56 int HandleFadConnections(const EventImp &d)
57 {
58 if (d.GetSize()!=41)
59 return GetCurrentState();
60
61 const uint8_t *ptr = d.Ptr<uint8_t>();
62
63 fNumConnectedFad = 0;
64 fFadConnected.assign(40, false);
65
66 vector<bool> reset(4);
67
68 for (int i=0; i<40; i++)
69 {
70 const uint8_t stat1 = ptr[i]&3;
71 const uint8_t stat2 = ptr[i]>>3;
72
73 // disconnected: ignore
74 if (stat1==0 && stat2==0)
75 continue;
76
77 fFadConnected[i] = true;
78
79 if (stat1>=2 && stat2==8)
80 fNumConnectedFad++;
81
82 // Does not need reset
83 if (stat1>2 && stat2==8)
84 continue;
85
86 // Not configured (stat1==2?kLedGreen:kLedGreenCheck)
87 // Connection problem (stat1==1&&stat2==1?kLedRed:kLedOrange)
88 reset[i/10] = true;
89 }
90 return GetCurrentState();
91 }
92
93 int HandleFtmStaticData(const EventImp &d)
94 {
95 if (d.GetSize()!=sizeof(FTM::DimStaticData))
96 return GetCurrentState();
97
98 const FTM::DimStaticData &sdata = d.Ref<FTM::DimStaticData>();
99
100 fNumConnectedFtu = 0;
101 for (int i=0; i<40; i++)
102 {
103 if (sdata.IsActive(i))
104 fNumConnectedFtu++;
105 }
106 return GetCurrentState();
107 }
108
109 int Print() const
110 {
111 Out() << fDim << endl;
112 Out() << fDimFTM << endl;
113 Out() << fDimFAD << endl;
114 Out() << fDimLog << endl;
115 Out() << fDimRC << endl;
116
117 return GetCurrentState();
118 }
119
120 int GetReady()
121 {
122 return GetCurrentState();
123 }
124
125 int StopRun()
126 {
127 if (fDimFTM.state()==FTM::State::kTriggerOn)
128 {
129 Message("Stopping FTM");
130 Dim::SendCommandNB("FTM_CONTROL/STOP_TRIGGER");
131 }
132
133 // FIXME: Do step 2 only when FTM is stopped
134 if (fDimFAD.state()==FAD::State::kConnected)
135 {
136 //Dim::SendCommand("FAD_CONTROL/ENABLE_TRIGGER_LINE", bool(false));
137 Message("Stopping FAD");
138 Dim::SendCommandNB("FAD_CONTROL/ENABLE_CONTINOUS_TRIGGER", bool(false));
139 }
140
141 return GetCurrentState();
142 }
143
144 int Reset()
145 {
146 if (GetCurrentState()<MCP::State::kConfiguring1 ||
147 GetCurrentState()>MCP::State::kConfigured)
148 return GetCurrentState();
149
150 fRunType = "";
151 Message("Reseting configuration states of FAD and FTM");
152
153 Dim::SendCommandNB("FTM_CONTROL/RESET_CONFIGURE");
154 Dim::SendCommandNB("FAD_CONTROL/RESET_CONFIGURE");
155
156 Update(MCP::State::kIdle);
157 return MCP::State::kIdle;
158 /*
159 // FIMXE: Handle error states!
160 if (fDimLog.state()>=20)//kSM_NightlyOpen
161 Dim::SendCommand("DATA_LOGGER/STOP");
162
163 if (fDimLog.state()==0)
164 Dim::SendCommand("DATA_LOGGER/WAIT_FOR_RUN_NUMBER");
165
166 if (fDimFAD.state()==FAD::State::kConnected)
167 {
168 Dim::SendCommand("FAD_CONTROL/ENABLE_TRIGGER_LINE", bool(false));
169 Dim::SendCommand("FAD_CONTROL/ENABLE_CONTINOUS_TRIGGER", bool(false));
170 }
171
172 if (fDimFTM.state()==FTM::State::kTakingData)
173 Dim::SendCommand("FTM_CONTROL/STOP");
174
175 return GetCurrentState(); */
176 }
177
178 int64_t fMaxTime;
179 int64_t fNumEvents;
180 string fRunType;
181
182 int StartRun(const EventImp &evt)
183 {
184 if (!fDimFTM.online())
185 {
186 Error("No connection to ftmcontrol (see PRINT).");
187 return GetCurrentState();
188 }
189 if (!fDimFAD.online())
190 {
191 Warn("No connection to fadcontrol (see PRINT).");
192 return GetCurrentState();
193 }
194 if (!fDimLog.online())
195 {
196 Warn("No connection to datalogger (see PRINT).");
197 return GetCurrentState();
198 }
199 if (!fDimRC.online())
200 {
201 Warn("No connection to ratecontrol (see PRINT).");
202 return GetCurrentState();
203 }
204
205 fMaxTime = evt.Get<int64_t>();
206 fNumEvents = evt.Get<int64_t>(8);
207 fRunType = evt.Ptr<char>(16);
208
209 fNumReset = 0;
210
211 ostringstream str;
212 str << "Starting configuration '" << fRunType << "' for new run";
213 if (fNumEvents>0 || fMaxTime>0)
214 str << " [";
215 if (fNumEvents>0)
216 str << fNumEvents << " events";
217 if (fNumEvents>0 && fMaxTime>0)
218 str << " / ";
219 if (fMaxTime>0)
220 str << fMaxTime << "s";
221 if (fNumEvents>0 || fMaxTime>0)
222 str << "]";
223 Message(str);
224
225 Update(MCP::State::kConfiguring1);
226
227 return MCP::State::kConfiguring1;
228 }
229
230 struct Value
231 {
232 uint64_t time;
233 uint64_t nevts;
234 char type[];
235 };
236
237 Value *GetBuffer()
238 {
239 const size_t len = sizeof(Value)+fRunType.length()+1;
240
241 char *buf = new char[len];
242
243 Value *val = reinterpret_cast<Value*>(buf);
244
245 val->time = fMaxTime;
246 val->nevts = fNumEvents;
247
248 strcpy(val->type, fRunType.c_str());
249
250 return val;
251 }
252
253 void Update(int newstate)
254 {
255 Value *buf = GetBuffer();
256 fService.setQuality(newstate);
257 fService.setData(buf, sizeof(Value)+fRunType.length()+1);
258 fService.Update();
259 delete buf;
260 }
261
262 void ConfigureFAD()
263 {
264 Value *buf = GetBuffer();
265
266 Message("Configuring FAD");
267 Dim::SendCommandNB("FAD_CONTROL/CONFIGURE", buf, sizeof(Value)+fRunType.length()+1);
268
269 delete buf;
270 }
271
272 int HandleStateChange()
273 {
274 if (!fDim.online())
275 return MCP::State::kDimNetworkNA;
276
277 if (fDimFTM.state() >= FTM::State::kConnected &&
278 fDimFAD.state() >= FAD::State::kConnected &&
279 fDimLog.state() >= kSM_Ready)
280 return GetCurrentState()<=MCP::State::kIdle ? MCP::State::kIdle : GetCurrentState();
281
282 if (fDimFTM.state() >-2 &&
283 fDimFAD.state() >-2 &&
284 fDimLog.state() >-2 &&
285 fDimRC.state() >-2)
286 return MCP::State::kConnected;
287
288 if (fDimFTM.state() >-2 ||
289 fDimFAD.state() >-2 ||
290 fDimLog.state() >-2 ||
291 fDimRC.state() >-2)
292 return MCP::State::kConnecting;
293
294 return MCP::State::kDisconnected;
295 }
296
297 int Execute()
298 {
299 // ========================================================
300
301 if (GetCurrentState()==MCP::State::kConfiguring1)
302 {
303 if (fDimLog.state()<30/*kSM_WaitForRun*/)
304 {
305 Message("Starting datalogger");
306 Dim::SendCommandNB("DATA_LOGGER/START_RUN_LOGGING");
307 }
308
309 Message("Configuring Trigger (FTM)");
310 Dim::SendCommandNB("FTM_CONTROL/CONFIGURE", fRunType);
311
312 Update(MCP::State::kConfiguring2);
313 return MCP::State::kConfiguring2;
314 }
315
316 // --------------------------------------------------------
317
318 if (GetCurrentState()==MCP::State::kConfiguring2)
319 {
320 // FIMXE: Reset in case of error
321 if ((/*fDimFTM.state() != FTM::State::kConfiguring2 &&*/
322 fDimFTM.state() != FTM::State::kConfigured) ||
323 fDimLog.state()<30 || fDimLog.state()>0xff)
324 return MCP::State::kConfiguring2;
325
326 // FIMXE: This is to make sure that the rate control
327 // has received the correct trigger setup already...
328 //usleep(1000000);
329
330 Message("Starting Rate Control");
331 // State of RC is not reported back fast enough!
332 Dim::SendCommandNB("RATE_CONTROL/CALIBRATE");
333
334 ConfigureFAD();
335
336 fFadTimeout = Time();
337
338 Update(MCP::State::kConfiguring3);
339 return MCP::State::kConfiguring3;
340 }
341
342 // --------------------------------------------------------
343
344 if (GetCurrentState()==MCP::State::kConfiguring3)
345 {
346 // If everything is configured but the FADs
347 // we run into a timeout and some FAD need to be reset
348 // then we start an automatic crate reset
349 if (fDimFTM.state() == FTM::State::kConfigured &&
350 fDimFAD.state() != FAD::State::kConfigured &&
351 /*fDimRC.state() > RateControl::State::kSettingGlobalThreshold &&*/
352 fFadTimeout+boost::posix_time::seconds(15)<Time() &&
353 count(fFadNeedsReset.begin(), fFadNeedsReset.end(), true)>0)
354 {
355 Update(MCP::State::kCrateReset0);
356 return MCP::State::kCrateReset0;
357 }
358
359 // If something is not yet properly configured: keep state
360 if (fDimFTM.state() != FTM::State::kConfigured ||
361 fDimFAD.state() != FAD::State::kConfigured ||
362 fDimRC.state() <= RateControl::State::kSettingGlobalThreshold)
363 return MCP::State::kConfiguring3;
364
365 Message("Starting Trigger (FTM)");
366 Dim::SendCommandNB("FTM_CONTROL/START_TRIGGER");
367
368 Update(MCP::State::kConfigured);
369 return MCP::State::kConfigured;
370 }
371
372 // --------------------------------------------------------
373
374 if (GetCurrentState()==MCP::State::kConfigured)
375 {
376 if (fDimFTM.state() != FTM::State::kTriggerOn)
377 return MCP::State::kConfigured;
378
379 Update(MCP::State::kTriggerOn);
380 return MCP::State::kTriggerOn;
381 }
382
383 // --------------------------------------------------------
384
385 if (GetCurrentState()==MCP::State::kTriggerOn)
386 {
387 if (fDimFAD.state() != FAD::State::kWritingData)
388 return MCP::State::kTriggerOn;
389
390 Update(MCP::State::kTakingData);
391 return MCP::State::kTakingData;
392 }
393
394 // --------------------------------------------------------
395
396 if (GetCurrentState()==MCP::State::kTakingData)
397 {
398 if (fDimFTM.state()==FTM::State::kTriggerOn &&
399 fDimFAD.state()==FAD::State::kWritingData)
400 return MCP::State::kTakingData;
401
402 Update(MCP::State::kIdle);
403 return MCP::State::kIdle;
404 }
405
406 // ========================================================
407
408 if (GetCurrentState()==MCP::State::kCrateReset0)
409 {
410 static const struct Data { int32_t id; char on; } __attribute__((__packed__)) d = { -1, 0 };
411
412 Dim::SendCommandNB("FTM_CONTROL/ENABLE_FTU", &d, sizeof(Data));
413
414 fFadCratesForReset = fFadNeedsReset;
415 fFadBoardsForConnection = fFadConnected;
416
417 for (int c=0; c<4; c++)
418 if (fFadNeedsReset[c])
419 for (int b=0; b<10; b++)
420 Dim::SendCommandNB("FAD_CONTROL/DISCONNECT", uint16_t(c*10+b));
421
422 fNumReset++;
423
424 Update(MCP::State::kCrateReset1);
425 return MCP::State::kCrateReset1;
426 }
427
428 // --------------------------------------------------------
429
430 if (GetCurrentState()==MCP::State::kCrateReset1)
431 {
432 if (fNumConnectedFtu>0 || count(fFadNeedsReset.begin(), fFadNeedsReset.end(), true)>0)
433 return MCP::State::kCrateReset1;
434
435 for (int i=0; i<4; i++)
436 if (fFadCratesForReset[i])
437 Dim::SendCommandNB("FAD_CONTROL/RESET_CRATE", uint16_t(i));
438
439 fFadTimeout = Time();
440
441 Update(MCP::State::kCrateReset2);
442 return MCP::State::kCrateReset2;
443 }
444
445 // --------------------------------------------------------
446
447 if (GetCurrentState()==MCP::State::kCrateReset2)
448 {
449 if (fFadTimeout+boost::posix_time::seconds(45)>Time())
450 return MCP::State::kCrateReset2;
451
452 static const struct Data { int32_t id; char on; } __attribute__((__packed__)) d = { -1, 1 };
453
454 Dim::SendCommandNB("FTM_CONTROL/ENABLE_FTU", &d, sizeof(Data));
455
456 for (int c=0; c<4; c++)
457 if (fFadCratesForReset[c])
458 for (int b=0; b<10; b++)
459 if (fFadBoardsForConnection[c*10+b])
460 Dim::SendCommandNB("FAD_CONTROL/CONNECT", uint16_t(c*10+b));
461
462 Update(MCP::State::kCrateReset3);
463 return MCP::State::kCrateReset3;
464 }
465
466 // --------------------------------------------------------
467
468 if (GetCurrentState()==MCP::State::kCrateReset3)
469 {
470 if (fNumConnectedFtu<40 || fFadBoardsForConnection!=fFadConnected)
471 return MCP::State::kCrateReset3;
472
473 if (count(fFadNeedsReset.begin(), fFadNeedsReset.end(), true)>0 && fNumReset<6)
474 {
475 Update(MCP::State::kCrateReset0);
476 return MCP::State::kCrateReset0;
477 }
478
479 // restart configuration
480 Update(MCP::State::kConfiguring1);
481 return MCP::State::kConfiguring1;
482 }
483
484 // ========================================================
485
486 return GetCurrentState();
487 }
488
489public:
490 StateMachineMCP(ostream &out=cout) : StateMachineDim(out, "MCP"),
491 fFadNeedsReset(4), fNumConnectedFtu(40),
492 fDimFTM("FTM_CONTROL"),
493 fDimFAD("FAD_CONTROL"),
494 fDimLog("DATA_LOGGER"),
495 fDimRC("RATE_CONTROL"),
496 fService("MCP/CONFIGURATION", "X:1;X:1;C", "Run configuration information"
497 "|MaxTime[s]:Maximum time before the run gets stopped"
498 "|MaxEvents[num]:Maximum number of events before the run gets stopped"
499 "|Name[text]:Name of the chosen configuration")
500 {
501 // ba::io_service::work is a kind of keep_alive for the loop.
502 // It prevents the io_service to go to stopped state, which
503 // would prevent any consecutive calls to run()
504 // or poll() to do nothing. reset() could also revoke to the
505 // previous state but this might introduce some overhead of
506 // deletion and creation of threads and more.
507
508 fDim.Subscribe(*this);
509 fDimFTM.Subscribe(*this);
510 fDimFAD.Subscribe(*this);
511 fDimLog.Subscribe(*this);
512 fDimRC.Subscribe(*this);
513
514 fDim.SetCallback(bind(&StateMachineMCP::HandleStateChange, this));
515 fDimFTM.SetCallback(bind(&StateMachineMCP::HandleStateChange, this));
516 fDimFAD.SetCallback(bind(&StateMachineMCP::HandleStateChange, this));
517 fDimLog.SetCallback(bind(&StateMachineMCP::HandleStateChange, this));
518 fDimRC.SetCallback(bind(&StateMachineMCP::HandleStateChange, this));
519
520 Subscribe("FAD_CONTROL/CONNECTIONS")
521 (bind(&StateMachineMCP::HandleFadConnections, this, placeholders::_1));
522 Subscribe("FTM_CONTROL/STATIC_DATA")
523 (bind(&StateMachineMCP::HandleFtmStaticData, this, placeholders::_1));
524
525 // State names
526 AddStateName(MCP::State::kDimNetworkNA, "DimNetworkNotAvailable",
527 "DIM dns server not available.");
528 AddStateName(MCP::State::kDisconnected, "Disconnected",
529 "Neither ftmctrl, fadctrl, datalogger nor rate control online.");
530 AddStateName(MCP::State::kConnecting, "Connecting",
531 "Either ftmctrl, fadctrl, datalogger or rate control not online.");
532 AddStateName(MCP::State::kConnected, "Connected",
533 "All needed subsystems online.");
534 AddStateName(MCP::State::kIdle, "Idle",
535 "Waiting for next configuration command");
536 AddStateName(MCP::State::kConfiguring1, "Configuring1",
537 "Starting configuration procedure, checking Datalogger state");
538 AddStateName(MCP::State::kConfiguring2, "Configuring2",
539 "Waiting for FTM and Datalogger to get ready");
540 AddStateName(MCP::State::kConfiguring3, "Configuring3",
541 "Waiting for FADs and rate control to get ready");
542
543 AddStateName(MCP::State::kCrateReset0, "CrateReset0",
544 "Disabling FTUs, disconnecting FADs");
545 AddStateName(MCP::State::kCrateReset1, "CrateReset1",
546 "Waiting for FTUs to be disabled and for FADs to be disconnected");
547 AddStateName(MCP::State::kCrateReset2, "CrateReset2",
548 "Waiting 45s");
549 AddStateName(MCP::State::kCrateReset3, "CrateReset3",
550 "Waiting for FTUs to be enabled and for FADs to be re-connected");
551
552 AddStateName(MCP::State::kConfigured, "Configured",
553 "Everything is configured, trigger will be switched on now");
554 AddStateName(MCP::State::kTriggerOn, "TriggerOn",
555 "The trigger is switched on, waiting for FAD to receive data");
556 AddStateName(MCP::State::kTakingData, "TakingData",
557 "The trigger is switched on, FADs are sending data");
558
559
560 AddEvent("START", "X:2;C")//, MCP::State::kIdle)
561 (bind(&StateMachineMCP::StartRun, this, placeholders::_1))
562 ("Start the configuration and data taking for a run-type of a pre-defined setup"
563 "|TimeMax[s]:Maximum number of seconds before the run will be closed automatically"
564 "|NumMax[count]:Maximum number events before the run will be closed automatically"
565 "|Name[text]:Name of the configuration to be used for taking data");
566
567 AddEvent("STOP")
568 (bind(&StateMachineMCP::StopRun, this))
569 ("Stops the trigger (either disables the FTM trigger or the internal DRS trigger)");
570
571 AddEvent("RESET")
572 (bind(&StateMachineMCP::Reset, this))
573 ("If a configuration blockes because a system cannot configure itself properly, "
574 "this command can be called to leave the configuration procedure. The command "
575 "is also propagated to FTM and FAD");
576
577 AddEvent("PRINT")
578 (bind(&StateMachineMCP::Print, this))
579 ("Print the states and connection status of all systems connected to the MCP.");
580 }
581
582 int EvalOptions(Configuration &)
583 {
584 return -1;
585 }
586};
587
588// ------------------------------------------------------------------------
589
590#include "Main.h"
591
592template<class T>
593int RunShell(Configuration &conf)
594{
595 return Main::execute<T, StateMachineMCP>(conf);
596}
597
598/*
599 Extract usage clause(s) [if any] for SYNOPSIS.
600 Translators: "Usage" and "or" here are patterns (regular expressions) which
601 are used to match the usage synopsis in program output. An example from cp
602 (GNU coreutils) which contains both strings:
603 Usage: cp [OPTION]... [-T] SOURCE DEST
604 or: cp [OPTION]... SOURCE... DIRECTORY
605 or: cp [OPTION]... -t DIRECTORY SOURCE...
606 */
607void PrintUsage()
608{
609 cout <<
610 "The ftmctrl controls the FSC (FACT Slow Control) board.\n"
611 "\n"
612 "The default is that the program is started without user intercation. "
613 "All actions are supposed to arrive as DimCommands. Using the -c "
614 "option, a local shell can be initialized. With h or help a short "
615 "help message about the usuage can be brought to the screen.\n"
616 "\n"
617 "Usage: fscctrl [-c type] [OPTIONS]\n"
618 " or: fscctrl [OPTIONS]\n";
619 cout << endl;
620}
621
622void PrintHelp()
623{
624 Main::PrintHelp<StateMachineMCP>();
625
626 /* Additional help text which is printed after the configuration
627 options goes here */
628
629 /*
630 cout << "bla bla bla" << endl << endl;
631 cout << endl;
632 cout << "Environment:" << endl;
633 cout << "environment" << endl;
634 cout << endl;
635 cout << "Examples:" << endl;
636 cout << "test exam" << endl;
637 cout << endl;
638 cout << "Files:" << endl;
639 cout << "files" << endl;
640 cout << endl;
641 */
642}
643
644int main(int argc, const char* argv[])
645{
646 Configuration conf(argv[0]);
647 conf.SetPrintUsage(PrintUsage);
648 Main::SetupConfiguration(conf);
649
650 if (!conf.DoParse(argc, argv, PrintHelp))
651 return 127;
652
653 //try
654 {
655 // No console access at all
656 if (!conf.Has("console"))
657 {
658// if (conf.Get<bool>("no-dim"))
659// return RunShell<LocalStream, StateMachine, ConnectionFSC>(conf);
660// else
661 return RunShell<LocalStream>(conf);
662 }
663 // Cosole access w/ and w/o Dim
664/* if (conf.Get<bool>("no-dim"))
665 {
666 if (conf.Get<int>("console")==0)
667 return RunShell<LocalShell, StateMachine, ConnectionFSC>(conf);
668 else
669 return RunShell<LocalConsole, StateMachine, ConnectionFSC>(conf);
670 }
671 else
672*/ {
673 if (conf.Get<int>("console")==0)
674 return RunShell<LocalShell>(conf);
675 else
676 return RunShell<LocalConsole>(conf);
677 }
678 }
679 /*catch (std::exception& e)
680 {
681 cerr << "Exception: " << e.what() << endl;
682 return -1;
683 }*/
684
685 return 0;
686}
Note: See TracBrowser for help on using the repository browser.