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

Last change on this file since 20115 was 18142, checked in by tbretz, 10 years ago
Added some explicit conversions, a const qualifier and removed an obsolete conditional.
File size: 20.8 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
11#include "tools.h"
12
13#include "LocalControl.h"
14
15#include "HeadersFTM.h"
16#include "HeadersRateScan.h"
17
18namespace ba = boost::asio;
19namespace bs = boost::system;
20
21using namespace std;
22
23// ------------------------------------------------------------------------
24
25#include "DimDescriptionService.h"
26#include "DimState.h"
27
28// ------------------------------------------------------------------------
29
30class StateMachineRateScan : public StateMachineDim
31{
32private:
33 struct config
34 {
35 int fCounterMax;
36 float fResolution;
37 };
38 map<string, config> fTypes;
39
40 DimVersion fDim;
41
42 DimDescribedState fDimFTM;
43 DimDescribedService fDimData;
44 DimDescribedService fDimProc;
45
46 bool fAutoPause;
47
48 int fCounter;
49 int fCounterMax;
50
51 int fThreshold;
52 int fThresholdMin;
53 int fThresholdMax;
54 int fThresholdStep;
55 int fThresholdStepDyn;
56
57 double fRate;
58 double fRateBoard[40];
59 double fRatePatch[160];
60
61 double fOnTime;
62
63 uint64_t fStartTime;
64
65 float fResolution;
66
67 enum reference_t
68 {
69 kCamera,
70 kBoard,
71 kPatch
72 };
73
74 reference_t fReference;
75 uint16_t fReferenceIdx;
76
77 string fCommand;
78
79 void UpdateProc()
80 {
81 const array<uint32_t,3> v = {{ uint32_t(fThresholdMin), uint32_t(fThresholdMax), uint32_t(fThresholdStep) }};
82 fDimProc.Update(v);
83 }
84
85 bool CheckEventSize(const EventImp &evt, size_t size)
86 {
87 if (size_t(evt.GetSize())==size)
88 return true;
89
90 if (evt.GetSize()==0)
91 return false;
92
93 ostringstream msg;
94 msg << evt.GetName() << " - Received event has " << evt.GetSize() << " bytes, but expected " << size << ".";
95 Fatal(msg);
96 return false;
97 }
98
99 int HandleTriggerRates(const EventImp &evt)
100 {
101 if (!CheckEventSize(evt, sizeof(FTM::DimTriggerRates)))
102 return GetCurrentState();
103
104 if (GetCurrentState()<RateScan::State::kInProgress)
105 return GetCurrentState();
106
107 const FTM::DimTriggerRates &sdata = *static_cast<const FTM::DimTriggerRates*>(evt.GetData());
108
109 if (++fCounter<0)
110 return GetCurrentState();
111
112 if (GetCurrentState()==RateScan::State::kPaused)
113 fCounter=0;
114
115 if (fCounter==0)
116 {
117 fRate = 0;
118
119 memset(fRateBoard, 0, 40*sizeof(double));
120 memset(fRatePatch, 0, 160*sizeof(double));
121
122 fOnTime = 0;
123 return GetCurrentState();
124 }
125/*
126 if (sdata.fTriggerRate==0)
127 {
128 Message("Rate scan stopped due zero trigger rate.");
129 fThreshold = -1;
130 return;
131 }
132*/
133
134 fRate += sdata.fTriggerRate;
135 for (int i=0; i<40; i++)
136 fRateBoard[i] += sdata.fBoardRate[i];
137 for (int i=0; i<160; i++)
138 fRatePatch[i] += sdata.fPatchRate[i];
139
140 double reference = fRate;
141 if (fReference==kBoard)
142 reference = fRateBoard[fReferenceIdx];
143 if (fReference==kPatch)
144 reference = fRatePatch[fReferenceIdx];
145
146 fOnTime += sdata.fOnTime;
147
148 reference *= sdata.fElapsedTime;
149
150 if ((reference==0 || sqrt(reference)>fResolution*reference) && fCounter<fCounterMax)
151 {
152 ostringstream out;
153 out << "Triggers so far: " << reference;
154 if (reference>0)
155 out << " (" << sqrt(reference)/reference << ")";
156 Info(out);
157
158 return GetCurrentState();
159 }
160
161 const double time = sdata.fElapsedTime*fCounter;
162 const uint32_t th = fThreshold;
163
164 float data[2+3+1+40+160];
165 memcpy(data, &fStartTime, 8);
166 memcpy(data+2, &th, 4);
167 data[3] = time; // total elapsed time
168 data[4] = fOnTime/time; // relative on time
169 data[5] = fRate/fCounter;
170 for (int i=0; i<40; i++)
171 data[i+6] = fRateBoard[i]/fCounter;
172 for (int i=0; i<160; i++)
173 data[i+46] = fRatePatch[i]/fCounter;
174
175 ostringstream sout1, sout2, sout3;
176
177 sout1 << th << " " << data[5];
178 for (int i=0; i<200; i++)
179 sout2 << " " << data[i+6];
180 sout3 << " " << data[3] << " " << data[4];
181
182 Info(sout1.str());
183
184 //ofstream fout("ratescan.txt", ios::app);
185 //fout << sout1.str() << sout2.str() << sout3.str() << endl;
186
187 fDimData.setQuality(fCommand=="FTM_CONTROL/SET_THRESHOLD");
188 fDimData.setData(data, sizeof(data));
189 fDimData.Update();
190
191 fThreshold += fThresholdStep;
192
193 if (fCounter>=fCounterMax)
194 {
195 Message("Rate scan stopped due to timeout.");
196 //Dim::SendCommandNB("FTM_CONTROL/RESET_CONFIGURE");
197 return RateScan::State::kConnected;
198 }
199
200 if (fThreshold>fThresholdMax)
201 {
202 Message("Rate scan finished.");
203 //Dim::SendCommandNB("FTM_CONTROL/RESET_CONFIGURE");
204 return RateScan::State::kConnected;
205 }
206
207 // Does this need to be shifted upwards?
208 if (fCounter>1 && fThresholdStepDyn>0)
209 {
210 //const double scale = fCounter/reference/fResolution/fResolution;
211 //const double step = floor(scale*fThresholdStepDyn);
212
213 fThresholdStep = fCounter*fThresholdStepDyn;
214 }
215
216 //fCounter = -2; // FIXME: In principle one missed report is enough
217 fCounter = -1;
218
219 const int32_t cmd[2] = { -1, fThreshold };
220 Dim::SendCommandNB(fCommand.c_str(), cmd);
221
222 return GetCurrentState();
223 }
224
225 int Print() const
226 {
227 Out() << fDim << endl;
228 Out() << fDimFTM << endl;
229
230 return GetCurrentState();
231 }
232
233 int StartRateScan(const EventImp &evt, const string &command)
234 {
235 //FIXME: check at least that size>12
236 //if (!CheckEventSize(evt, 12))
237 // return kSM_FatalError;
238
239 const string fType = evt.Ptr<char>(12);
240
241 auto it = fTypes.find(fType);
242 if (it==fTypes.end())
243 {
244 Info("StartRateScan - Type '"+fType+"' not found... trying 'default'.");
245
246 it = fTypes.find("default");
247 if (it==fTypes.end())
248 {
249 Error("StartRateScan - Type 'default' not found.");
250 return GetCurrentState();
251 }
252 }
253
254 fCounterMax = it->second.fCounterMax;
255 fResolution = it->second.fResolution;
256
257 fCommand = "FTM_CONTROL/"+command;
258
259 const int32_t step = evt.Get<int32_t>(8);
260
261 fThresholdMin = evt.Get<uint32_t>();
262 fThresholdMax = evt.Get<uint32_t>(4);
263 fThresholdStep = abs(step);
264
265 fThresholdStepDyn = step<0 ? -step : 0;
266
267 UpdateProc();
268
269 //Dim::SendCommand("FAD_CONTROL/SET_FILE_FORMAT", uint16_t(0));
270 Dim::SendCommandNB("FTM_CONTROL/CONFIGURE", string("ratescan"));
271
272 Message("Configuration for ratescan started.");
273
274 return RateScan::State::kConfiguring;
275 }
276
277 int HandleFtmStateChange(/*const EventImp &evt*/)
278 {
279 // ftmctrl connected to FTM
280 if (GetCurrentState()!=RateScan::State::kConfiguring)
281 return GetCurrentState();
282
283 if (fDimFTM.state()!=FTM::State::kConfigured1)
284 return GetCurrentState();
285
286 const int32_t data[2] = { -1, fThresholdMin };
287
288 Dim::SendCommandNB("FTM_CONTROL/RESET_CONFIGURE");
289 Dim::SendCommandNB(fCommand, data);
290
291 fThreshold = fThresholdMin;
292 fCounter = -2;
293
294 const Time now;
295 fStartTime = trunc(now.UnixTime());
296
297 /*
298 ofstream fout("ratescan.txt", ios::app);
299 fout << "# ----- " << now << " (" << fStartTime << ") -----\n";
300 fout << "# Command: " << fCommand << '\n';
301 fout << "# Reference: ";
302 switch (fReference)
303 {
304 case kCamera: fout << "Camera"; break;
305 case kBoard: fout << "Board #" << fReferenceIdx; break;
306 case kPatch: fout << "Patch #" << fReferenceIdx; break;
307 }
308 fout << '\n';
309 fout << "# -----" << endl;
310 */
311
312 ostringstream msg;
313 msg << "Rate scan " << now << "(" << fStartTime << ") from " << fThresholdMin << " to ";
314 msg << fThresholdMax << " in steps of " << fThresholdStep;
315 msg << " with a resolution of " << fResolution ;
316 msg << " and max-wait " << fCounterMax ;
317 msg << " started.";
318 Message(msg);
319
320 if (!fAutoPause)
321 return RateScan::State::kInProgress;
322
323 fAutoPause = false;
324
325 return RateScan::State::kPaused;
326 }
327
328 int StopRateScan()
329 {
330 if (GetCurrentState()<RateScan::State::kConfiguring)
331 return GetCurrentState();
332
333 Dim::SendCommandNB("FTM_CONTROL/RESET_CONFIGURE");
334 Message("Rate scan manually stopped.");
335
336 return RateScan::State::kConnected;
337 }
338
339 int SetReferenceCamera()
340 {
341 fReference = kCamera;
342
343 return GetCurrentState();
344 }
345
346 int SetReferenceBoard(const EventImp &evt)
347 {
348 if (!CheckEventSize(evt, 4))
349 return kSM_FatalError;
350
351 if (evt.GetUInt()>39)
352 {
353 Error("SetReferenceBoard - Board index out of range [0;39]");
354 return GetCurrentState();
355 }
356
357 fReference = kBoard;
358 fReferenceIdx = evt.GetUInt();
359
360 return GetCurrentState();
361 }
362
363 int SetReferencePatch(const EventImp &evt)
364 {
365 if (!CheckEventSize(evt, 4))
366 return kSM_FatalError;
367
368 if (evt.GetUInt()>159)
369 {
370 Error("SetReferencePatch - Patch index out of range [0;159]");
371 return GetCurrentState();
372 }
373
374 fReference = kPatch;
375 fReferenceIdx = evt.GetUInt();
376
377 return GetCurrentState();
378 }
379
380 int ChangeStepSize(const EventImp &evt)
381 {
382 if (!CheckEventSize(evt, 4))
383 return kSM_FatalError;
384
385 fThresholdStep = evt.Get<uint32_t>();
386
387 ostringstream msg;
388 msg << "New step size " << fThresholdStep;
389 Info(msg);
390
391 UpdateProc();
392
393 return GetCurrentState();
394 }
395
396 int ChangeMaximum(const EventImp &evt)
397 {
398 if (!CheckEventSize(evt, 4))
399 return kSM_FatalError;
400
401 fThresholdMax = evt.Get<uint32_t>();
402
403 return GetCurrentState();
404 }
405
406 int TriggerAutoPause()
407 {
408 fAutoPause = true;
409 return GetCurrentState();
410 }
411
412 int Pause()
413 {
414 return RateScan::State::kPaused;
415 }
416
417 int Resume()
418 {
419 return RateScan::State::kInProgress;
420 }
421
422 int Execute()
423 {
424 if (!fDim.online())
425 return RateScan::State::kDimNetworkNA;
426
427 // All subsystems are not connected
428 if (fDimFTM.state()<FTM::State::kConnected)
429 return RateScan::State::kDisconnected;
430
431 // ftmctrl connected to FTM
432 if (GetCurrentState()<=RateScan::State::kDisconnected)
433 return RateScan::State::kConnected;
434
435 return GetCurrentState();
436 }
437
438public:
439 StateMachineRateScan(ostream &out=cout) : StateMachineDim(out, "RATE_SCAN"),
440 fDimFTM("FTM_CONTROL"),
441 fDimData("RATE_SCAN/DATA", "X:1;I:1;F:1;F:1;F:1;F:40;F:160",
442 "|Id[s]:Start time used to identify measurement (UnixTime)"
443 "|Threshold[dac]:Threshold in DAC counts"
444 "|ElapsedTime[s]:Real elapsed time"
445 "|RelOnTime[ratio]:Relative on time"
446 "|TriggerRate[Hz]:Camera trigger rate"
447 "|BoardRate[Hz]:Board trigger rates"
448 "|PatchRate[Hz]:Patch trigger rates"),
449 fDimProc("RATE_SCAN/PROCESS_DATA", "I:1;I:1;I:1",
450 "Rate scan process data"
451 "|min[DAC]:Value at which scan was started"
452 "|max[DAC]:Value at which scan will end"
453 "|step[DAC]:Step size for scan"),
454 fAutoPause(false), fThreshold(-1), fReference(kCamera), fReferenceIdx(0)
455 {
456 // ba::io_service::work is a kind of keep_alive for the loop.
457 // It prevents the io_service to go to stopped state, which
458 // would prevent any consecutive calls to run()
459 // or poll() to do nothing. reset() could also revoke to the
460 // previous state but this might introduce some overhead of
461 // deletion and creation of threads and more.
462
463 fDim.Subscribe(*this);
464 fDimFTM.Subscribe(*this);
465 fDimFTM.SetCallback(bind(&StateMachineRateScan::HandleFtmStateChange, this));
466
467 Subscribe("FTM_CONTROL/TRIGGER_RATES")
468 (bind(&StateMachineRateScan::HandleTriggerRates, this, placeholders::_1));
469
470 // State names
471 AddStateName(RateScan::State::kDimNetworkNA, "DimNetworkNotAvailable",
472 "The Dim DNS is not reachable.");
473
474 AddStateName(RateScan::State::kDisconnected, "Disconnected",
475 "The Dim DNS is reachable, but the required subsystems are not available.");
476
477 AddStateName(RateScan::State::kConnected, "Connected",
478 "All needed subsystems are connected to their hardware, no action is performed.");
479
480 AddStateName(RateScan::State::kConfiguring, "Configuring",
481 "Waiting for FTM to get 'Configured'.");
482
483 AddStateName(RateScan::State::kInProgress, "InProgress",
484 "Rate scan in progress.");
485
486 AddStateName(RateScan::State::kPaused, "Paused",
487 "Rate scan in progress but paused.");
488
489 AddEvent("START_THRESHOLD_SCAN", "I:3;C", RateScan::State::kConnected)
490 (bind(&StateMachineRateScan::StartRateScan, this, placeholders::_1, "SET_THRESHOLD"))
491 ("Start rate scan for the threshold in the defined range"
492 "|min[int]:Start value in DAC counts"
493 "|max[int]:Limiting value in DAC counts"
494 "|step[int]:Single step in DAC counts"
495 "|type[text]:Ratescan type");
496
497 AddEvent("START_N_OUT_OF_4_SCAN", "I:3", RateScan::State::kConnected)
498 (bind(&StateMachineRateScan::StartRateScan, this, placeholders::_1, "SET_N_OUT_OF_4"))
499 ("Start rate scan for N-out-of-4 in the defined range"
500 "|min[int]:Start value in DAC counts"
501 "|max[int]:Limiting value in DAC counts"
502 "|step[int]:Single step in DAC counts");
503
504 AddEvent("CHANGE_STEP_SIZE", "I:1", RateScan::State::kPaused, RateScan::State::kInProgress)
505 (bind(&StateMachineRateScan::ChangeStepSize, this, placeholders::_1))
506 ("Change the step size during a ratescan in progress"
507 "|step[int]:Single step in DAC counts");
508
509 AddEvent("CHANGE_MAXIMUM", "I:1", RateScan::State::kPaused, RateScan::State::kInProgress)
510 (bind(&StateMachineRateScan::ChangeMaximum, this, placeholders::_1))
511 ("Change the maximum limit during a ratescan in progress"
512 "|max[int]:Limiting value in DAC counts");
513
514 AddEvent("STOP", RateScan::State::kConfiguring, RateScan::State::kPaused, RateScan::State::kInProgress)
515 (bind(&StateMachineRateScan::StopRateScan, this))
516 ("Stop a ratescan in progress");
517
518 AddEvent("SET_REFERENCE_CAMERA", RateScan::State::kDimNetworkNA, RateScan::State::kDisconnected, RateScan::State::kConnected)
519 (bind(&StateMachineRateScan::SetReferenceCamera, this))
520 ("Use the camera trigger rate as reference for the reolution");
521 AddEvent("SET_REFERENCE_BOARD", "I:1", RateScan::State::kDimNetworkNA, RateScan::State::kDisconnected, RateScan::State::kConnected)
522 (bind(&StateMachineRateScan::SetReferenceBoard, this, placeholders::_1))
523 ("Use the given board trigger-rate as reference for the reolution"
524 "|board[idx]:Index of the board (4*crate+board)");
525 AddEvent("SET_REFERENCE_PATCH", "I:1", RateScan::State::kDimNetworkNA, RateScan::State::kDisconnected, RateScan::State::kConnected)
526 (bind(&StateMachineRateScan::SetReferencePatch, this, placeholders::_1))
527 ("Use the given patch trigger-rate as reference for the reolution"
528 "|patch[idx]:Index of the patch (360*crate+36*board+patch)");
529
530 AddEvent("TRIGGER_AUTO_PAUSE", RateScan::State::kDimNetworkNA, RateScan::State::kDisconnected, RateScan::State::kConnected)
531 (bind(&StateMachineRateScan::TriggerAutoPause, this))
532 ("Enable an automatic pause for the next ratescan, after it got configured.");
533
534 AddEvent("PAUSE", RateScan::State::kInProgress)
535 (bind(&StateMachineRateScan::Pause, this))
536 ("Pause a ratescan in progress");
537 AddEvent("RESUME", RateScan::State::kPaused)
538 (bind(&StateMachineRateScan::Resume, this))
539 ("Resume a paused ratescan");
540
541 AddEvent("PRINT")
542 (bind(&StateMachineRateScan::Print, this))
543 ("");
544 }
545
546 int EvalOptions(Configuration &conf)
547 {
548 // ---------- Setup run types ---------
549 const vector<string> types = conf.Vec<string>("type");
550 if (types.empty())
551 Warn("No types defined.");
552 else
553 Message("Defining types");
554
555 for (auto it=types.begin(); it!=types.end(); it++)
556 {
557 Message(" -> "+ *it);
558
559 if (fTypes.count(*it)>0)
560 {
561 Error("Type "+*it+" defined twice.");
562 return 1;
563 }
564
565 config &c = fTypes[*it];
566 if (conf.HasDef("max-wait.", *it))
567 c.fCounterMax = conf.GetDef<int>("max-wait.", *it);
568 else
569 {
570 Error("Neither max-wait.default nor max-wait."+*it+" found.");
571 return 2;
572 }
573 if (conf.HasDef("resolution.", *it))
574 c.fResolution = conf.GetDef<double>("resolution.", *it);
575 else
576 {
577 Error("Neither resolution.default nor resolution."+*it+" found.");
578 return 2;
579 }
580 }
581 return -1;
582 }
583};
584
585// ------------------------------------------------------------------------
586
587#include "Main.h"
588
589template<class T>
590int RunShell(Configuration &conf)
591{
592 return Main::execute<T, StateMachineRateScan>(conf);
593}
594
595void SetupConfiguration(Configuration &conf)
596{
597 po::options_description type("Ratescan type configuration");
598 type.add_options()
599 ("type", vars<string>(), "Name of ratescan types (replace the * in the following configuration by the case-sensitive names defined here)")
600 ("max-wait.*", var<int>(), "The maximum number of seconds to wait to get the anticipated resolution for a point.")
601 ("resolution.*", var<double>() , "The minimum resolution required for a single data point.")
602 ;
603
604 conf.AddOptions(type);
605}
606
607/*
608 Extract usage clause(s) [if any] for SYNOPSIS.
609 Translators: "Usage" and "or" here are patterns (regular expressions) which
610 are used to match the usage synopsis in program output. An example from cp
611 (GNU coreutils) which contains both strings:
612 Usage: cp [OPTION]... [-T] SOURCE DEST
613 or: cp [OPTION]... SOURCE... DIRECTORY
614 or: cp [OPTION]... -t DIRECTORY SOURCE...
615 */
616void PrintUsage()
617{
618 cout <<
619 "The ratescan program is a tool for automation of rate scans.\n"
620 "\n"
621 "Usage: ratescan [-c type] [OPTIONS]\n"
622 " or: ratescan [OPTIONS]\n";
623 cout << endl;
624}
625
626void PrintHelp()
627{
628 Main::PrintHelp<StateMachineRateScan>();
629
630 /* Additional help text which is printed after the configuration
631 options goes here */
632
633 /*
634 cout << "bla bla bla" << endl << endl;
635 cout << endl;
636 cout << "Environment:" << endl;
637 cout << "environment" << endl;
638 cout << endl;
639 cout << "Examples:" << endl;
640 cout << "test exam" << endl;
641 cout << endl;
642 cout << "Files:" << endl;
643 cout << "files" << endl;
644 cout << endl;
645 */
646}
647
648int main(int argc, const char* argv[])
649{
650 Configuration conf(argv[0]);
651 conf.SetPrintUsage(PrintUsage);
652 Main::SetupConfiguration(conf);
653 SetupConfiguration(conf);
654
655 if (!conf.DoParse(argc, argv, PrintHelp))
656 return 127;
657
658 //try
659 {
660 // No console access at all
661 if (!conf.Has("console"))
662 {
663// if (conf.Get<bool>("no-dim"))
664// return RunShell<LocalStream, StateMachine, ConnectionFSC>(conf);
665// else
666 return RunShell<LocalStream>(conf);
667 }
668 // Cosole access w/ and w/o Dim
669/* if (conf.Get<bool>("no-dim"))
670 {
671 if (conf.Get<int>("console")==0)
672 return RunShell<LocalShell, StateMachine, ConnectionFSC>(conf);
673 else
674 return RunShell<LocalConsole, StateMachine, ConnectionFSC>(conf);
675 }
676 else
677*/ {
678 if (conf.Get<int>("console")==0)
679 return RunShell<LocalShell>(conf);
680 else
681 return RunShell<LocalConsole>(conf);
682 }
683 }
684 /*catch (std::exception& e)
685 {
686 cerr << "Exception: " << e.what() << endl;
687 return -1;
688 }*/
689
690 return 0;
691}
Note: See TracBrowser for help on using the repository browser.