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

Last change on this file since 12686 was 12526, checked in by tbretz, 13 years ago
Added descriptions for some states.
File size: 15.7 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// kStateRunInProgress,
59 };
60
61 DimServiceInfoList fNetwork;
62
63 pair<Time, int> fStatusDim;
64 pair<Time, int> fStatusFTM;
65 pair<Time, int> fStatusFAD;
66 pair<Time, int> fStatusLog;
67 pair<Time, int> fStatusRC;
68
69 DimStampedInfo fDim;
70 DimStampedInfo fFTM;
71 DimStampedInfo fFAD;
72 DimStampedInfo fLog;
73 DimStampedInfo fRC;
74
75 pair<Time, int> GetNewState(DimStampedInfo &info) const
76 {
77 const bool disconnected = info.getSize()==0;
78
79 // Make sure getTimestamp is called _before_ getTimestampMillisecs
80 const int tsec = info.getTimestamp();
81 const int tms = info.getTimestampMillisecs();
82
83 return make_pair(Time(tsec, tms*1000),
84 disconnected ? -2 : info.getQuality());
85 }
86
87 void infoHandler()
88 {
89 DimInfo *curr = getInfo(); // get current DimInfo address
90 if (!curr)
91 return;
92
93 if (curr==&fFTM)
94 {
95 fStatusFTM = GetNewState(fFTM);
96 return;
97 }
98
99 if (curr==&fFAD)
100 {
101 fStatusFAD = GetNewState(fFAD);
102 return;
103 }
104
105 if (curr==&fLog)
106 {
107 fStatusLog = GetNewState(fLog);
108 return;
109 }
110
111 if (curr==&fRC)
112 {
113 fStatusRC = GetNewState(fRC);
114 return;
115 }
116
117 if (curr==&fDim)
118 {
119 fStatusDim = GetNewState(fDim);
120 fStatusDim.second = curr->getSize()==4 ? curr->getInt() : 0;
121 return;
122 }
123
124 }
125
126 bool CheckEventSize(size_t has, const char *name, size_t size)
127 {
128 if (has==size)
129 return true;
130
131 ostringstream msg;
132 msg << name << " - Received event has " << has << " bytes, but expected " << size << ".";
133 Fatal(msg);
134 return false;
135 }
136
137 int SetVerbosity(const EventImp &)
138 {
139 /*
140 if (!CheckEventSize(evt.GetSize(), "SetVerbosity", 1))
141 return T::kSM_FatalError;
142
143 fFSC.SetVerbose(evt.GetBool());
144
145 */
146
147 return GetCurrentState();
148 }
149
150
151 void PrintState(const pair<Time,int> &state, const char *server)
152 {
153 const State rc = fNetwork.GetState(server, state.second);
154
155 Out() << state.first.GetAsStr("%H:%M:%S.%f").substr(0, 12) << " - ";
156 Out() << kBold << server << ": ";
157 Out() << rc.name << "[" << rc.index << "]";
158 Out() << kReset << " - " << kBlue << rc.comment << endl;
159 }
160
161 int Print()
162 {
163 Out() << fStatusDim.first.GetAsStr("%H:%M:%S.%f").substr(0, 12) << " - ";
164 Out() << kBold << "DIM_DNS: ";
165 if (fStatusDim.second==0)
166 Out() << "Offline" << endl;
167 else
168 Out() << "V" << fStatusDim.second/100 << 'r' << fStatusDim.second%100 << endl;
169
170 PrintState(fStatusFTM, "FTM_CONTROL");
171 PrintState(fStatusFAD, "FAD_CONTROL");
172 PrintState(fStatusLog, "DATA_LOGGER");
173 PrintState(fStatusRC, "RATE_CONTROL");
174
175 return GetCurrentState();
176 }
177
178 int GetReady()
179 {
180
181 return GetCurrentState();
182 }
183
184 int StopRun(const EventImp &)
185 {
186 if (fStatusFTM.second==FTM::kTriggerOn)
187 {
188 Message("Stopping FTM");
189 Dim::SendCommand("FTM_CONTROL/STOP_TRIGGER");
190 }
191
192 // FIXME: Do step 2 only when FTM is stopped
193 if (fStatusFAD.second==FAD::kConnected)
194 {
195 //Dim::SendCommand("FAD_CONTROL/ENABLE_TRIGGER_LINE", bool(false));
196 Message("Stopping FAD");
197 Dim::SendCommand("FAD_CONTROL/ENABLE_CONTINOUS_TRIGGER", bool(false));
198 }
199
200 return GetCurrentState();
201 }
202
203 int Reset(const EventImp &)
204 {
205 fRunType = "";
206 Message("Reseting configuration states of FAD and FTM");
207 Dim::SendCommand("FTM_CONTROL/RESET_CONFIGURE");
208 Dim::SendCommand("FAD_CONTROL/RESET_CONFIGURE");
209 return kStateIdle;
210 /*
211 // FIMXE: Handle error states!
212 if (fStatusLog.second>=20)//kSM_NightlyOpen
213 Dim::SendCommand("DATA_LOGGER/STOP");
214
215 if (fStatusLog.second==0)
216 Dim::SendCommand("DATA_LOGGER/WAIT_FOR_RUN_NUMBER");
217
218 if (fStatusFAD.second==FAD::kConnected)
219 {
220 Dim::SendCommand("FAD_CONTROL/ENABLE_TRIGGER_LINE", bool(false));
221 Dim::SendCommand("FAD_CONTROL/ENABLE_CONTINOUS_TRIGGER", bool(false));
222 }
223
224 if (fStatusFTM.second==FTM::kTakingData)
225 Dim::SendCommand("FTM_CONTROL/STOP");
226
227 return GetCurrentState(); */
228 }
229
230 uint64_t fMaxTime;
231 uint64_t fNumEvents;
232 string fRunType;
233
234 int StartRun(const EventImp &evt)
235 {
236 fMaxTime = evt.Get<int64_t>();
237 fNumEvents = evt.Get<int64_t>(8);
238 fRunType = evt.Ptr<char>(16);
239
240 ostringstream str;
241 str << "Starting configuration '" << fRunType << "' for new run";
242 if (fNumEvents>0 || fMaxTime>0)
243 str << " [";
244 if (fNumEvents>0)
245 str << fNumEvents << " events";
246 if (fNumEvents>0 && fMaxTime>0)
247 str << " / ";
248 if (fMaxTime>0)
249 str << fMaxTime << "s";
250 if (fNumEvents>0 || fMaxTime>0)
251 str << "]";
252 Message(str);
253
254 return kStateConfiguring1;
255 }
256
257 void ConfigureFAD()
258 {
259 struct Value
260 {
261 uint64_t time;
262 uint64_t nevts;
263 char type[];
264 };
265
266 const size_t len = sizeof(Value)+fRunType.length()+1;
267
268 char *buf = new char[len];
269
270 Value *val = reinterpret_cast<Value*>(buf);
271
272 val->time = fMaxTime;
273 val->nevts = fNumEvents;
274
275 strcpy(val->type, fRunType.c_str());
276
277 Message("Configuring FAD");
278 Dim::SendCommand("FAD_CONTROL/CONFIGURE", buf, len);
279
280 delete buf;
281 }
282
283 int Execute()
284 {
285 // Dispatch (execute) at most one handler from the queue. In contrary
286 // to run_one(), it doesn't wait until a handler is available
287 // which can be dispatched, so poll_one() might return with 0
288 // handlers dispatched. The handlers are always dispatched/executed
289 // synchronously, i.e. within the call to poll_one()
290 //poll_one();
291
292 if (fStatusDim.second==0)
293 return kStateDimNetworkNA;
294
295 if (fStatusFTM.second >= FTM::kConnected &&
296 fStatusFAD.second >= FAD::kConnected &&
297 fStatusLog.second >= kSM_Ready)
298 {
299 if (GetCurrentState()==kStateConfiguring1)
300 {
301 if (fStatusLog.second<30/*kSM_WaitForRun*/)
302 {
303 Message("Starting datalogger");
304 Dim::SendCommand("DATA_LOGGER/START_RUN_LOGGING");
305 }
306 Message("Configuring Trigger (FTM)");
307 Dim::SendCommand("FTM_CONTROL/CONFIGURE", fRunType);
308 return kStateConfiguring2;
309 }
310
311 if (GetCurrentState()==kStateConfiguring2)
312 {
313 // FIMXE: Reset in case of error
314 if ((/*fStatusFTM.second != FTM::kConfiguring2 &&*/
315 fStatusFTM.second != FTM::kConfigured) ||
316 fStatusLog.second<30 || fStatusLog.second>0xff)
317 return GetCurrentState();
318
319 // FIMXE: This is to make sure that the rate control
320 // has received the correct trigger setup already...
321 //usleep(1000000);
322
323 Message("Starting Rate Control");
324 Dim::SendCommand("RATE_CONTROL/CALIBRATE");
325
326 Message("Starting FAD");
327 ConfigureFAD();
328 return kStateConfiguring3;
329 }
330
331 if (GetCurrentState()==kStateConfiguring3)
332 {
333 if (fStatusFTM.second != FTM::kConfigured ||
334 fStatusFAD.second != FAD::kConfigured ||
335 fStatusRC.second < 6)
336 return GetCurrentState();
337
338 Message("Starting Trigger (FTM)");
339 Dim::SendCommand("FTM_CONTROL/START_TRIGGER");
340 return kStateConfigured;
341 }
342
343 if (GetCurrentState()==kStateConfigured)
344 {
345 if (fStatusFTM.second != FTM::kTriggerOn)
346 return GetCurrentState();
347
348 // Now we are taking data... we could now wait for
349 // the fad to go back to -1
350 }
351
352 return kStateIdle;
353 }
354
355 /*
356 if (fStatusFTM.second >= FTM::kConnected &&
357 fStatusFAD.second >= FAD::kConnected &&
358 fStatusLog.second >= kSM_Ready)
359 return kStateIdle;
360 */
361 if (fStatusFTM.second >-2 &&
362 fStatusFAD.second >-2 &&
363 fStatusLog.second >-2 &&
364 fStatusRC.second >-2)
365 return kStateConnected;
366
367 if (fStatusFTM.second >-2 ||
368 fStatusFAD.second >-2 ||
369 fStatusLog.second >-2 ||
370 fStatusRC.second >-2)
371 return kStateConnecting;
372
373 return kStateDisconnected;
374 }
375
376public:
377 StateMachineMCP(ostream &out=cout) : StateMachineDim(out, "MCP"),
378 fStatusDim(make_pair(Time(), -2)),
379 fStatusFTM(make_pair(Time(), -2)),
380 fStatusFAD(make_pair(Time(), -2)),
381 fStatusLog(make_pair(Time(), -2)),
382 fDim("DIS_DNS/VERSION_NUMBER", (void*)NULL, 0, this),
383 fFTM("FTM_CONTROL/STATE", (void*)NULL, 0, this),
384 fFAD("FAD_CONTROL/STATE", (void*)NULL, 0, this),
385 fLog("DATA_LOGGER/STATE", (void*)NULL, 0, this),
386 fRC("RATE_CONTROL/STATE", (void*)NULL, 0, this)
387 {
388 // ba::io_service::work is a kind of keep_alive for the loop.
389 // It prevents the io_service to go to stopped state, which
390 // would prevent any consecutive calls to run()
391 // or poll() to do nothing. reset() could also revoke to the
392 // previous state but this might introduce some overhead of
393 // deletion and creation of threads and more.
394
395 // State names
396 AddStateName(kStateDimNetworkNA, "DimNetworkNotAvailable",
397 "DIM dns server not available.");
398
399 AddStateName(kStateDisconnected, "Disconnected",
400 "Neither ftmctrl, fadctrl, datalogger nor rate control online.");
401
402 AddStateName(kStateConnecting, "Connecting",
403 "Either ftmctrl, fadctrl, datalogger or rate control not online.");
404
405 AddStateName(kStateConnected, "Connected",
406 "All needed subsystems online.");
407
408 AddStateName(kStateIdle, "Idle",
409 ".");
410
411 AddStateName(kStateReadyForDataTaking, "ReadyForDataTaking",
412 ".");
413
414 AddStateName(kStateConfiguring1, "Configuring1",
415 ".");
416
417 AddStateName(kStateConfiguring2, "Configuring2",
418 "Waiting for FTM and Datalogger to get ready");
419
420 AddStateName(kStateConfiguring3, "Configuring3",
421 "Waiting for FAD to get ready");
422
423 AddStateName(kStateConfigured, "Configured",
424 ".");
425
426
427 AddEvent("START", "X:2;C")//, kStateIdle)
428 (bind(&StateMachineMCP::StartRun, this, placeholders::_1))
429 ("");
430
431 AddEvent("STOP")
432 (bind(&StateMachineMCP::StopRun, this, placeholders::_1))
433 ("");
434
435 AddEvent("RESET", kStateConfiguring1, kStateConfiguring2, kStateConfiguring3, kStateConfigured)
436 (bind(&StateMachineMCP::Reset, this, placeholders::_1))
437 ("");
438
439 // Verbosity commands
440 AddEvent("SET_VERBOSE", "B:1")
441 (bind(&StateMachineMCP::SetVerbosity, this, placeholders::_1))
442 ("set verbosity state"
443 "|verbosity[bool]:disable or enable verbosity for received data (yes/no), except dynamic data");
444
445 AddEvent("PRINT")
446 (bind(&StateMachineMCP::Print, this))
447 ("");
448 }
449
450 int EvalOptions(Configuration &)
451 {
452 //SetEndpoint(conf.Get<string>("addr"));
453
454 //fFSC.SetVerbose(!conf.Get<bool>("quiet"));
455
456 return -1;
457 }
458};
459
460// ------------------------------------------------------------------------
461
462#include "Main.h"
463
464template<class T>
465int RunShell(Configuration &conf)
466{
467 return Main::execute<T, StateMachineMCP>(conf);
468}
469
470/*
471 Extract usage clause(s) [if any] for SYNOPSIS.
472 Translators: "Usage" and "or" here are patterns (regular expressions) which
473 are used to match the usage synopsis in program output. An example from cp
474 (GNU coreutils) which contains both strings:
475 Usage: cp [OPTION]... [-T] SOURCE DEST
476 or: cp [OPTION]... SOURCE... DIRECTORY
477 or: cp [OPTION]... -t DIRECTORY SOURCE...
478 */
479void PrintUsage()
480{
481 cout <<
482 "The ftmctrl controls the FSC (FACT Slow Control) board.\n"
483 "\n"
484 "The default is that the program is started without user intercation. "
485 "All actions are supposed to arrive as DimCommands. Using the -c "
486 "option, a local shell can be initialized. With h or help a short "
487 "help message about the usuage can be brought to the screen.\n"
488 "\n"
489 "Usage: fscctrl [-c type] [OPTIONS]\n"
490 " or: fscctrl [OPTIONS]\n";
491 cout << endl;
492}
493
494void PrintHelp()
495{
496 Main::PrintHelp<StateMachineMCP>();
497
498 /* Additional help text which is printed after the configuration
499 options goes here */
500
501 /*
502 cout << "bla bla bla" << endl << endl;
503 cout << endl;
504 cout << "Environment:" << endl;
505 cout << "environment" << endl;
506 cout << endl;
507 cout << "Examples:" << endl;
508 cout << "test exam" << endl;
509 cout << endl;
510 cout << "Files:" << endl;
511 cout << "files" << endl;
512 cout << endl;
513 */
514}
515
516int main(int argc, const char* argv[])
517{
518 Configuration conf(argv[0]);
519 conf.SetPrintUsage(PrintUsage);
520 Main::SetupConfiguration(conf);
521
522 if (!conf.DoParse(argc, argv, PrintHelp))
523 return -1;
524
525 //try
526 {
527 // No console access at all
528 if (!conf.Has("console"))
529 {
530// if (conf.Get<bool>("no-dim"))
531// return RunShell<LocalStream, StateMachine, ConnectionFSC>(conf);
532// else
533 return RunShell<LocalStream>(conf);
534 }
535 // Cosole access w/ and w/o Dim
536/* if (conf.Get<bool>("no-dim"))
537 {
538 if (conf.Get<int>("console")==0)
539 return RunShell<LocalShell, StateMachine, ConnectionFSC>(conf);
540 else
541 return RunShell<LocalConsole, StateMachine, ConnectionFSC>(conf);
542 }
543 else
544*/ {
545 if (conf.Get<int>("console")==0)
546 return RunShell<LocalShell>(conf);
547 else
548 return RunShell<LocalConsole>(conf);
549 }
550 }
551 /*catch (std::exception& e)
552 {
553 cerr << "Exception: " << e.what() << endl;
554 return -1;
555 }*/
556
557 return 0;
558}
Note: See TracBrowser for help on using the repository browser.