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

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