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

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