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

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