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

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