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

Last change on this file since 14001 was 13916, checked in by tbretz, 12 years ago
Replaced Execute by callbacks and moved state definition to own header file and namespace.
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 -1;
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.