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

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