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

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