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

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