source: trunk/FACT++/src/ratescan.cc@ 12650

Last change on this file since 12650 was 12555, checked in by tbretz, 13 years ago
Added the UNIX start-time to the report.
File size: 18.7 KB
Line 
1#include <valarray>
2
3#include "Dim.h"
4#include "Event.h"
5#include "Shell.h"
6#include "StateMachineDim.h"
7#include "Connection.h"
8#include "Configuration.h"
9#include "Console.h"
10#include "Converter.h"
11#include "DimServiceInfoList.h"
12//#include "PixelMap.h"
13
14#include "tools.h"
15
16#include "LocalControl.h"
17
18#include "HeadersFTM.h"
19
20namespace ba = boost::asio;
21namespace bs = boost::system;
22namespace dummy = ba::placeholders;
23
24using namespace std;
25
26// ------------------------------------------------------------------------
27
28#include "DimDescriptionService.h"
29
30// ------------------------------------------------------------------------
31
32class StateMachineRateScan : public StateMachineDim, public DimInfoHandler
33{
34 /*
35 int Wrap(boost::function<void()> f)
36 {
37 f();
38 return T::GetCurrentState();
39 }
40
41 boost::function<int(const EventImp &)> Wrapper(boost::function<void()> func)
42 {
43 return bind(&StateMachineMCP::Wrap, this, func);
44 }*/
45
46private:
47 enum states_t
48 {
49 kStateDimNetworkNA = 1,
50 kStateDisconnected,
51 kStateConnecting,
52 kStateConnected,
53 kStateInProgress,
54 };
55
56// PixelMap fMap;
57
58 DimServiceInfoList fNetwork;
59
60 pair<Time, int> fStatusDim;
61 pair<Time, int> fStatusFTM;
62
63 DimStampedInfo fDim;
64 DimStampedInfo fFTM;
65 DimStampedInfo fRates;
66
67 DimDescribedService fDimData;
68 DimDescribedService fDimProc;
69
70 int fCounter;
71 int fSeconds;
72
73 int fSecondsMax;
74 int fThresholdMin;
75 int fThresholdMax;
76 int fThresholdStep;
77
78 double fRate;
79 double fRateBoard[40];
80 double fRatePatch[160];
81
82 double fOnTime;
83
84 uint64_t fStartTime;
85
86 float fResolution;
87
88 enum reference_t
89 {
90 kCamera,
91 kBoard,
92 kPatch
93 };
94
95 reference_t fReference;
96 uint16_t fReferenceIdx;
97
98 string fCommand;
99
100 void UpdateProc()
101 {
102 const array<uint32_t,3> v = {{ fThresholdMin, fThresholdMax, fThresholdStep }};
103 fDimProc.Update(v);
104 }
105
106 pair<Time, int> GetNewState(DimStampedInfo &info) const
107 {
108 const bool disconnected = info.getSize()==0;
109
110 // Make sure getTimestamp is called _before_ getTimestampMillisecs
111 const int tsec = info.getTimestamp();
112 const int tms = info.getTimestampMillisecs();
113
114 return make_pair(Time(tsec, tms*1000),
115 disconnected ? -2 : info.getQuality());
116 }
117
118 bool CheckEventSize(size_t has, const char *name, size_t size)
119 {
120 if (has==size)
121 return true;
122
123 if (has==0)
124 return false;
125
126 ostringstream msg;
127 msg << name << " - Received event has " << has << " bytes, but expected " << size << ".";
128 Fatal(msg);
129 return false;
130 }
131
132 void infoHandler()
133 {
134 DimInfo *curr = getInfo(); // get current DimInfo address
135 if (!curr)
136 return;
137
138 if (curr==&fFTM)
139 {
140 fStatusFTM = GetNewState(fFTM);
141 return;
142 }
143
144 if (curr==&fDim)
145 {
146 fStatusDim = GetNewState(fDim);
147 fStatusDim.second = curr->getSize()==4 ? curr->getInt() : 0;
148 return;
149 }
150
151 if (curr==&fRates)
152 {
153 if (!CheckEventSize(curr->getSize(), "infoHandler[DimTriggerRates]", sizeof(FTM::DimTriggerRates)))
154 return;
155
156 if (fCounter<0/* || fStatusFTM.second!=FTM::kTakingData*/)
157 return;
158
159 const FTM::DimTriggerRates &sdata = *static_cast<FTM::DimTriggerRates*>(curr->getData());
160
161 if (++fSeconds<0)
162 return;
163
164 if (fSeconds==0)
165 {
166 fRate = 0;
167
168 memset(fRateBoard, 0, 40*sizeof(double));
169 memset(fRatePatch, 0, 160*sizeof(double));
170
171 fOnTime = 0;
172 return;
173 }
174
175 if (sdata.fTriggerRate==0)
176 {
177 Message("Rate scan stopped due zero trigger rate.");
178 fCounter = -1;
179 return;
180 }
181
182 fRate += sdata.fTriggerRate;
183 for (int i=0; i<40; i++)
184 fRateBoard[i] += sdata.fBoardRate[i];
185 for (int i=0; i<160; i++)
186 fRatePatch[i] += sdata.fPatchRate[i];
187
188 double reference = fRate;
189 if (fReference==kBoard)
190 reference = fRateBoard[fReferenceIdx];
191 if (fReference==kPatch)
192 reference = fRatePatch[fReferenceIdx];
193
194 fOnTime += sdata.fOnTime;
195
196 reference *= sdata.fElapsedTime;
197
198 if ((reference==0 || sqrt(reference)>fResolution*reference) && fSeconds<fSecondsMax)
199 {
200 ostringstream out;
201 out << "Triggers so far: " << reference;
202 if (reference>0)
203 out << " (" << sqrt(reference)/reference << ")";
204 Info(out);
205
206 return;
207 }
208
209 const double time = sdata.fElapsedTime*fSeconds;
210 const uint32_t th = fThresholdMin+fCounter*fThresholdStep;
211
212 float data[2+3+1+40+160];
213 memcpy(data, &fStartTime, 8);
214 memcpy(data+2, &th, 4);
215 data[3] = time; // total elapsed time
216 data[4] = fOnTime/time; // relative on time
217 data[5] = fRate/fSeconds;
218 for (int i=0; i<40; i++)
219 data[i+6] = fRateBoard[i]/fSeconds;
220 for (int i=0; i<160; i++)
221 data[i+46] = fRatePatch[i]/fSeconds;
222
223 ostringstream sout1, sout2, sout3;
224
225 sout1 << th << " " << data[5];
226 for (int i=0; i<200; i++)
227 sout2 << " " << data[i+6];
228 sout3 << " " << data[3] << " " << data[4];
229
230 Info(sout1.str());
231
232 ofstream fout("ratescan.txt", ios::app);
233 fout << sout1.str() << sout2.str() << sout3.str() << endl;
234
235 fDimData.setQuality(fCommand=="FTM_CONTROL/SET_THRESHOLD");
236 fDimData.setData(data, 204*sizeof(float));
237 fDimData.Update();
238
239 fCounter++;
240
241 if (fSeconds>=fSecondsMax)
242 {
243 Message("Rate scan stopped due to timeout.");
244 fCounter=-1;
245 return;
246 }
247
248 if (fThresholdMin+fCounter*fThresholdStep>fThresholdMax)
249 {
250 Message("Rate scan finished.");
251 fCounter = -1;
252
253 //DimClient::sendCommandNB("FTM_CONTROL/STOP_TRIGGER", NULL, 0);
254 return;
255 }
256
257 fSeconds = -2; // FIXME: In principle one missed report is enough
258
259 const int32_t cmd[2] = { -1, fThresholdMin+fCounter*fThresholdStep };
260 DimClient::sendCommandNB(fCommand.c_str(), (void*)cmd, 8);
261 }
262 }
263
264 void PrintState(const pair<Time,int> &state, const char *server)
265 {
266 const State rc = fNetwork.GetState(server, state.second);
267
268 Out() << state.first.GetAsStr("%H:%M:%S.%f").substr(0, 12) << " - ";
269 Out() << kBold << server << ": ";
270 Out() << rc.name << "[" << rc.index << "]";
271 Out() << kReset << " - " << kBlue << rc.comment << endl;
272 }
273
274 int Print()
275 {
276 Out() << fStatusDim.first.GetAsStr("%H:%M:%S.%f").substr(0, 12) << " - ";
277 Out() << kBold << "DIM_DNS: ";
278 if (fStatusDim.second==0)
279 Out() << "Offline" << endl;
280 else
281 Out() << "V" << fStatusDim.second/100 << 'r' << fStatusDim.second%100 << endl;
282
283 PrintState(fStatusFTM, "FTM_CONTROL");
284
285 return GetCurrentState();
286 }
287
288 int StartRateScan(const EventImp &evt, const string &command)
289 {
290 if (!CheckEventSize(evt.GetSize(), "StartRateScan", 12))
291 return kSM_FatalError;
292
293 fCommand = "FTM_CONTROL/"+command;
294
295 fThresholdMin = evt.Get<uint32_t>();
296 fThresholdMax = evt.Get<uint32_t>(4);
297 fThresholdStep = evt.Get<uint32_t>(8);
298
299 UpdateProc();
300
301 const Time now;
302 fStartTime = trunc(now.UnixTime());
303
304 ofstream fout("ratescan.txt", ios::app);
305 fout << "# ----- " << now << " (" << fStartTime << ") -----\n";
306 fout << "# Command: " << fCommand << '\n';
307 fout << "# Reference: ";
308 switch (fReference)
309 {
310 case kCamera: fout << "Camera"; break;
311 case kBoard: fout << "Board #" << fReferenceIdx; break;
312 case kPatch: fout << "Patch #" << fReferenceIdx; break;
313 }
314 fout << '\n';
315 fout << "# -----" << endl;
316
317 Dim::SendCommand("FAD_CONTROL/SET_FILE_FORMAT", uint16_t(0));
318
319 const int32_t data[2] = { -1, fThresholdMin };
320
321 //Message("Starting Trigger (FTM)");
322 //Dim::SendCommand("FTM_CONTROL/SET_PRESCALING", int32_t(20));
323 Dim::SendCommand(fCommand, data);
324 //Dim::SendCommand("FTM_CONTROL/STOP_TRIGGER");
325
326 fCounter = 0;
327 fSeconds = -2;
328
329 ostringstream msg;
330 msg << "Rate scan " << now << "(" << fStartTime << ") from " << fThresholdMin << " to ";
331 msg << fThresholdMax << " in steps of " << fThresholdStep;
332 msg << " started.";
333 Message(msg);
334
335 return GetCurrentState();
336 }
337
338 int StopRateScan()
339 {
340 fCounter = -1;
341 Message("Rate scan manually stopped.");
342
343 //if (fStatusFTM.second==FTM::kTakingData)
344 {
345 //Message("Stopping FTM");
346 //Dim::SendCommand("FTM_CONTROL/STOP_TRIGGER");
347 }
348
349 return GetCurrentState();
350 }
351
352 int SetReferenceCamera()
353 {
354 fReference = kCamera;
355
356 return GetCurrentState();
357 }
358
359 int SetReferenceBoard(const EventImp &evt)
360 {
361 if (!CheckEventSize(evt.GetSize(), "SetReferenceBoard", 4))
362 return kSM_FatalError;
363
364 if (evt.GetUInt()>39)
365 {
366 Error("SetReferenceBoard - Board index out of range [0;39]");
367 return GetCurrentState();
368 }
369
370 fReference = kBoard;
371 fReferenceIdx = evt.GetUInt();
372
373 return GetCurrentState();
374 }
375
376 int SetReferencePatch(const EventImp &evt)
377 {
378 if (!CheckEventSize(evt.GetSize(), "SetReferencePatch", 4))
379 return kSM_FatalError;
380
381 if (evt.GetUInt()>159)
382 {
383 Error("SetReferencePatch - Patch index out of range [0;159]");
384 return GetCurrentState();
385 }
386
387 fReference = kPatch;
388 fReferenceIdx = evt.GetUInt();
389
390 return GetCurrentState();
391 }
392
393 int ChangeStepSize(const EventImp &evt)
394 {
395 if (!CheckEventSize(evt.GetSize(), "ChangeStepSize", 4))
396 return kSM_FatalError;
397
398 fThresholdStep = evt.Get<uint32_t>();
399
400 UpdateProc();
401
402 return GetCurrentState();
403 }
404
405 int ChangeMaximum(const EventImp &evt)
406 {
407 if (!CheckEventSize(evt.GetSize(), "ChangeMaximum", 4))
408 return kSM_FatalError;
409
410 fThresholdMax = evt.Get<uint32_t>();
411
412 return GetCurrentState();
413 }
414
415 int Execute()
416 {
417 // Dispatch (execute) at most one handler from the queue. In contrary
418 // to run_one(), it doesn't wait until a handler is available
419 // which can be dispatched, so poll_one() might return with 0
420 // handlers dispatched. The handlers are always dispatched/executed
421 // synchronously, i.e. within the call to poll_one()
422 //poll_one();
423
424 if (fStatusDim.second==0)
425 return kStateDimNetworkNA;
426
427 // All subsystems are not connected
428 if (fStatusFTM.second<FTM::kConnected)
429 return kStateDisconnected;
430
431 // At least one subsystem is not connected
432 // if (fStatusFTM.second>=FTM::kConnected)
433 return fCounter<0 ? kStateConnected : kStateInProgress;
434 }
435
436public:
437 StateMachineRateScan(ostream &out=cout) : StateMachineDim(out, "RATE_SCAN"),
438 fStatusDim(make_pair(Time(), -2)),
439 fStatusFTM(make_pair(Time(), -2)),
440 fDim("DIS_DNS/VERSION_NUMBER", (void*)NULL, 0, this),
441 fFTM("FTM_CONTROL/STATE", (void*)NULL, 0, this),
442 fRates("FTM_CONTROL/TRIGGER_RATES", (void*)NULL, 0, this),
443 fDimData("RATE_SCAN/DATA", "X:1;I:1;F:1;F:1;F:1;F:40;F:160", ""),
444 fDimProc("RATE_SCAN/PROCESS_DATA", "I:1;I:1;I:1",
445 "Rate scan process data"
446 "|min[DAC]:Value at which scan was started"
447 "|max[DAC]:Value at which scan will end"
448 "|step[DAC]:Step size for scan"),
449 fCounter(-1), fReference(kCamera), fReferenceIdx(0)
450 {
451 // ba::io_service::work is a kind of keep_alive for the loop.
452 // It prevents the io_service to go to stopped state, which
453 // would prevent any consecutive calls to run()
454 // or poll() to do nothing. reset() could also revoke to the
455 // previous state but this might introduce some overhead of
456 // deletion and creation of threads and more.
457
458 // State names
459 AddStateName(kStateDimNetworkNA, "DimNetworkNotAvailable",
460 "The Dim DNS is not reachable.");
461
462 AddStateName(kStateDisconnected, "Disconnected",
463 "The Dim DNS is reachable, but the required subsystems are not available.");
464
465 AddStateName(kStateConnected, "Connected",
466 "All needed subsystems are connected to their hardware, no action is performed.");
467
468 AddStateName(kStateInProgress, "InProgress",
469 "Rate scan in progress.");
470
471 AddEvent("START_THRESHOLD_SCAN", "I:3", kStateConnected)
472 (bind(&StateMachineRateScan::StartRateScan, this, placeholders::_1, "SET_THRESHOLD"))
473 ("Start rate scan for the threshold in the defined range"
474 "|min[int]:Start value in DAC counts"
475 "|max[int]:Limiting value in DAC counts"
476 "|step[int]:Single step in DAC counts");
477
478 AddEvent("START_N_OUT_OF_4_SCAN", "I:3", kStateConnected)
479 (bind(&StateMachineRateScan::StartRateScan, this, placeholders::_1, "SET_N_OUT_OF_4"))
480 ("Start rate scan for N-out-of-4 in the defined range"
481 "|min[int]:Start value in DAC counts"
482 "|max[int]:Limiting value in DAC counts"
483 "|step[int]:Single step in DAC counts");
484
485 AddEvent("CHANGE_STEP_SIZE", "I:1", kStateInProgress)
486 (bind(&StateMachineRateScan::ChangeStepSize, this, placeholders::_1))
487 ("Change the step size during a ratescan in progress"
488 "|step[int]:Single step in DAC counts");
489
490 AddEvent("CHANGE_MAXIMUM", "I:1", kStateInProgress)
491 (bind(&StateMachineRateScan::ChangeMaximum, this, placeholders::_1))
492 ("Change the maximum limit during a ratescan in progress"
493 "|max[int]:Limiting value in DAC counts");
494
495 AddEvent("STOP", kStateInProgress)
496 (bind(&StateMachineRateScan::StopRateScan, this))
497 ("Stop a ratescan in progress");
498
499 AddEvent("SET_REFERENCE_CAMERA", kStateDimNetworkNA, kStateDisconnected, kStateConnected)
500 (bind(&StateMachineRateScan::SetReferenceCamera, this))
501 ("Use the camera trigger rate as reference for the reolution");
502 AddEvent("SET_REFERENCE_BOARD", "I:1", kStateDimNetworkNA, kStateDisconnected, kStateConnected)
503 (bind(&StateMachineRateScan::SetReferenceBoard, this, placeholders::_1))
504 ("Use the given board trigger-rate as reference for the reolution"
505 "|board[idx]:Index of the board (4*crate+board)");
506 AddEvent("SET_REFERENCE_PATCH", "I:1", kStateDimNetworkNA, kStateDisconnected, kStateConnected)
507 (bind(&StateMachineRateScan::SetReferenceBoard, this, placeholders::_1))
508 ("Use the given patch trigger-rate as reference for the reolution"
509 "|patch[idx]:Index of the patch (360*crate+36*board+patch)" );
510
511 AddEvent("PRINT")
512 (bind(&StateMachineRateScan::Print, this))
513 ("");
514 }
515
516 int EvalOptions(Configuration &conf)
517 {
518 fSecondsMax = conf.Get<uint16_t>("max-wait");
519 fResolution = conf.Get<double>("resolution");
520
521 return -1;
522 }
523};
524
525// ------------------------------------------------------------------------
526
527#include "Main.h"
528
529template<class T>
530int RunShell(Configuration &conf)
531{
532 return Main::execute<T, StateMachineRateScan>(conf);
533}
534
535void SetupConfiguration(Configuration &conf)
536{
537 po::options_description control("Rate scan options");
538 control.add_options()
539 ("max-wait", var<uint16_t>(150), "The maximum number of seconds to wait to get the anticipated resolution for a point.")
540 ("resolution", var<double>(0.05) , "The minimum resolution required for a single data point.")
541 ;
542
543 conf.AddOptions(control);
544}
545
546/*
547 Extract usage clause(s) [if any] for SYNOPSIS.
548 Translators: "Usage" and "or" here are patterns (regular expressions) which
549 are used to match the usage synopsis in program output. An example from cp
550 (GNU coreutils) which contains both strings:
551 Usage: cp [OPTION]... [-T] SOURCE DEST
552 or: cp [OPTION]... SOURCE... DIRECTORY
553 or: cp [OPTION]... -t DIRECTORY SOURCE...
554 */
555void PrintUsage()
556{
557 cout <<
558 "The ratescan program is a tool for automation of rate scans.\n"
559 "\n"
560 "Usage: ratescan [-c type] [OPTIONS]\n"
561 " or: ratescan [OPTIONS]\n";
562 cout << endl;
563}
564
565void PrintHelp()
566{
567 Main::PrintHelp<StateMachineRateScan>();
568
569 /* Additional help text which is printed after the configuration
570 options goes here */
571
572 /*
573 cout << "bla bla bla" << endl << endl;
574 cout << endl;
575 cout << "Environment:" << endl;
576 cout << "environment" << endl;
577 cout << endl;
578 cout << "Examples:" << endl;
579 cout << "test exam" << endl;
580 cout << endl;
581 cout << "Files:" << endl;
582 cout << "files" << endl;
583 cout << endl;
584 */
585}
586
587int main(int argc, const char* argv[])
588{
589 Configuration conf(argv[0]);
590 conf.SetPrintUsage(PrintUsage);
591 Main::SetupConfiguration(conf);
592 SetupConfiguration(conf);
593
594 if (!conf.DoParse(argc, argv, PrintHelp))
595 return -1;
596
597 //try
598 {
599 // No console access at all
600 if (!conf.Has("console"))
601 {
602// if (conf.Get<bool>("no-dim"))
603// return RunShell<LocalStream, StateMachine, ConnectionFSC>(conf);
604// else
605 return RunShell<LocalStream>(conf);
606 }
607 // Cosole access w/ and w/o Dim
608/* if (conf.Get<bool>("no-dim"))
609 {
610 if (conf.Get<int>("console")==0)
611 return RunShell<LocalShell, StateMachine, ConnectionFSC>(conf);
612 else
613 return RunShell<LocalConsole, StateMachine, ConnectionFSC>(conf);
614 }
615 else
616*/ {
617 if (conf.Get<int>("console")==0)
618 return RunShell<LocalShell>(conf);
619 else
620 return RunShell<LocalConsole>(conf);
621 }
622 }
623 /*catch (std::exception& e)
624 {
625 cerr << "Exception: " << e.what() << endl;
626 return -1;
627 }*/
628
629 return 0;
630}
Note: See TracBrowser for help on using the repository browser.