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

Last change on this file since 13217 was 12914, checked in by tbretz, 13 years ago
Removed the zero trigger check for the time being.
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 fSeconds;
71 int fSecondsMax;
72
73 int fThreshold;
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 (fThreshold<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 fThreshold = -1;
179 return;
180 }
181*/
182
183 fRate += sdata.fTriggerRate;
184 for (int i=0; i<40; i++)
185 fRateBoard[i] += sdata.fBoardRate[i];
186 for (int i=0; i<160; i++)
187 fRatePatch[i] += sdata.fPatchRate[i];
188
189 double reference = fRate;
190 if (fReference==kBoard)
191 reference = fRateBoard[fReferenceIdx];
192 if (fReference==kPatch)
193 reference = fRatePatch[fReferenceIdx];
194
195 fOnTime += sdata.fOnTime;
196
197 reference *= sdata.fElapsedTime;
198
199 if ((reference==0 || sqrt(reference)>fResolution*reference) && fSeconds<fSecondsMax)
200 {
201 ostringstream out;
202 out << "Triggers so far: " << reference;
203 if (reference>0)
204 out << " (" << sqrt(reference)/reference << ")";
205 Info(out);
206
207 return;
208 }
209
210 const double time = sdata.fElapsedTime*fSeconds;
211 const uint32_t th = fThreshold;
212
213 float data[2+3+1+40+160];
214 memcpy(data, &fStartTime, 8);
215 memcpy(data+2, &th, 4);
216 data[3] = time; // total elapsed time
217 data[4] = fOnTime/time; // relative on time
218 data[5] = fRate/fSeconds;
219 for (int i=0; i<40; i++)
220 data[i+6] = fRateBoard[i]/fSeconds;
221 for (int i=0; i<160; i++)
222 data[i+46] = fRatePatch[i]/fSeconds;
223
224 ostringstream sout1, sout2, sout3;
225
226 sout1 << th << " " << data[5];
227 for (int i=0; i<200; i++)
228 sout2 << " " << data[i+6];
229 sout3 << " " << data[3] << " " << data[4];
230
231 Info(sout1.str());
232
233 ofstream fout("ratescan.txt", ios::app);
234 fout << sout1.str() << sout2.str() << sout3.str() << endl;
235
236 fDimData.setQuality(fCommand=="FTM_CONTROL/SET_THRESHOLD");
237 fDimData.setData(data, sizeof(data));
238 fDimData.Update();
239
240 fThreshold += fThresholdStep;
241
242 if (fSeconds>=fSecondsMax)
243 {
244 Message("Rate scan stopped due to timeout.");
245 fThreshold=-1;
246 return;
247 }
248
249 if (fThreshold>fThresholdMax)
250 {
251 Message("Rate scan finished.");
252 fThreshold = -1;
253 return;
254 }
255
256 //fSeconds = -2; // FIXME: In principle one missed report is enough
257 fSeconds = -1;
258
259 const int32_t cmd[2] = { -1, fThreshold };
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 fThreshold = fThresholdMin;
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 fThreshold = -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 ostringstream msg;
401 msg << "New step size " << fThresholdStep;
402 Info(msg);
403
404 UpdateProc();
405
406 return GetCurrentState();
407 }
408
409 int ChangeMaximum(const EventImp &evt)
410 {
411 if (!CheckEventSize(evt.GetSize(), "ChangeMaximum", 4))
412 return kSM_FatalError;
413
414 fThresholdMax = evt.Get<uint32_t>();
415
416 return GetCurrentState();
417 }
418
419 int Execute()
420 {
421 // Dispatch (execute) at most one handler from the queue. In contrary
422 // to run_one(), it doesn't wait until a handler is available
423 // which can be dispatched, so poll_one() might return with 0
424 // handlers dispatched. The handlers are always dispatched/executed
425 // synchronously, i.e. within the call to poll_one()
426 //poll_one();
427
428 if (fStatusDim.second==0)
429 return kStateDimNetworkNA;
430
431 // All subsystems are not connected
432 if (fStatusFTM.second<FTM::kConnected)
433 return kStateDisconnected;
434
435 // At least one subsystem is not connected
436 // if (fStatusFTM.second>=FTM::kConnected)
437 return fThreshold<0 ? kStateConnected : kStateInProgress;
438 }
439
440public:
441 StateMachineRateScan(ostream &out=cout) : StateMachineDim(out, "RATE_SCAN"),
442 fStatusDim(make_pair(Time(), -2)),
443 fStatusFTM(make_pair(Time(), -2)),
444 fDim("DIS_DNS/VERSION_NUMBER", (void*)NULL, 0, this),
445 fFTM("FTM_CONTROL/STATE", (void*)NULL, 0, this),
446 fRates("FTM_CONTROL/TRIGGER_RATES", (void*)NULL, 0, this),
447 fDimData("RATE_SCAN/DATA", "X:1;I:1;F:1;F:1;F:1;F:40;F:160", ""),
448 fDimProc("RATE_SCAN/PROCESS_DATA", "I:1;I:1;I:1",
449 "Rate scan process data"
450 "|min[DAC]:Value at which scan was started"
451 "|max[DAC]:Value at which scan will end"
452 "|step[DAC]:Step size for scan"),
453 fThreshold(-1), fReference(kCamera), fReferenceIdx(0)
454 {
455 // ba::io_service::work is a kind of keep_alive for the loop.
456 // It prevents the io_service to go to stopped state, which
457 // would prevent any consecutive calls to run()
458 // or poll() to do nothing. reset() could also revoke to the
459 // previous state but this might introduce some overhead of
460 // deletion and creation of threads and more.
461
462 // State names
463 AddStateName(kStateDimNetworkNA, "DimNetworkNotAvailable",
464 "The Dim DNS is not reachable.");
465
466 AddStateName(kStateDisconnected, "Disconnected",
467 "The Dim DNS is reachable, but the required subsystems are not available.");
468
469 AddStateName(kStateConnected, "Connected",
470 "All needed subsystems are connected to their hardware, no action is performed.");
471
472 AddStateName(kStateInProgress, "InProgress",
473 "Rate scan in progress.");
474
475 AddEvent("START_THRESHOLD_SCAN", "I:3", kStateConnected)
476 (bind(&StateMachineRateScan::StartRateScan, this, placeholders::_1, "SET_THRESHOLD"))
477 ("Start rate scan for the threshold in the defined range"
478 "|min[int]:Start value in DAC counts"
479 "|max[int]:Limiting value in DAC counts"
480 "|step[int]:Single step in DAC counts");
481
482 AddEvent("START_N_OUT_OF_4_SCAN", "I:3", kStateConnected)
483 (bind(&StateMachineRateScan::StartRateScan, this, placeholders::_1, "SET_N_OUT_OF_4"))
484 ("Start rate scan for N-out-of-4 in the defined range"
485 "|min[int]:Start value in DAC counts"
486 "|max[int]:Limiting value in DAC counts"
487 "|step[int]:Single step in DAC counts");
488
489 AddEvent("CHANGE_STEP_SIZE", "I:1", kStateInProgress)
490 (bind(&StateMachineRateScan::ChangeStepSize, this, placeholders::_1))
491 ("Change the step size during a ratescan in progress"
492 "|step[int]:Single step in DAC counts");
493
494 AddEvent("CHANGE_MAXIMUM", "I:1", kStateInProgress)
495 (bind(&StateMachineRateScan::ChangeMaximum, this, placeholders::_1))
496 ("Change the maximum limit during a ratescan in progress"
497 "|max[int]:Limiting value in DAC counts");
498
499 AddEvent("STOP", kStateInProgress)
500 (bind(&StateMachineRateScan::StopRateScan, this))
501 ("Stop a ratescan in progress");
502
503 AddEvent("SET_REFERENCE_CAMERA", kStateDimNetworkNA, kStateDisconnected, kStateConnected)
504 (bind(&StateMachineRateScan::SetReferenceCamera, this))
505 ("Use the camera trigger rate as reference for the reolution");
506 AddEvent("SET_REFERENCE_BOARD", "I:1", kStateDimNetworkNA, kStateDisconnected, kStateConnected)
507 (bind(&StateMachineRateScan::SetReferenceBoard, this, placeholders::_1))
508 ("Use the given board trigger-rate as reference for the reolution"
509 "|board[idx]:Index of the board (4*crate+board)");
510 AddEvent("SET_REFERENCE_PATCH", "I:1", kStateDimNetworkNA, kStateDisconnected, kStateConnected)
511 (bind(&StateMachineRateScan::SetReferenceBoard, this, placeholders::_1))
512 ("Use the given patch trigger-rate as reference for the reolution"
513 "|patch[idx]:Index of the patch (360*crate+36*board+patch)" );
514
515 AddEvent("PRINT")
516 (bind(&StateMachineRateScan::Print, this))
517 ("");
518 }
519
520 int EvalOptions(Configuration &conf)
521 {
522 fSecondsMax = conf.Get<uint16_t>("max-wait");
523 fResolution = conf.Get<double>("resolution");
524
525 return -1;
526 }
527};
528
529// ------------------------------------------------------------------------
530
531#include "Main.h"
532
533template<class T>
534int RunShell(Configuration &conf)
535{
536 return Main::execute<T, StateMachineRateScan>(conf);
537}
538
539void SetupConfiguration(Configuration &conf)
540{
541 po::options_description control("Rate scan options");
542 control.add_options()
543 ("max-wait", var<uint16_t>(150), "The maximum number of seconds to wait to get the anticipated resolution for a point.")
544 ("resolution", var<double>(0.05) , "The minimum resolution required for a single data point.")
545 ;
546
547 conf.AddOptions(control);
548}
549
550/*
551 Extract usage clause(s) [if any] for SYNOPSIS.
552 Translators: "Usage" and "or" here are patterns (regular expressions) which
553 are used to match the usage synopsis in program output. An example from cp
554 (GNU coreutils) which contains both strings:
555 Usage: cp [OPTION]... [-T] SOURCE DEST
556 or: cp [OPTION]... SOURCE... DIRECTORY
557 or: cp [OPTION]... -t DIRECTORY SOURCE...
558 */
559void PrintUsage()
560{
561 cout <<
562 "The ratescan program is a tool for automation of rate scans.\n"
563 "\n"
564 "Usage: ratescan [-c type] [OPTIONS]\n"
565 " or: ratescan [OPTIONS]\n";
566 cout << endl;
567}
568
569void PrintHelp()
570{
571 Main::PrintHelp<StateMachineRateScan>();
572
573 /* Additional help text which is printed after the configuration
574 options goes here */
575
576 /*
577 cout << "bla bla bla" << endl << endl;
578 cout << endl;
579 cout << "Environment:" << endl;
580 cout << "environment" << endl;
581 cout << endl;
582 cout << "Examples:" << endl;
583 cout << "test exam" << endl;
584 cout << endl;
585 cout << "Files:" << endl;
586 cout << "files" << endl;
587 cout << endl;
588 */
589}
590
591int main(int argc, const char* argv[])
592{
593 Configuration conf(argv[0]);
594 conf.SetPrintUsage(PrintUsage);
595 Main::SetupConfiguration(conf);
596 SetupConfiguration(conf);
597
598 if (!conf.DoParse(argc, argv, PrintHelp))
599 return -1;
600
601 //try
602 {
603 // No console access at all
604 if (!conf.Has("console"))
605 {
606// if (conf.Get<bool>("no-dim"))
607// return RunShell<LocalStream, StateMachine, ConnectionFSC>(conf);
608// else
609 return RunShell<LocalStream>(conf);
610 }
611 // Cosole access w/ and w/o Dim
612/* if (conf.Get<bool>("no-dim"))
613 {
614 if (conf.Get<int>("console")==0)
615 return RunShell<LocalShell, StateMachine, ConnectionFSC>(conf);
616 else
617 return RunShell<LocalConsole, StateMachine, ConnectionFSC>(conf);
618 }
619 else
620*/ {
621 if (conf.Get<int>("console")==0)
622 return RunShell<LocalShell>(conf);
623 else
624 return RunShell<LocalConsole>(conf);
625 }
626 }
627 /*catch (std::exception& e)
628 {
629 cerr << "Exception: " << e.what() << endl;
630 return -1;
631 }*/
632
633 return 0;
634}
Note: See TracBrowser for help on using the repository browser.