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

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