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

Last change on this file since 14560 was 14367, checked in by tbretz, 12 years ago
Added the missing Configuring state description; fixed the string sent to the FTM_CONTROL/CONFIGURE
File size: 17.5 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 "PixelMap.h"
12
13#include "tools.h"
14
15#include "LocalControl.h"
16
17#include "HeadersFTM.h"
18#include "HeadersRateScan.h"
19
20namespace ba = boost::asio;
21namespace bs = boost::system;
22
23using namespace std;
24
25// ------------------------------------------------------------------------
26
27#include "DimDescriptionService.h"
28#include "DimState.h"
29
30// ------------------------------------------------------------------------
31
32class StateMachineRateScan : public StateMachineDim
33{
34private:
35 DimVersion fDim;
36
37 DimDescribedState fDimFTM;
38 DimDescribedService fDimData;
39 DimDescribedService fDimProc;
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 (fCounter==0)
106 {
107 fRate = 0;
108
109 memset(fRateBoard, 0, 40*sizeof(double));
110 memset(fRatePatch, 0, 160*sizeof(double));
111
112 fOnTime = 0;
113 return GetCurrentState();
114 }
115/*
116 if (sdata.fTriggerRate==0)
117 {
118 Message("Rate scan stopped due zero trigger rate.");
119 fThreshold = -1;
120 return;
121 }
122*/
123
124 fRate += sdata.fTriggerRate;
125 for (int i=0; i<40; i++)
126 fRateBoard[i] += sdata.fBoardRate[i];
127 for (int i=0; i<160; i++)
128 fRatePatch[i] += sdata.fPatchRate[i];
129
130 double reference = fRate;
131 if (fReference==kBoard)
132 reference = fRateBoard[fReferenceIdx];
133 if (fReference==kPatch)
134 reference = fRatePatch[fReferenceIdx];
135
136 fOnTime += sdata.fOnTime;
137
138 reference *= sdata.fElapsedTime;
139
140 if ((reference==0 || sqrt(reference)>fResolution*reference) && fCounter<fCounterMax)
141 {
142 ostringstream out;
143 out << "Triggers so far: " << reference;
144 if (reference>0)
145 out << " (" << sqrt(reference)/reference << ")";
146 Info(out);
147
148 return GetCurrentState();
149 }
150
151 const double time = sdata.fElapsedTime*fCounter;
152 const uint32_t th = fThreshold;
153
154 float data[2+3+1+40+160];
155 memcpy(data, &fStartTime, 8);
156 memcpy(data+2, &th, 4);
157 data[3] = time; // total elapsed time
158 data[4] = fOnTime/time; // relative on time
159 data[5] = fRate/fCounter;
160 for (int i=0; i<40; i++)
161 data[i+6] = fRateBoard[i]/fCounter;
162 for (int i=0; i<160; i++)
163 data[i+46] = fRatePatch[i]/fCounter;
164
165 ostringstream sout1, sout2, sout3;
166
167 sout1 << th << " " << data[5];
168 for (int i=0; i<200; i++)
169 sout2 << " " << data[i+6];
170 sout3 << " " << data[3] << " " << data[4];
171
172 Info(sout1.str());
173
174 ofstream fout("ratescan.txt", ios::app);
175 fout << sout1.str() << sout2.str() << sout3.str() << endl;
176
177 fDimData.setQuality(fCommand=="FTM_CONTROL/SET_THRESHOLD");
178 fDimData.setData(data, sizeof(data));
179 fDimData.Update();
180
181 fThreshold += fThresholdStep;
182
183 if (fCounter>=fCounterMax)
184 {
185 Message("Rate scan stopped due to timeout.");
186 return RateScan::State::kConnected;
187 }
188
189 if (fThreshold>fThresholdMax)
190 {
191 Message("Rate scan finished.");
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 DimClient::sendCommandNB(fCommand.c_str(), (void*)cmd, 8);
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::SendCommand("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 // All subsystems are not connected
249 if (fDimFTM.state()<FTM::State::kConnected)
250 return RateScan::State::kDisconnected;
251
252 // ftmctrl connected to FTM
253 if (GetCurrentState()==RateScan::State::kDisconnected)
254 return RateScan::State::kConnected;
255
256 if (GetCurrentState()!=RateScan::State::kConfiguring)
257 return GetCurrentState();
258
259 if (fDimFTM.state()!=FTM::State::kConfigured)
260 return GetCurrentState();
261
262 const int32_t data[2] = { -1, fThresholdMin };
263
264 Dim::SendCommand(fCommand, data);
265
266 fThreshold = fThresholdMin;
267 fCounter = -2;
268
269 const Time now;
270 fStartTime = trunc(now.UnixTime());
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 ostringstream msg;
286 msg << "Rate scan " << now << "(" << fStartTime << ") from " << fThresholdMin << " to ";
287 msg << fThresholdMax << " in steps of " << fThresholdStep;
288 msg << " started.";
289 Message(msg);
290
291 return RateScan::State::kInProgress;
292 }
293
294 int StopRateScan()
295 {
296 if (GetCurrentState()!=RateScan::State::kConfiguring && GetCurrentState()!=RateScan::State::kInProgress)
297 return GetCurrentState();
298
299 Message("Rate scan manually stopped.");
300
301 return RateScan::State::kConnected;
302 }
303
304 int SetReferenceCamera()
305 {
306 fReference = kCamera;
307
308 return GetCurrentState();
309 }
310
311 int SetReferenceBoard(const EventImp &evt)
312 {
313 if (!CheckEventSize(evt, 4))
314 return kSM_FatalError;
315
316 if (evt.GetUInt()>39)
317 {
318 Error("SetReferenceBoard - Board index out of range [0;39]");
319 return GetCurrentState();
320 }
321
322 fReference = kBoard;
323 fReferenceIdx = evt.GetUInt();
324
325 return GetCurrentState();
326 }
327
328 int SetReferencePatch(const EventImp &evt)
329 {
330 if (!CheckEventSize(evt, 4))
331 return kSM_FatalError;
332
333 if (evt.GetUInt()>159)
334 {
335 Error("SetReferencePatch - Patch index out of range [0;159]");
336 return GetCurrentState();
337 }
338
339 fReference = kPatch;
340 fReferenceIdx = evt.GetUInt();
341
342 return GetCurrentState();
343 }
344
345 int ChangeStepSize(const EventImp &evt)
346 {
347 if (!CheckEventSize(evt, 4))
348 return kSM_FatalError;
349
350 fThresholdStep = evt.Get<uint32_t>();
351
352 ostringstream msg;
353 msg << "New step size " << fThresholdStep;
354 Info(msg);
355
356 UpdateProc();
357
358 return GetCurrentState();
359 }
360
361 int ChangeMaximum(const EventImp &evt)
362 {
363 if (!CheckEventSize(evt, 4))
364 return kSM_FatalError;
365
366 fThresholdMax = evt.Get<uint32_t>();
367
368 return GetCurrentState();
369 }
370
371 int Execute()
372 {
373 if (!fDim.online())
374 return RateScan::State::kDimNetworkNA;
375
376 return GetCurrentState();
377 }
378
379public:
380 StateMachineRateScan(ostream &out=cout) : StateMachineDim(out, "RATE_SCAN"),
381 fDimFTM("FTM_CONTROL"),
382 fDimData("RATE_SCAN/DATA", "X:1;I:1;F:1;F:1;F:1;F:40;F:160",
383 "|Id[s]:Start time used to identify measurement (UnixTime)"
384 "|Threshold[dac]:Threshold in DAC counts"
385 "|ElapsedTime[s]:Real elapsed time"
386 "|RelOnTime[ratio]:Relative on time"
387 "|TriggerRate[Hz]:Camera trigger rate"
388 "|BoardRate[Hz]:Board trigger rates"
389 "|PatchRate[Hz]:Patch trigger rates"),
390 fDimProc("RATE_SCAN/PROCESS_DATA", "I:1;I:1;I:1",
391 "Rate scan process data"
392 "|min[DAC]:Value at which scan was started"
393 "|max[DAC]:Value at which scan will end"
394 "|step[DAC]:Step size for scan"),
395 fThreshold(-1), fReference(kCamera), fReferenceIdx(0)
396 {
397 // ba::io_service::work is a kind of keep_alive for the loop.
398 // It prevents the io_service to go to stopped state, which
399 // would prevent any consecutive calls to run()
400 // or poll() to do nothing. reset() could also revoke to the
401 // previous state but this might introduce some overhead of
402 // deletion and creation of threads and more.
403
404 fDim.Subscribe(*this);
405 fDimFTM.Subscribe(*this);
406 fDimFTM.SetCallback(bind(&StateMachineRateScan::HandleFtmStateChange, this));
407
408 Subscribe("FTM_CONTROL/TRIGGER_RATES")
409 (bind(&StateMachineRateScan::HandleTriggerRates, this, placeholders::_1));
410
411 // State names
412 AddStateName(RateScan::State::kDimNetworkNA, "DimNetworkNotAvailable",
413 "The Dim DNS is not reachable.");
414
415 AddStateName(RateScan::State::kDisconnected, "Disconnected",
416 "The Dim DNS is reachable, but the required subsystems are not available.");
417
418 AddStateName(RateScan::State::kConnected, "Connected",
419 "All needed subsystems are connected to their hardware, no action is performed.");
420
421 AddStateName(RateScan::State::kConfiguring, "Configuring",
422 "Waiting for FTM to get 'Configured'.");
423
424 AddStateName(RateScan::State::kInProgress, "InProgress",
425 "Rate scan in progress.");
426
427 AddEvent("START_THRESHOLD_SCAN", "I:3", RateScan::State::kConnected)
428 (bind(&StateMachineRateScan::StartRateScan, this, placeholders::_1, "SET_THRESHOLD"))
429 ("Start rate scan for the threshold in the defined range"
430 "|min[int]:Start value in DAC counts"
431 "|max[int]:Limiting value in DAC counts"
432 "|step[int]:Single step in DAC counts");
433
434 AddEvent("START_N_OUT_OF_4_SCAN", "I:3", RateScan::State::kConnected)
435 (bind(&StateMachineRateScan::StartRateScan, this, placeholders::_1, "SET_N_OUT_OF_4"))
436 ("Start rate scan for N-out-of-4 in the defined range"
437 "|min[int]:Start value in DAC counts"
438 "|max[int]:Limiting value in DAC counts"
439 "|step[int]:Single step in DAC counts");
440
441 AddEvent("CHANGE_STEP_SIZE", "I:1", RateScan::State::kInProgress)
442 (bind(&StateMachineRateScan::ChangeStepSize, this, placeholders::_1))
443 ("Change the step size during a ratescan in progress"
444 "|step[int]:Single step in DAC counts");
445
446 AddEvent("CHANGE_MAXIMUM", "I:1", RateScan::State::kInProgress)
447 (bind(&StateMachineRateScan::ChangeMaximum, this, placeholders::_1))
448 ("Change the maximum limit during a ratescan in progress"
449 "|max[int]:Limiting value in DAC counts");
450
451 AddEvent("STOP", RateScan::State::kConfiguring, RateScan::State::kInProgress)
452 (bind(&StateMachineRateScan::StopRateScan, this))
453 ("Stop a ratescan in progress");
454
455 AddEvent("SET_REFERENCE_CAMERA", RateScan::State::kDimNetworkNA, RateScan::State::kDisconnected, RateScan::State::kConnected)
456 (bind(&StateMachineRateScan::SetReferenceCamera, this))
457 ("Use the camera trigger rate as reference for the reolution");
458 AddEvent("SET_REFERENCE_BOARD", "I:1", RateScan::State::kDimNetworkNA, RateScan::State::kDisconnected, RateScan::State::kConnected)
459 (bind(&StateMachineRateScan::SetReferenceBoard, this, placeholders::_1))
460 ("Use the given board trigger-rate as reference for the reolution"
461 "|board[idx]:Index of the board (4*crate+board)");
462 AddEvent("SET_REFERENCE_PATCH", "I:1", RateScan::State::kDimNetworkNA, RateScan::State::kDisconnected, RateScan::State::kConnected)
463 (bind(&StateMachineRateScan::SetReferenceBoard, this, placeholders::_1))
464 ("Use the given patch trigger-rate as reference for the reolution"
465 "|patch[idx]:Index of the patch (360*crate+36*board+patch)");
466
467 AddEvent("PRINT")
468 (bind(&StateMachineRateScan::Print, this))
469 ("");
470 }
471
472 int EvalOptions(Configuration &conf)
473 {
474 fCounterMax = conf.Get<uint16_t>("max-wait");
475 fResolution = conf.Get<double>("resolution");
476
477 return -1;
478 }
479};
480
481// ------------------------------------------------------------------------
482
483#include "Main.h"
484
485template<class T>
486int RunShell(Configuration &conf)
487{
488 return Main::execute<T, StateMachineRateScan>(conf);
489}
490
491void SetupConfiguration(Configuration &conf)
492{
493 po::options_description control("Rate scan options");
494 control.add_options()
495 ("max-wait", var<uint16_t>(150), "The maximum number of seconds to wait to get the anticipated resolution for a point.")
496 ("resolution", var<double>(0.05) , "The minimum resolution required for a single data point.")
497 ;
498
499 conf.AddOptions(control);
500}
501
502/*
503 Extract usage clause(s) [if any] for SYNOPSIS.
504 Translators: "Usage" and "or" here are patterns (regular expressions) which
505 are used to match the usage synopsis in program output. An example from cp
506 (GNU coreutils) which contains both strings:
507 Usage: cp [OPTION]... [-T] SOURCE DEST
508 or: cp [OPTION]... SOURCE... DIRECTORY
509 or: cp [OPTION]... -t DIRECTORY SOURCE...
510 */
511void PrintUsage()
512{
513 cout <<
514 "The ratescan program is a tool for automation of rate scans.\n"
515 "\n"
516 "Usage: ratescan [-c type] [OPTIONS]\n"
517 " or: ratescan [OPTIONS]\n";
518 cout << endl;
519}
520
521void PrintHelp()
522{
523 Main::PrintHelp<StateMachineRateScan>();
524
525 /* Additional help text which is printed after the configuration
526 options goes here */
527
528 /*
529 cout << "bla bla bla" << endl << endl;
530 cout << endl;
531 cout << "Environment:" << endl;
532 cout << "environment" << endl;
533 cout << endl;
534 cout << "Examples:" << endl;
535 cout << "test exam" << endl;
536 cout << endl;
537 cout << "Files:" << endl;
538 cout << "files" << endl;
539 cout << endl;
540 */
541}
542
543int main(int argc, const char* argv[])
544{
545 Configuration conf(argv[0]);
546 conf.SetPrintUsage(PrintUsage);
547 Main::SetupConfiguration(conf);
548 SetupConfiguration(conf);
549
550 if (!conf.DoParse(argc, argv, PrintHelp))
551 return 127;
552
553 //try
554 {
555 // No console access at all
556 if (!conf.Has("console"))
557 {
558// if (conf.Get<bool>("no-dim"))
559// return RunShell<LocalStream, StateMachine, ConnectionFSC>(conf);
560// else
561 return RunShell<LocalStream>(conf);
562 }
563 // Cosole access w/ and w/o Dim
564/* if (conf.Get<bool>("no-dim"))
565 {
566 if (conf.Get<int>("console")==0)
567 return RunShell<LocalShell, StateMachine, ConnectionFSC>(conf);
568 else
569 return RunShell<LocalConsole, StateMachine, ConnectionFSC>(conf);
570 }
571 else
572*/ {
573 if (conf.Get<int>("console")==0)
574 return RunShell<LocalShell>(conf);
575 else
576 return RunShell<LocalConsole>(conf);
577 }
578 }
579 /*catch (std::exception& e)
580 {
581 cerr << "Exception: " << e.what() << endl;
582 return -1;
583 }*/
584
585 return 0;
586}
Note: See TracBrowser for help on using the repository browser.