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

Last change on this file since 15027 was 14683, checked in by tbretz, 12 years ago
Took out automatic crate reset for the moment. That is something which needs to be done once at the beginning of data-taking.
File size: 21.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
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
155 Update(MCP::State::kIdle);
156 return MCP::State::kIdle;
157 /*
158 // FIMXE: Handle error states!
159 if (fDimLog.state()>=20)//kSM_NightlyOpen
160 Dim::SendCommand("DATA_LOGGER/STOP");
161
162 if (fDimLog.state()==0)
163 Dim::SendCommand("DATA_LOGGER/WAIT_FOR_RUN_NUMBER");
164
165 if (fDimFAD.state()==FAD::State::kConnected)
166 {
167 Dim::SendCommand("FAD_CONTROL/ENABLE_TRIGGER_LINE", bool(false));
168 Dim::SendCommand("FAD_CONTROL/ENABLE_CONTINOUS_TRIGGER", bool(false));
169 }
170
171 if (fDimFTM.state()==FTM::State::kTakingData)
172 Dim::SendCommand("FTM_CONTROL/STOP");
173
174 return GetCurrentState(); */
175 }
176
177 int64_t fMaxTime;
178 int64_t fNumEvents;
179 string fRunType;
180
181 int StartRun(const EventImp &evt)
182 {
183 if (!fDimFTM.online())
184 {
185 Error("No connection to ftmcontrol (see PRINT).");
186 return GetCurrentState();
187 }
188 if (!fDimFAD.online())
189 {
190 Warn("No connection to fadcontrol (see PRINT).");
191 return GetCurrentState();
192 }
193 if (!fDimLog.online())
194 {
195 Warn("No connection to datalogger (see PRINT).");
196 return GetCurrentState();
197 }
198 if (!fDimRC.online())
199 {
200 Warn("No connection to ratecontrol (see PRINT).");
201 return GetCurrentState();
202 }
203
204 fMaxTime = evt.Get<int64_t>();
205 fNumEvents = evt.Get<int64_t>(8);
206 fRunType = evt.Ptr<char>(16);
207
208 fNumReset = 0;
209
210 ostringstream str;
211 str << "Starting configuration '" << fRunType << "' for new run";
212 if (fNumEvents>0 || fMaxTime>0)
213 str << " [";
214 if (fNumEvents>0)
215 str << fNumEvents << " events";
216 if (fNumEvents>0 && fMaxTime>0)
217 str << " / ";
218 if (fMaxTime>0)
219 str << fMaxTime << "s";
220 if (fNumEvents>0 || fMaxTime>0)
221 str << "]";
222 Message(str);
223
224 Update(MCP::State::kConfiguring1);
225
226 return MCP::State::kConfiguring1;
227 }
228
229 struct Value
230 {
231 uint64_t time;
232 uint64_t nevts;
233 char type[];
234 };
235
236 Value *GetBuffer()
237 {
238 const size_t len = sizeof(Value)+fRunType.length()+1;
239
240 char *buf = new char[len];
241
242 Value *val = reinterpret_cast<Value*>(buf);
243
244 val->time = fMaxTime;
245 val->nevts = fNumEvents;
246
247 strcpy(val->type, fRunType.c_str());
248
249 return val;
250 }
251
252 void Update(int newstate)
253 {
254 Value *buf = GetBuffer();
255 fService.setQuality(newstate);
256 fService.setData(buf, sizeof(Value)+fRunType.length()+1);
257 fService.Update();
258 delete buf;
259 }
260
261 void ConfigureFAD()
262 {
263 Value *buf = GetBuffer();
264
265 Message("Configuring FAD");
266 Dim::SendCommandNB("FAD_CONTROL/CONFIGURE", buf, sizeof(Value)+fRunType.length()+1);
267
268 delete buf;
269 }
270
271 int HandleStateChange()
272 {
273 if (!fDim.online())
274 return MCP::State::kDimNetworkNA;
275
276 if (fDimFTM.state() >= FTM::State::kConnected &&
277 fDimFAD.state() >= FAD::State::kConnected &&
278 fDimLog.state() >= kSM_Ready)
279 return GetCurrentState()<=MCP::State::kIdle ? MCP::State::kIdle : GetCurrentState();
280
281 if (fDimFTM.state() >-2 &&
282 fDimFAD.state() >-2 &&
283 fDimLog.state() >-2 &&
284 fDimRC.state() >-2)
285 return MCP::State::kConnected;
286
287 if (fDimFTM.state() >-2 ||
288 fDimFAD.state() >-2 ||
289 fDimLog.state() >-2 ||
290 fDimRC.state() >-2)
291 return MCP::State::kConnecting;
292
293 return MCP::State::kDisconnected;
294 }
295
296 int Execute()
297 {
298 // ========================================================
299
300 if (GetCurrentState()==MCP::State::kConfiguring1)
301 {
302 if (fDimLog.state()<30/*kSM_WaitForRun*/)
303 {
304 Message("Starting datalogger");
305 Dim::SendCommandNB("DATA_LOGGER/START_RUN_LOGGING");
306 }
307
308 Message("Configuring Trigger (FTM)");
309 Dim::SendCommandNB("FTM_CONTROL/CONFIGURE", fRunType);
310
311 Update(MCP::State::kConfiguring2);
312 return MCP::State::kConfiguring2;
313 }
314
315 // --------------------------------------------------------
316
317 if (GetCurrentState()==MCP::State::kConfiguring2)
318 {
319 // FIMXE: Reset in case of error
320 if ((/*fDimFTM.state() != FTM::State::kConfiguring2 &&*/
321 fDimFTM.state() != FTM::State::kConfigured) ||
322 fDimLog.state()<30 || fDimLog.state()>0xff)
323 return MCP::State::kConfiguring2;
324
325 // FIMXE: This is to make sure that the rate control
326 // has received the correct trigger setup already...
327 //usleep(1000000);
328
329 Message("Starting Rate Control");
330 // State of RC is not reported back fast enough!
331 Dim::SendCommandNB("RATE_CONTROL/CALIBRATE");
332
333 ConfigureFAD();
334
335 fFadTimeout = Time();
336
337 Update(MCP::State::kConfiguring3);
338 return MCP::State::kConfiguring3;
339 }
340
341 // --------------------------------------------------------
342
343 if (GetCurrentState()==MCP::State::kConfiguring3)
344 {
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 (fDimFTM.state() != FTM::State::kTriggerOn)
388 {
389 Update(MCP::State::kIdle);
390 return MCP::State::kIdle;
391 }
392
393 if (fDimFAD.state() != FAD::State::kWritingData)
394 return MCP::State::kTriggerOn;
395
396 Update(MCP::State::kTakingData);
397 return MCP::State::kTakingData;
398 }
399
400 // --------------------------------------------------------
401
402 if (GetCurrentState()==MCP::State::kTakingData)
403 {
404 if (fDimFTM.state()==FTM::State::kTriggerOn &&
405 fDimFAD.state()==FAD::State::kWritingData)
406 return MCP::State::kTakingData;
407
408 Update(MCP::State::kIdle);
409 return MCP::State::kIdle;
410 }
411
412 // ========================================================
413 /*
414 if (GetCurrentState()==MCP::State::kCrateReset0)
415 {
416 static const struct Data { int32_t id; char on; } __attribute__((__packed__)) d = { -1, 0 };
417
418 Dim::SendCommandNB("FTM_CONTROL/ENABLE_FTU", &d, sizeof(Data));
419
420 fFadCratesForReset = fFadNeedsReset;
421 fFadBoardsForConnection = fFadConnected;
422
423 for (int c=0; c<4; c++)
424 if (fFadNeedsReset[c])
425 for (int b=0; b<10; b++)
426 Dim::SendCommandNB("FAD_CONTROL/DISCONNECT", uint16_t(c*10+b));
427
428 fNumReset++;
429
430 Update(MCP::State::kCrateReset1);
431 return MCP::State::kCrateReset1;
432 }
433
434 // --------------------------------------------------------
435
436 if (GetCurrentState()==MCP::State::kCrateReset1)
437 {
438 if (fNumConnectedFtu>0 || count(fFadNeedsReset.begin(), fFadNeedsReset.end(), true)>0)
439 return MCP::State::kCrateReset1;
440
441 for (int i=0; i<4; i++)
442 if (fFadCratesForReset[i])
443 Dim::SendCommandNB("FAD_CONTROL/RESET_CRATE", uint16_t(i));
444
445 fFadTimeout = Time();
446
447 Update(MCP::State::kCrateReset2);
448 return MCP::State::kCrateReset2;
449 }
450
451 // --------------------------------------------------------
452
453 if (GetCurrentState()==MCP::State::kCrateReset2)
454 {
455 if (fFadTimeout+boost::posix_time::seconds(45)>Time())
456 return MCP::State::kCrateReset2;
457
458 static const struct Data { int32_t id; char on; } __attribute__((__packed__)) d = { -1, 1 };
459
460 Dim::SendCommandNB("FTM_CONTROL/ENABLE_FTU", &d, sizeof(Data));
461
462 for (int c=0; c<4; c++)
463 if (fFadCratesForReset[c])
464 for (int b=0; b<10; b++)
465 if (fFadBoardsForConnection[c*10+b])
466 Dim::SendCommandNB("FAD_CONTROL/CONNECT", uint16_t(c*10+b));
467
468 Update(MCP::State::kCrateReset3);
469 return MCP::State::kCrateReset3;
470 }
471
472 // --------------------------------------------------------
473
474 if (GetCurrentState()==MCP::State::kCrateReset3)
475 {
476 if (fNumConnectedFtu<40 || fFadBoardsForConnection!=fFadConnected)
477 return MCP::State::kCrateReset3;
478
479 if (count(fFadNeedsReset.begin(), fFadNeedsReset.end(), true)>0 && fNumReset<6)
480 {
481 Update(MCP::State::kCrateReset0);
482 return MCP::State::kCrateReset0;
483 }
484
485 // restart configuration
486 Update(MCP::State::kConfiguring1);
487 return MCP::State::kConfiguring1;
488 }
489 */
490 // ========================================================
491
492 return GetCurrentState();
493 }
494
495public:
496 StateMachineMCP(ostream &out=cout) : StateMachineDim(out, "MCP"),
497 fFadNeedsReset(4), fNumConnectedFtu(40),
498 fDimFTM("FTM_CONTROL"),
499 fDimFAD("FAD_CONTROL"),
500 fDimLog("DATA_LOGGER"),
501 fDimRC("RATE_CONTROL"),
502 fService("MCP/CONFIGURATION", "X:1;X:1;C", "Run configuration information"
503 "|MaxTime[s]:Maximum time before the run gets stopped"
504 "|MaxEvents[num]:Maximum number of events before the run gets stopped"
505 "|Name[text]:Name of the chosen configuration")
506 {
507 // ba::io_service::work is a kind of keep_alive for the loop.
508 // It prevents the io_service to go to stopped state, which
509 // would prevent any consecutive calls to run()
510 // or poll() to do nothing. reset() could also revoke to the
511 // previous state but this might introduce some overhead of
512 // deletion and creation of threads and more.
513
514 fDim.Subscribe(*this);
515 fDimFTM.Subscribe(*this);
516 fDimFAD.Subscribe(*this);
517 fDimLog.Subscribe(*this);
518 fDimRC.Subscribe(*this);
519
520 fDim.SetCallback(bind(&StateMachineMCP::HandleStateChange, this));
521 fDimFTM.SetCallback(bind(&StateMachineMCP::HandleStateChange, this));
522 fDimFAD.SetCallback(bind(&StateMachineMCP::HandleStateChange, this));
523 fDimLog.SetCallback(bind(&StateMachineMCP::HandleStateChange, this));
524 fDimRC.SetCallback(bind(&StateMachineMCP::HandleStateChange, this));
525
526 Subscribe("FAD_CONTROL/CONNECTIONS")
527 (bind(&StateMachineMCP::HandleFadConnections, this, placeholders::_1));
528 Subscribe("FTM_CONTROL/STATIC_DATA")
529 (bind(&StateMachineMCP::HandleFtmStaticData, this, placeholders::_1));
530
531 // State names
532 AddStateName(MCP::State::kDimNetworkNA, "DimNetworkNotAvailable",
533 "DIM dns server not available.");
534 AddStateName(MCP::State::kDisconnected, "Disconnected",
535 "Neither ftmctrl, fadctrl, datalogger nor rate control online.");
536 AddStateName(MCP::State::kConnecting, "Connecting",
537 "Either ftmctrl, fadctrl, datalogger or rate control not online.");
538 AddStateName(MCP::State::kConnected, "Connected",
539 "All needed subsystems online.");
540 AddStateName(MCP::State::kIdle, "Idle",
541 "Waiting for next configuration command");
542 AddStateName(MCP::State::kConfiguring1, "Configuring1",
543 "Starting configuration procedure, checking Datalogger state");
544 AddStateName(MCP::State::kConfiguring2, "Configuring2",
545 "Waiting for FTM and Datalogger to get ready");
546 AddStateName(MCP::State::kConfiguring3, "Configuring3",
547 "Waiting for FADs and rate control to get ready");
548 /*
549 AddStateName(MCP::State::kCrateReset0, "CrateReset0",
550 "Disabling FTUs, disconnecting FADs");
551 AddStateName(MCP::State::kCrateReset1, "CrateReset1",
552 "Waiting for FTUs to be disabled and for FADs to be disconnected");
553 AddStateName(MCP::State::kCrateReset2, "CrateReset2",
554 "Waiting 45s");
555 AddStateName(MCP::State::kCrateReset3, "CrateReset3",
556 "Waiting for FTUs to be enabled and for FADs to be re-connected");
557 */
558 AddStateName(MCP::State::kConfigured, "Configured",
559 "Everything is configured, trigger will be switched on now");
560 AddStateName(MCP::State::kTriggerOn, "TriggerOn",
561 "The trigger is switched on, waiting for FAD to receive data");
562 AddStateName(MCP::State::kTakingData, "TakingData",
563 "The trigger is switched on, FADs are sending data");
564
565
566 AddEvent("START", "X:2;C")//, MCP::State::kIdle)
567 (bind(&StateMachineMCP::StartRun, this, placeholders::_1))
568 ("Start the configuration and data taking for a run-type of a pre-defined setup"
569 "|TimeMax[s]:Maximum number of seconds before the run will be closed automatically"
570 "|NumMax[count]:Maximum number events before the run will be closed automatically"
571 "|Name[text]:Name of the configuration to be used for taking data");
572
573 AddEvent("STOP")
574 (bind(&StateMachineMCP::StopRun, this))
575 ("Stops the trigger (either disables the FTM trigger or the internal DRS trigger)");
576
577 AddEvent("RESET")
578 (bind(&StateMachineMCP::Reset, this))
579 ("If a configuration blockes because a system cannot configure itself properly, "
580 "this command can be called to leave the configuration procedure. The command "
581 "is also propagated to FTM and FAD");
582
583 AddEvent("PRINT")
584 (bind(&StateMachineMCP::Print, this))
585 ("Print the states and connection status of all systems connected to the MCP.");
586 }
587
588 int EvalOptions(Configuration &)
589 {
590 return -1;
591 }
592};
593
594// ------------------------------------------------------------------------
595
596#include "Main.h"
597
598template<class T>
599int RunShell(Configuration &conf)
600{
601 return Main::execute<T, StateMachineMCP>(conf);
602}
603
604/*
605 Extract usage clause(s) [if any] for SYNOPSIS.
606 Translators: "Usage" and "or" here are patterns (regular expressions) which
607 are used to match the usage synopsis in program output. An example from cp
608 (GNU coreutils) which contains both strings:
609 Usage: cp [OPTION]... [-T] SOURCE DEST
610 or: cp [OPTION]... SOURCE... DIRECTORY
611 or: cp [OPTION]... -t DIRECTORY SOURCE...
612 */
613void PrintUsage()
614{
615 cout <<
616 "The ftmctrl controls the FSC (FACT Slow Control) board.\n"
617 "\n"
618 "The default is that the program is started without user intercation. "
619 "All actions are supposed to arrive as DimCommands. Using the -c "
620 "option, a local shell can be initialized. With h or help a short "
621 "help message about the usuage can be brought to the screen.\n"
622 "\n"
623 "Usage: fscctrl [-c type] [OPTIONS]\n"
624 " or: fscctrl [OPTIONS]\n";
625 cout << endl;
626}
627
628void PrintHelp()
629{
630 Main::PrintHelp<StateMachineMCP>();
631
632 /* Additional help text which is printed after the configuration
633 options goes here */
634
635 /*
636 cout << "bla bla bla" << endl << endl;
637 cout << endl;
638 cout << "Environment:" << endl;
639 cout << "environment" << endl;
640 cout << endl;
641 cout << "Examples:" << endl;
642 cout << "test exam" << endl;
643 cout << endl;
644 cout << "Files:" << endl;
645 cout << "files" << endl;
646 cout << endl;
647 */
648}
649
650int main(int argc, const char* argv[])
651{
652 Configuration conf(argv[0]);
653 conf.SetPrintUsage(PrintUsage);
654 Main::SetupConfiguration(conf);
655
656 if (!conf.DoParse(argc, argv, PrintHelp))
657 return 127;
658
659 //try
660 {
661 // No console access at all
662 if (!conf.Has("console"))
663 {
664// if (conf.Get<bool>("no-dim"))
665// return RunShell<LocalStream, StateMachine, ConnectionFSC>(conf);
666// else
667 return RunShell<LocalStream>(conf);
668 }
669 // Cosole access w/ and w/o Dim
670/* if (conf.Get<bool>("no-dim"))
671 {
672 if (conf.Get<int>("console")==0)
673 return RunShell<LocalShell, StateMachine, ConnectionFSC>(conf);
674 else
675 return RunShell<LocalConsole, StateMachine, ConnectionFSC>(conf);
676 }
677 else
678*/ {
679 if (conf.Get<int>("console")==0)
680 return RunShell<LocalShell>(conf);
681 else
682 return RunShell<LocalConsole>(conf);
683 }
684 }
685 /*catch (std::exception& e)
686 {
687 cerr << "Exception: " << e.what() << endl;
688 return -1;
689 }*/
690
691 return 0;
692}
Note: See TracBrowser for help on using the repository browser.