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

Last change on this file since 13898 was 13847, checked in by tbretz, 13 years ago
Removed obsolete include of DimServiceInfoList
File size: 15.3 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
10#include "tools.h"
11
12#include "LocalControl.h"
13
14#include "HeadersFTM.h"
15#include "HeadersFAD.h"
16
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 enum states_t
35 {
36 kStateDimNetworkNA = 1,
37 kStateDisconnected,
38 kStateConnecting,
39 kStateConnected,
40 kStateIdle,
41 kStateDummy, // Doesn't exist, kept to keep the numbers
42 kStateConfiguring1,
43 kStateConfiguring2,
44 kStateConfiguring3,
45 kStateConfigured,
46 kStateTriggerOn,
47 kStateTakingData,
48// kStateRunInProgress,
49 };
50
51 DimVersion fDim;
52 DimDescribedState fDimFTM;
53 DimDescribedState fDimFAD;
54 DimDescribedState fDimLog;
55 DimDescribedState fDimRC;
56
57 DimDescribedService fService;
58
59 int Print() const
60 {
61 Out() << fDim << endl;
62 Out() << fDimFTM << endl;
63 Out() << fDimFAD << endl;
64 Out() << fDimLog << endl;
65 Out() << fDimRC << endl;
66
67 return GetCurrentState();
68 }
69
70 int GetReady()
71 {
72 return GetCurrentState();
73 }
74
75 int StopRun(const EventImp &)
76 {
77 if (fDimFTM.state()==FTM::kTriggerOn)
78 {
79 Message("Stopping FTM");
80 Dim::SendCommand("FTM_CONTROL/STOP_TRIGGER");
81 }
82
83 // FIXME: Do step 2 only when FTM is stopped
84 if (fDimFAD.state()==FAD::kConnected)
85 {
86 //Dim::SendCommand("FAD_CONTROL/ENABLE_TRIGGER_LINE", bool(false));
87 Message("Stopping FAD");
88 Dim::SendCommand("FAD_CONTROL/ENABLE_CONTINOUS_TRIGGER", bool(false));
89 }
90
91 return GetCurrentState();
92 }
93
94 int Reset(const EventImp &)
95 {
96 fRunType = "";
97 Message("Reseting configuration states of FAD and FTM");
98 Dim::SendCommand("FTM_CONTROL/RESET_CONFIGURE");
99 Dim::SendCommand("FAD_CONTROL/RESET_CONFIGURE");
100 Update(kStateIdle);
101 return kStateIdle;
102 /*
103 // FIMXE: Handle error states!
104 if (fDimLog.state()>=20)//kSM_NightlyOpen
105 Dim::SendCommand("DATA_LOGGER/STOP");
106
107 if (fDimLog.state()==0)
108 Dim::SendCommand("DATA_LOGGER/WAIT_FOR_RUN_NUMBER");
109
110 if (fDimFAD.state()==FAD::kConnected)
111 {
112 Dim::SendCommand("FAD_CONTROL/ENABLE_TRIGGER_LINE", bool(false));
113 Dim::SendCommand("FAD_CONTROL/ENABLE_CONTINOUS_TRIGGER", bool(false));
114 }
115
116 if (fDimFTM.state()==FTM::kTakingData)
117 Dim::SendCommand("FTM_CONTROL/STOP");
118
119 return GetCurrentState(); */
120 }
121
122 int64_t fMaxTime;
123 int64_t fNumEvents;
124 string fRunType;
125
126 int StartRun(const EventImp &evt)
127 {
128 if (fDimFTM.state()==-2)
129 {
130 Error("No connection to ftmcontrol (see PRINT).");
131 return GetCurrentState();
132 }
133 if (fDimFAD.state()==-2)
134 {
135 Warn("No connection to fadcontrol (see PRINT).");
136 return GetCurrentState();
137 }
138 if (fDimLog.state()==-2)
139 {
140 Warn("No connection to datalogger (see PRINT).");
141 return GetCurrentState();
142 }
143 if (fDimRC.state()==-2)
144 {
145 Warn("No connection to ratecontrol (see PRINT).");
146 return GetCurrentState();
147 }
148
149 fMaxTime = evt.Get<int64_t>();
150 fNumEvents = evt.Get<int64_t>(8);
151 fRunType = evt.Ptr<char>(16);
152
153 ostringstream str;
154 str << "Starting configuration '" << fRunType << "' for new run";
155 if (fNumEvents>0 || fMaxTime>0)
156 str << " [";
157 if (fNumEvents>0)
158 str << fNumEvents << " events";
159 if (fNumEvents>0 && fMaxTime>0)
160 str << " / ";
161 if (fMaxTime>0)
162 str << fMaxTime << "s";
163 if (fNumEvents>0 || fMaxTime>0)
164 str << "]";
165 Message(str);
166
167 Update(kStateConfiguring1);
168
169 return kStateConfiguring1;
170 }
171
172 struct Value
173 {
174 uint64_t time;
175 uint64_t nevts;
176 char type[];
177 };
178
179 Value *GetBuffer()
180 {
181 const size_t len = sizeof(Value)+fRunType.length()+1;
182
183 char *buf = new char[len];
184
185 Value *val = reinterpret_cast<Value*>(buf);
186
187 val->time = fMaxTime;
188 val->nevts = fNumEvents;
189
190 strcpy(val->type, fRunType.c_str());
191
192 return val;
193 }
194
195 void Update(int newstate)
196 {
197 Value *buf = GetBuffer();
198 fService.setQuality(newstate);
199 fService.setData(buf, sizeof(Value)+fRunType.length()+1);
200 fService.Update();
201 delete buf;
202 }
203
204 void ConfigureFAD()
205 {
206 Value *buf = GetBuffer();
207
208 Message("Configuring FAD");
209 Dim::SendCommand("FAD_CONTROL/CONFIGURE", buf, sizeof(Value)+fRunType.length()+1);
210
211 delete buf;
212 }
213
214 int Execute()
215 {
216 // Dispatch (execute) at most one handler from the queue. In contrary
217 // to run_one(), it doesn't wait until a handler is available
218 // which can be dispatched, so poll_one() might return with 0
219 // handlers dispatched. The handlers are always dispatched/executed
220 // synchronously, i.e. within the call to poll_one()
221 //poll_one();
222
223 if (!fDim.online())
224 return kStateDimNetworkNA;
225
226 if (fDimFTM.state() >= FTM::kConnected &&
227 fDimFAD.state() >= FAD::kConnected &&
228 fDimLog.state() >= kSM_Ready)
229 {
230 if (GetCurrentState()==kStateConfiguring1)
231 {
232 if (fDimLog.state()<30/*kSM_WaitForRun*/)
233 {
234 Message("Starting datalogger");
235 Dim::SendCommand("DATA_LOGGER/START_RUN_LOGGING");
236 }
237 Message("Configuring Trigger (FTM)");
238 Dim::SendCommand("FTM_CONTROL/CONFIGURE", fRunType);
239 Update(kStateConfiguring2);
240 return kStateConfiguring2;
241 }
242
243 if (GetCurrentState()==kStateConfiguring2)
244 {
245 // FIMXE: Reset in case of error
246 if ((/*fDimFTM.state() != FTM::kConfiguring2 &&*/
247 fDimFTM.state() != FTM::kConfigured) ||
248 fDimLog.state()<30 || fDimLog.state()>0xff)
249 return GetCurrentState();
250
251 // FIMXE: This is to make sure that the rate control
252 // has received the correct trigger setup already...
253 //usleep(1000000);
254
255 Message("Starting Rate Control");
256 Dim::SendCommand("RATE_CONTROL/CALIBRATE");
257
258 ConfigureFAD();
259 Update(kStateConfiguring3);
260 return kStateConfiguring3;
261 }
262
263 if (GetCurrentState()==kStateConfiguring3)
264 {
265 if (fDimFTM.state() != FTM::kConfigured ||
266 fDimFAD.state() != FAD::kConfigured ||
267 fDimRC.state() < 6)
268 return GetCurrentState();
269
270 Message("Starting Trigger (FTM)");
271 Dim::SendCommand("FTM_CONTROL/START_TRIGGER");
272 Update(kStateConfigured);
273 return kStateConfigured;
274 }
275
276 if (GetCurrentState()==kStateConfigured)
277 {
278 if (fDimFTM.state() != FTM::kTriggerOn)
279 return GetCurrentState();
280
281 Update(kStateTriggerOn);
282
283 return kStateTriggerOn;
284 }
285
286 if (GetCurrentState()==kStateTriggerOn)
287 {
288 if (fDimFAD.state() != FAD::kWritingData)
289 return GetCurrentState();
290
291 Update(kStateTakingData);
292
293 return kStateTakingData;
294 }
295
296 if (GetCurrentState()==kStateTakingData)
297 {
298 if (fDimFTM.state()==FTM::kTriggerOn &&
299 fDimFAD.state()==FAD::kWritingData)
300 return kStateTakingData;
301
302 Update(kStateIdle);
303 }
304
305 return kStateIdle;
306 }
307
308 /*
309 if (fDimFTM.state() >= FTM::kConnected &&
310 fDimFAD.state() >= FAD::kConnected &&
311 fDimLog.state() >= kSM_Ready)
312 return kStateIdle;
313 */
314 if (fDimFTM.state() >-2 &&
315 fDimFAD.state() >-2 &&
316 fDimLog.state() >-2 &&
317 fDimRC.state() >-2)
318 return kStateConnected;
319
320 if (fDimFTM.state() >-2 ||
321 fDimFAD.state() >-2 ||
322 fDimLog.state() >-2 ||
323 fDimRC.state() >-2)
324 return kStateConnecting;
325
326 return kStateDisconnected;
327 }
328
329public:
330 StateMachineMCP(ostream &out=cout) : StateMachineDim(out, "MCP"),
331 fDimFTM("FTM_CONTROL"),
332 fDimFAD("FAD_CONTROL"),
333 fDimLog("DATA_LOGGER"),
334 fDimRC("RATE_CONTROL"),
335 fService("MCP/CONFIGURATION", "X:1;X:1;C", "Run configuration information"
336 "|MaxTime[s]:Maximum time before the run gets stopped"
337 "|MaxEvents[num]:Maximum number of events before the run gets stopped"
338 "|Name[text]:Name of the chosen configuration")
339 {
340 // ba::io_service::work is a kind of keep_alive for the loop.
341 // It prevents the io_service to go to stopped state, which
342 // would prevent any consecutive calls to run()
343 // or poll() to do nothing. reset() could also revoke to the
344 // previous state but this might introduce some overhead of
345 // deletion and creation of threads and more.
346
347 fDim.Subscribe(*this);
348 fDimFTM.Subscribe(*this);
349 fDimFAD.Subscribe(*this);
350 fDimLog.Subscribe(*this);
351 fDimRC.Subscribe(*this);
352
353 // State names
354 AddStateName(kStateDimNetworkNA, "DimNetworkNotAvailable",
355 "DIM dns server not available.");
356
357 AddStateName(kStateDisconnected, "Disconnected",
358 "Neither ftmctrl, fadctrl, datalogger nor rate control online.");
359
360 AddStateName(kStateConnecting, "Connecting",
361 "Either ftmctrl, fadctrl, datalogger or rate control not online.");
362
363 AddStateName(kStateConnected, "Connected",
364 "All needed subsystems online.");
365
366 AddStateName(kStateIdle, "Idle",
367 "Waiting for next configuration command");
368
369 AddStateName(kStateConfiguring1, "Configuring1",
370 "Starting configuration procedure, checking Datalogger state");
371
372 AddStateName(kStateConfiguring2, "Configuring2",
373 "Waiting for FTM and Datalogger to get ready");
374
375 AddStateName(kStateConfiguring3, "Configuring3",
376 "Waiting for FADs and rate control to get ready");
377
378 AddStateName(kStateConfigured, "Configured",
379 "Everything is configured, trigger will be switched on now");
380
381 AddStateName(kStateTriggerOn, "TriggerOn",
382 "The trigger is switched on, waiting for FAD to receive data");
383
384 AddStateName(kStateTakingData, "TakingData",
385 "The trigger is switched on, FADs are sending data");
386
387
388 AddEvent("START", "X:2;C")//, kStateIdle)
389 (bind(&StateMachineMCP::StartRun, this, placeholders::_1))
390 ("Start the configuration and data taking for a run-type of a pre-defined setup"
391 "|TimeMax[s]:Maximum number of seconds before the run will be closed automatically"
392 "|NumMax[count]:Maximum number events before the run will be closed automatically"
393 "|Name[text]:Name of the configuration to be used for taking data");
394
395 AddEvent("STOP")
396 (bind(&StateMachineMCP::StopRun, this, placeholders::_1))
397 ("Stops the trigger (either disables the FTM trigger or the internal DRS trigger)");
398
399 AddEvent("RESET", kStateConfiguring1, kStateConfiguring2, kStateConfiguring3, kStateConfigured)
400 (bind(&StateMachineMCP::Reset, this, placeholders::_1))
401 ("If a configuration blockes because a system cannot configure itself properly, "
402 "this command can be called to leave the configuration procedure. The command "
403 "is also propagated to FTM and FAD");
404
405 AddEvent("PRINT")
406 (bind(&StateMachineMCP::Print, this))
407 ("Print the states and connection status of all systems connected to the MCP.");
408 }
409
410 int EvalOptions(Configuration &)
411 {
412 return -1;
413 }
414};
415
416// ------------------------------------------------------------------------
417
418#include "Main.h"
419
420template<class T>
421int RunShell(Configuration &conf)
422{
423 return Main::execute<T, StateMachineMCP>(conf);
424}
425
426/*
427 Extract usage clause(s) [if any] for SYNOPSIS.
428 Translators: "Usage" and "or" here are patterns (regular expressions) which
429 are used to match the usage synopsis in program output. An example from cp
430 (GNU coreutils) which contains both strings:
431 Usage: cp [OPTION]... [-T] SOURCE DEST
432 or: cp [OPTION]... SOURCE... DIRECTORY
433 or: cp [OPTION]... -t DIRECTORY SOURCE...
434 */
435void PrintUsage()
436{
437 cout <<
438 "The ftmctrl controls the FSC (FACT Slow Control) board.\n"
439 "\n"
440 "The default is that the program is started without user intercation. "
441 "All actions are supposed to arrive as DimCommands. Using the -c "
442 "option, a local shell can be initialized. With h or help a short "
443 "help message about the usuage can be brought to the screen.\n"
444 "\n"
445 "Usage: fscctrl [-c type] [OPTIONS]\n"
446 " or: fscctrl [OPTIONS]\n";
447 cout << endl;
448}
449
450void PrintHelp()
451{
452 Main::PrintHelp<StateMachineMCP>();
453
454 /* Additional help text which is printed after the configuration
455 options goes here */
456
457 /*
458 cout << "bla bla bla" << endl << endl;
459 cout << endl;
460 cout << "Environment:" << endl;
461 cout << "environment" << endl;
462 cout << endl;
463 cout << "Examples:" << endl;
464 cout << "test exam" << endl;
465 cout << endl;
466 cout << "Files:" << endl;
467 cout << "files" << endl;
468 cout << endl;
469 */
470}
471
472int main(int argc, const char* argv[])
473{
474 Configuration conf(argv[0]);
475 conf.SetPrintUsage(PrintUsage);
476 Main::SetupConfiguration(conf);
477
478 if (!conf.DoParse(argc, argv, PrintHelp))
479 return -1;
480
481 //try
482 {
483 // No console access at all
484 if (!conf.Has("console"))
485 {
486// if (conf.Get<bool>("no-dim"))
487// return RunShell<LocalStream, StateMachine, ConnectionFSC>(conf);
488// else
489 return RunShell<LocalStream>(conf);
490 }
491 // Cosole access w/ and w/o Dim
492/* if (conf.Get<bool>("no-dim"))
493 {
494 if (conf.Get<int>("console")==0)
495 return RunShell<LocalShell, StateMachine, ConnectionFSC>(conf);
496 else
497 return RunShell<LocalConsole, StateMachine, ConnectionFSC>(conf);
498 }
499 else
500*/ {
501 if (conf.Get<int>("console")==0)
502 return RunShell<LocalShell>(conf);
503 else
504 return RunShell<LocalConsole>(conf);
505 }
506 }
507 /*catch (std::exception& e)
508 {
509 cerr << "Exception: " << e.what() << endl;
510 return -1;
511 }*/
512
513 return 0;
514}
Note: See TracBrowser for help on using the repository browser.