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

Last change on this file since 18087 was 18048, checked in by Daniela Dorner, 10 years ago
added ratescan type
File size: 20.9 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 = {{ fThresholdMin, fThresholdMax, 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 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 //const config &conf = it->second;
254
255 if (it!=fTypes.end())
256 {
257 fCounterMax=it->second.fCounterMax;
258 fResolution=it->second.fResolution;
259 }
260
261 fCommand = "FTM_CONTROL/"+command;
262
263 const int32_t step = evt.Get<int32_t>(8);
264
265 fThresholdMin = evt.Get<uint32_t>();
266 fThresholdMax = evt.Get<uint32_t>(4);
267 fThresholdStep = abs(step);
268
269 fThresholdStepDyn = step<0 ? -step : 0;
270
271 UpdateProc();
272
273 //Dim::SendCommand("FAD_CONTROL/SET_FILE_FORMAT", uint16_t(0));
274 Dim::SendCommandNB("FTM_CONTROL/CONFIGURE", string("ratescan"));
275
276 Message("Configuration for ratescan started.");
277
278 return RateScan::State::kConfiguring;
279 }
280
281 int HandleFtmStateChange(/*const EventImp &evt*/)
282 {
283 // ftmctrl connected to FTM
284 if (GetCurrentState()!=RateScan::State::kConfiguring)
285 return GetCurrentState();
286
287 if (fDimFTM.state()!=FTM::State::kConfigured1)
288 return GetCurrentState();
289
290 const int32_t data[2] = { -1, fThresholdMin };
291
292 Dim::SendCommandNB("FTM_CONTROL/RESET_CONFIGURE");
293 Dim::SendCommandNB(fCommand, data);
294
295 fThreshold = fThresholdMin;
296 fCounter = -2;
297
298 const Time now;
299 fStartTime = trunc(now.UnixTime());
300
301 /*
302 ofstream fout("ratescan.txt", ios::app);
303 fout << "# ----- " << now << " (" << fStartTime << ") -----\n";
304 fout << "# Command: " << fCommand << '\n';
305 fout << "# Reference: ";
306 switch (fReference)
307 {
308 case kCamera: fout << "Camera"; break;
309 case kBoard: fout << "Board #" << fReferenceIdx; break;
310 case kPatch: fout << "Patch #" << fReferenceIdx; break;
311 }
312 fout << '\n';
313 fout << "# -----" << endl;
314 */
315
316 ostringstream msg;
317 msg << "Rate scan " << now << "(" << fStartTime << ") from " << fThresholdMin << " to ";
318 msg << fThresholdMax << " in steps of " << fThresholdStep;
319 msg << " with a resolution of " << fResolution ;
320 msg << " and max-wait " << fCounterMax ;
321 msg << " started.";
322 Message(msg);
323
324 if (!fAutoPause)
325 return RateScan::State::kInProgress;
326
327 fAutoPause = false;
328
329 return RateScan::State::kPaused;
330 }
331
332 int StopRateScan()
333 {
334 if (GetCurrentState()<RateScan::State::kConfiguring)
335 return GetCurrentState();
336
337 Dim::SendCommandNB("FTM_CONTROL/RESET_CONFIGURE");
338 Message("Rate scan manually stopped.");
339
340 return RateScan::State::kConnected;
341 }
342
343 int SetReferenceCamera()
344 {
345 fReference = kCamera;
346
347 return GetCurrentState();
348 }
349
350 int SetReferenceBoard(const EventImp &evt)
351 {
352 if (!CheckEventSize(evt, 4))
353 return kSM_FatalError;
354
355 if (evt.GetUInt()>39)
356 {
357 Error("SetReferenceBoard - Board index out of range [0;39]");
358 return GetCurrentState();
359 }
360
361 fReference = kBoard;
362 fReferenceIdx = evt.GetUInt();
363
364 return GetCurrentState();
365 }
366
367 int SetReferencePatch(const EventImp &evt)
368 {
369 if (!CheckEventSize(evt, 4))
370 return kSM_FatalError;
371
372 if (evt.GetUInt()>159)
373 {
374 Error("SetReferencePatch - Patch index out of range [0;159]");
375 return GetCurrentState();
376 }
377
378 fReference = kPatch;
379 fReferenceIdx = evt.GetUInt();
380
381 return GetCurrentState();
382 }
383
384 int ChangeStepSize(const EventImp &evt)
385 {
386 if (!CheckEventSize(evt, 4))
387 return kSM_FatalError;
388
389 fThresholdStep = evt.Get<uint32_t>();
390
391 ostringstream msg;
392 msg << "New step size " << fThresholdStep;
393 Info(msg);
394
395 UpdateProc();
396
397 return GetCurrentState();
398 }
399
400 int ChangeMaximum(const EventImp &evt)
401 {
402 if (!CheckEventSize(evt, 4))
403 return kSM_FatalError;
404
405 fThresholdMax = evt.Get<uint32_t>();
406
407 return GetCurrentState();
408 }
409
410 int TriggerAutoPause()
411 {
412 fAutoPause = true;
413 return GetCurrentState();
414 }
415
416 int Pause()
417 {
418 return RateScan::State::kPaused;
419 }
420
421 int Resume()
422 {
423 return RateScan::State::kInProgress;
424 }
425
426 int Execute()
427 {
428 if (!fDim.online())
429 return RateScan::State::kDimNetworkNA;
430
431 // All subsystems are not connected
432 if (fDimFTM.state()<FTM::State::kConnected)
433 return RateScan::State::kDisconnected;
434
435 // ftmctrl connected to FTM
436 if (GetCurrentState()<=RateScan::State::kDisconnected)
437 return RateScan::State::kConnected;
438
439 return GetCurrentState();
440 }
441
442public:
443 StateMachineRateScan(ostream &out=cout) : StateMachineDim(out, "RATE_SCAN"),
444 fDimFTM("FTM_CONTROL"),
445 fDimData("RATE_SCAN/DATA", "X:1;I:1;F:1;F:1;F:1;F:40;F:160",
446 "|Id[s]:Start time used to identify measurement (UnixTime)"
447 "|Threshold[dac]:Threshold in DAC counts"
448 "|ElapsedTime[s]:Real elapsed time"
449 "|RelOnTime[ratio]:Relative on time"
450 "|TriggerRate[Hz]:Camera trigger rate"
451 "|BoardRate[Hz]:Board trigger rates"
452 "|PatchRate[Hz]:Patch trigger rates"),
453 fDimProc("RATE_SCAN/PROCESS_DATA", "I:1;I:1;I:1",
454 "Rate scan process data"
455 "|min[DAC]:Value at which scan was started"
456 "|max[DAC]:Value at which scan will end"
457 "|step[DAC]:Step size for scan"),
458 fAutoPause(false), fThreshold(-1), fReference(kCamera), fReferenceIdx(0)
459 {
460 // ba::io_service::work is a kind of keep_alive for the loop.
461 // It prevents the io_service to go to stopped state, which
462 // would prevent any consecutive calls to run()
463 // or poll() to do nothing. reset() could also revoke to the
464 // previous state but this might introduce some overhead of
465 // deletion and creation of threads and more.
466
467 fDim.Subscribe(*this);
468 fDimFTM.Subscribe(*this);
469 fDimFTM.SetCallback(bind(&StateMachineRateScan::HandleFtmStateChange, this));
470
471 Subscribe("FTM_CONTROL/TRIGGER_RATES")
472 (bind(&StateMachineRateScan::HandleTriggerRates, this, placeholders::_1));
473
474 // State names
475 AddStateName(RateScan::State::kDimNetworkNA, "DimNetworkNotAvailable",
476 "The Dim DNS is not reachable.");
477
478 AddStateName(RateScan::State::kDisconnected, "Disconnected",
479 "The Dim DNS is reachable, but the required subsystems are not available.");
480
481 AddStateName(RateScan::State::kConnected, "Connected",
482 "All needed subsystems are connected to their hardware, no action is performed.");
483
484 AddStateName(RateScan::State::kConfiguring, "Configuring",
485 "Waiting for FTM to get 'Configured'.");
486
487 AddStateName(RateScan::State::kInProgress, "InProgress",
488 "Rate scan in progress.");
489
490 AddStateName(RateScan::State::kPaused, "Paused",
491 "Rate scan in progress but paused.");
492
493 AddEvent("START_THRESHOLD_SCAN", "I:3;C", RateScan::State::kConnected)
494 (bind(&StateMachineRateScan::StartRateScan, this, placeholders::_1, "SET_THRESHOLD"))
495 ("Start rate scan for the threshold in the defined range"
496 "|min[int]:Start value in DAC counts"
497 "|max[int]:Limiting value in DAC counts"
498 "|step[int]:Single step in DAC counts"
499 "|type[text]:Ratescan type");
500
501 AddEvent("START_N_OUT_OF_4_SCAN", "I:3", RateScan::State::kConnected)
502 (bind(&StateMachineRateScan::StartRateScan, this, placeholders::_1, "SET_N_OUT_OF_4"))
503 ("Start rate scan for N-out-of-4 in the defined range"
504 "|min[int]:Start value in DAC counts"
505 "|max[int]:Limiting value in DAC counts"
506 "|step[int]:Single step in DAC counts");
507
508 AddEvent("CHANGE_STEP_SIZE", "I:1", RateScan::State::kPaused, RateScan::State::kInProgress)
509 (bind(&StateMachineRateScan::ChangeStepSize, this, placeholders::_1))
510 ("Change the step size during a ratescan in progress"
511 "|step[int]:Single step in DAC counts");
512
513 AddEvent("CHANGE_MAXIMUM", "I:1", RateScan::State::kPaused, RateScan::State::kInProgress)
514 (bind(&StateMachineRateScan::ChangeMaximum, this, placeholders::_1))
515 ("Change the maximum limit during a ratescan in progress"
516 "|max[int]:Limiting value in DAC counts");
517
518 AddEvent("STOP", RateScan::State::kConfiguring, RateScan::State::kPaused, RateScan::State::kInProgress)
519 (bind(&StateMachineRateScan::StopRateScan, this))
520 ("Stop a ratescan in progress");
521
522 AddEvent("SET_REFERENCE_CAMERA", RateScan::State::kDimNetworkNA, RateScan::State::kDisconnected, RateScan::State::kConnected)
523 (bind(&StateMachineRateScan::SetReferenceCamera, this))
524 ("Use the camera trigger rate as reference for the reolution");
525 AddEvent("SET_REFERENCE_BOARD", "I:1", RateScan::State::kDimNetworkNA, RateScan::State::kDisconnected, RateScan::State::kConnected)
526 (bind(&StateMachineRateScan::SetReferenceBoard, this, placeholders::_1))
527 ("Use the given board trigger-rate as reference for the reolution"
528 "|board[idx]:Index of the board (4*crate+board)");
529 AddEvent("SET_REFERENCE_PATCH", "I:1", RateScan::State::kDimNetworkNA, RateScan::State::kDisconnected, RateScan::State::kConnected)
530 (bind(&StateMachineRateScan::SetReferenceBoard, this, placeholders::_1))
531 ("Use the given patch trigger-rate as reference for the reolution"
532 "|patch[idx]:Index of the patch (360*crate+36*board+patch)");
533
534 AddEvent("TRIGGER_AUTO_PAUSE", RateScan::State::kDimNetworkNA, RateScan::State::kDisconnected, RateScan::State::kConnected)
535 (bind(&StateMachineRateScan::TriggerAutoPause, this))
536 ("Enable an automatic pause for the next ratescan, after it got configured.");
537
538 AddEvent("PAUSE", RateScan::State::kInProgress)
539 (bind(&StateMachineRateScan::Pause, this))
540 ("Pause a ratescan in progress");
541 AddEvent("RESUME", RateScan::State::kPaused)
542 (bind(&StateMachineRateScan::Resume, this))
543 ("Resume a paused ratescan");
544
545 AddEvent("PRINT")
546 (bind(&StateMachineRateScan::Print, this))
547 ("");
548 }
549
550 int EvalOptions(Configuration &conf)
551 {
552 // ---------- Setup run types ---------
553 const vector<string> types = conf.Vec<string>("type");
554 if (types.empty())
555 Warn("No types defined.");
556 else
557 Message("Defining types");
558
559 for (auto it=types.begin(); it!=types.end(); it++)
560 {
561 Message(" -> "+ *it);
562
563 if (fTypes.count(*it)>0)
564 {
565 Error("Type "+*it+" defined twice.");
566 return 1;
567 }
568
569 config &c = fTypes[*it];
570 if (conf.HasDef("max-wait.", *it))
571 c.fCounterMax = conf.GetDef<int>("max-wait.", *it);
572 else
573 {
574 Error("Neither max-wait.default nor max-wait."+*it+" found.");
575 return 2;
576 }
577 if (conf.HasDef("resolution.", *it))
578 c.fResolution = conf.GetDef<double>("resolution.", *it);
579 else
580 {
581 Error("Neither resolution.default nor resolution."+*it+" found.");
582 return 2;
583 }
584 }
585 return -1;
586 }
587};
588
589// ------------------------------------------------------------------------
590
591#include "Main.h"
592
593template<class T>
594int RunShell(Configuration &conf)
595{
596 return Main::execute<T, StateMachineRateScan>(conf);
597}
598
599void SetupConfiguration(Configuration &conf)
600{
601 po::options_description type("Ratescan type configuration");
602 type.add_options()
603 ("type", vars<string>(), "Name of ratescan types (replace the * in the following configuration by the case-sensitive names defined here)")
604 ("max-wait.*", var<int>(), "The maximum number of seconds to wait to get the anticipated resolution for a point.")
605 ("resolution.*", var<double>() , "The minimum resolution required for a single data point.")
606 ;
607
608 conf.AddOptions(type);
609}
610
611/*
612 Extract usage clause(s) [if any] for SYNOPSIS.
613 Translators: "Usage" and "or" here are patterns (regular expressions) which
614 are used to match the usage synopsis in program output. An example from cp
615 (GNU coreutils) which contains both strings:
616 Usage: cp [OPTION]... [-T] SOURCE DEST
617 or: cp [OPTION]... SOURCE... DIRECTORY
618 or: cp [OPTION]... -t DIRECTORY SOURCE...
619 */
620void PrintUsage()
621{
622 cout <<
623 "The ratescan program is a tool for automation of rate scans.\n"
624 "\n"
625 "Usage: ratescan [-c type] [OPTIONS]\n"
626 " or: ratescan [OPTIONS]\n";
627 cout << endl;
628}
629
630void PrintHelp()
631{
632 Main::PrintHelp<StateMachineRateScan>();
633
634 /* Additional help text which is printed after the configuration
635 options goes here */
636
637 /*
638 cout << "bla bla bla" << endl << endl;
639 cout << endl;
640 cout << "Environment:" << endl;
641 cout << "environment" << endl;
642 cout << endl;
643 cout << "Examples:" << endl;
644 cout << "test exam" << endl;
645 cout << endl;
646 cout << "Files:" << endl;
647 cout << "files" << endl;
648 cout << endl;
649 */
650}
651
652int main(int argc, const char* argv[])
653{
654 Configuration conf(argv[0]);
655 conf.SetPrintUsage(PrintUsage);
656 Main::SetupConfiguration(conf);
657 SetupConfiguration(conf);
658
659 if (!conf.DoParse(argc, argv, PrintHelp))
660 return 127;
661
662 //try
663 {
664 // No console access at all
665 if (!conf.Has("console"))
666 {
667// if (conf.Get<bool>("no-dim"))
668// return RunShell<LocalStream, StateMachine, ConnectionFSC>(conf);
669// else
670 return RunShell<LocalStream>(conf);
671 }
672 // Cosole access w/ and w/o Dim
673/* if (conf.Get<bool>("no-dim"))
674 {
675 if (conf.Get<int>("console")==0)
676 return RunShell<LocalShell, StateMachine, ConnectionFSC>(conf);
677 else
678 return RunShell<LocalConsole, StateMachine, ConnectionFSC>(conf);
679 }
680 else
681*/ {
682 if (conf.Get<int>("console")==0)
683 return RunShell<LocalShell>(conf);
684 else
685 return RunShell<LocalConsole>(conf);
686 }
687 }
688 /*catch (std::exception& e)
689 {
690 cerr << "Exception: " << e.what() << endl;
691 return -1;
692 }*/
693
694 return 0;
695}
Note: See TracBrowser for help on using the repository browser.