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

Last change on this file since 13220 was 13190, checked in by tbretz, 13 years ago
Propagate max number of events and time correctly as signed int.
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 int64_t fMaxTime;
231 int64_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 ConfigureFAD();
327 return kStateConfiguring3;
328 }
329
330 if (GetCurrentState()==kStateConfiguring3)
331 {
332 if (fStatusFTM.second != FTM::kConfigured ||
333 fStatusFAD.second != FAD::kConfigured ||
334 fStatusRC.second < 6)
335 return GetCurrentState();
336
337 Message("Starting Trigger (FTM)");
338 Dim::SendCommand("FTM_CONTROL/START_TRIGGER");
339 return kStateConfigured;
340 }
341
342 if (GetCurrentState()==kStateConfigured)
343 {
344 if (fStatusFTM.second != FTM::kTriggerOn)
345 return GetCurrentState();
346
347 // Now we are taking data... we could now wait for
348 // the fad to go back to -1
349 }
350
351 return kStateIdle;
352 }
353
354 /*
355 if (fStatusFTM.second >= FTM::kConnected &&
356 fStatusFAD.second >= FAD::kConnected &&
357 fStatusLog.second >= kSM_Ready)
358 return kStateIdle;
359 */
360 if (fStatusFTM.second >-2 &&
361 fStatusFAD.second >-2 &&
362 fStatusLog.second >-2 &&
363 fStatusRC.second >-2)
364 return kStateConnected;
365
366 if (fStatusFTM.second >-2 ||
367 fStatusFAD.second >-2 ||
368 fStatusLog.second >-2 ||
369 fStatusRC.second >-2)
370 return kStateConnecting;
371
372 return kStateDisconnected;
373 }
374
375public:
376 StateMachineMCP(ostream &out=cout) : StateMachineDim(out, "MCP"),
377 fStatusDim(make_pair(Time(), -2)),
378 fStatusFTM(make_pair(Time(), -2)),
379 fStatusFAD(make_pair(Time(), -2)),
380 fStatusLog(make_pair(Time(), -2)),
381 fDim("DIS_DNS/VERSION_NUMBER", (void*)NULL, 0, this),
382 fFTM("FTM_CONTROL/STATE", (void*)NULL, 0, this),
383 fFAD("FAD_CONTROL/STATE", (void*)NULL, 0, this),
384 fLog("DATA_LOGGER/STATE", (void*)NULL, 0, this),
385 fRC("RATE_CONTROL/STATE", (void*)NULL, 0, this)
386 {
387 // ba::io_service::work is a kind of keep_alive for the loop.
388 // It prevents the io_service to go to stopped state, which
389 // would prevent any consecutive calls to run()
390 // or poll() to do nothing. reset() could also revoke to the
391 // previous state but this might introduce some overhead of
392 // deletion and creation of threads and more.
393
394 // State names
395 AddStateName(kStateDimNetworkNA, "DimNetworkNotAvailable",
396 "DIM dns server not available.");
397
398 AddStateName(kStateDisconnected, "Disconnected",
399 "Neither ftmctrl, fadctrl, datalogger nor rate control online.");
400
401 AddStateName(kStateConnecting, "Connecting",
402 "Either ftmctrl, fadctrl, datalogger or rate control not online.");
403
404 AddStateName(kStateConnected, "Connected",
405 "All needed subsystems online.");
406
407 AddStateName(kStateIdle, "Idle",
408 ".");
409
410 AddStateName(kStateReadyForDataTaking, "ReadyForDataTaking",
411 ".");
412
413 AddStateName(kStateConfiguring1, "Configuring1",
414 ".");
415
416 AddStateName(kStateConfiguring2, "Configuring2",
417 "Waiting for FTM and Datalogger to get ready");
418
419 AddStateName(kStateConfiguring3, "Configuring3",
420 "Waiting for FAD to get ready");
421
422 AddStateName(kStateConfigured, "Configured",
423 ".");
424
425
426 AddEvent("START", "X:2;C")//, kStateIdle)
427 (bind(&StateMachineMCP::StartRun, this, placeholders::_1))
428 ("");
429
430 AddEvent("STOP")
431 (bind(&StateMachineMCP::StopRun, this, placeholders::_1))
432 ("");
433
434 AddEvent("RESET", kStateConfiguring1, kStateConfiguring2, kStateConfiguring3, kStateConfigured)
435 (bind(&StateMachineMCP::Reset, this, placeholders::_1))
436 ("");
437
438 // Verbosity commands
439 AddEvent("SET_VERBOSE", "B:1")
440 (bind(&StateMachineMCP::SetVerbosity, this, placeholders::_1))
441 ("set verbosity state"
442 "|verbosity[bool]:disable or enable verbosity for received data (yes/no), except dynamic data");
443
444 AddEvent("PRINT")
445 (bind(&StateMachineMCP::Print, this))
446 ("");
447 }
448
449 int EvalOptions(Configuration &)
450 {
451 //SetEndpoint(conf.Get<string>("addr"));
452
453 //fFSC.SetVerbose(!conf.Get<bool>("quiet"));
454
455 return -1;
456 }
457};
458
459// ------------------------------------------------------------------------
460
461#include "Main.h"
462
463template<class T>
464int RunShell(Configuration &conf)
465{
466 return Main::execute<T, StateMachineMCP>(conf);
467}
468
469/*
470 Extract usage clause(s) [if any] for SYNOPSIS.
471 Translators: "Usage" and "or" here are patterns (regular expressions) which
472 are used to match the usage synopsis in program output. An example from cp
473 (GNU coreutils) which contains both strings:
474 Usage: cp [OPTION]... [-T] SOURCE DEST
475 or: cp [OPTION]... SOURCE... DIRECTORY
476 or: cp [OPTION]... -t DIRECTORY SOURCE...
477 */
478void PrintUsage()
479{
480 cout <<
481 "The ftmctrl controls the FSC (FACT Slow Control) board.\n"
482 "\n"
483 "The default is that the program is started without user intercation. "
484 "All actions are supposed to arrive as DimCommands. Using the -c "
485 "option, a local shell can be initialized. With h or help a short "
486 "help message about the usuage can be brought to the screen.\n"
487 "\n"
488 "Usage: fscctrl [-c type] [OPTIONS]\n"
489 " or: fscctrl [OPTIONS]\n";
490 cout << endl;
491}
492
493void PrintHelp()
494{
495 Main::PrintHelp<StateMachineMCP>();
496
497 /* Additional help text which is printed after the configuration
498 options goes here */
499
500 /*
501 cout << "bla bla bla" << endl << endl;
502 cout << endl;
503 cout << "Environment:" << endl;
504 cout << "environment" << endl;
505 cout << endl;
506 cout << "Examples:" << endl;
507 cout << "test exam" << endl;
508 cout << endl;
509 cout << "Files:" << endl;
510 cout << "files" << endl;
511 cout << endl;
512 */
513}
514
515int main(int argc, const char* argv[])
516{
517 Configuration conf(argv[0]);
518 conf.SetPrintUsage(PrintUsage);
519 Main::SetupConfiguration(conf);
520
521 if (!conf.DoParse(argc, argv, PrintHelp))
522 return -1;
523
524 //try
525 {
526 // No console access at all
527 if (!conf.Has("console"))
528 {
529// if (conf.Get<bool>("no-dim"))
530// return RunShell<LocalStream, StateMachine, ConnectionFSC>(conf);
531// else
532 return RunShell<LocalStream>(conf);
533 }
534 // Cosole access w/ and w/o Dim
535/* if (conf.Get<bool>("no-dim"))
536 {
537 if (conf.Get<int>("console")==0)
538 return RunShell<LocalShell, StateMachine, ConnectionFSC>(conf);
539 else
540 return RunShell<LocalConsole, StateMachine, ConnectionFSC>(conf);
541 }
542 else
543*/ {
544 if (conf.Get<int>("console")==0)
545 return RunShell<LocalShell>(conf);
546 else
547 return RunShell<LocalConsole>(conf);
548 }
549 }
550 /*catch (std::exception& e)
551 {
552 cerr << "Exception: " << e.what() << endl;
553 return -1;
554 }*/
555
556 return 0;
557}
Note: See TracBrowser for help on using the repository browser.