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

Last change on this file since 16954 was 16866, checked in by tbretz, 11 years ago
Removed the output of the ratescans to an ascii file. Sending it to the datalogger has proven to be stable.
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::kConfigured1)
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 /*
267 ofstream fout("ratescan.txt", ios::app);
268 fout << "# ----- " << now << " (" << fStartTime << ") -----\n";
269 fout << "# Command: " << fCommand << '\n';
270 fout << "# Reference: ";
271 switch (fReference)
272 {
273 case kCamera: fout << "Camera"; break;
274 case kBoard: fout << "Board #" << fReferenceIdx; break;
275 case kPatch: fout << "Patch #" << fReferenceIdx; break;
276 }
277 fout << '\n';
278 fout << "# -----" << endl;
279 */
280
281 ostringstream msg;
282 msg << "Rate scan " << now << "(" << fStartTime << ") from " << fThresholdMin << " to ";
283 msg << fThresholdMax << " in steps of " << fThresholdStep;
284 msg << " started.";
285 Message(msg);
286
287 return RateScan::State::kInProgress;
288 }
289
290 int StopRateScan()
291 {
292 if (GetCurrentState()!=RateScan::State::kConfiguring && GetCurrentState()!=RateScan::State::kInProgress)
293 return GetCurrentState();
294
295 Dim::SendCommandNB("FTM_CONTROL/RESET_CONFIGURE");
296 Message("Rate scan manually stopped.");
297
298 return RateScan::State::kConnected;
299 }
300
301 int SetReferenceCamera()
302 {
303 fReference = kCamera;
304
305 return GetCurrentState();
306 }
307
308 int SetReferenceBoard(const EventImp &evt)
309 {
310 if (!CheckEventSize(evt, 4))
311 return kSM_FatalError;
312
313 if (evt.GetUInt()>39)
314 {
315 Error("SetReferenceBoard - Board index out of range [0;39]");
316 return GetCurrentState();
317 }
318
319 fReference = kBoard;
320 fReferenceIdx = evt.GetUInt();
321
322 return GetCurrentState();
323 }
324
325 int SetReferencePatch(const EventImp &evt)
326 {
327 if (!CheckEventSize(evt, 4))
328 return kSM_FatalError;
329
330 if (evt.GetUInt()>159)
331 {
332 Error("SetReferencePatch - Patch index out of range [0;159]");
333 return GetCurrentState();
334 }
335
336 fReference = kPatch;
337 fReferenceIdx = evt.GetUInt();
338
339 return GetCurrentState();
340 }
341
342 int ChangeStepSize(const EventImp &evt)
343 {
344 if (!CheckEventSize(evt, 4))
345 return kSM_FatalError;
346
347 fThresholdStep = evt.Get<uint32_t>();
348
349 ostringstream msg;
350 msg << "New step size " << fThresholdStep;
351 Info(msg);
352
353 UpdateProc();
354
355 return GetCurrentState();
356 }
357
358 int ChangeMaximum(const EventImp &evt)
359 {
360 if (!CheckEventSize(evt, 4))
361 return kSM_FatalError;
362
363 fThresholdMax = evt.Get<uint32_t>();
364
365 return GetCurrentState();
366 }
367
368 int Execute()
369 {
370 if (!fDim.online())
371 return RateScan::State::kDimNetworkNA;
372
373 // All subsystems are not connected
374 if (fDimFTM.state()<FTM::State::kConnected)
375 return RateScan::State::kDisconnected;
376
377 // ftmctrl connected to FTM
378 if (GetCurrentState()<=RateScan::State::kDisconnected)
379 return RateScan::State::kConnected;
380
381 return GetCurrentState();
382 }
383
384public:
385 StateMachineRateScan(ostream &out=cout) : StateMachineDim(out, "RATE_SCAN"),
386 fDimFTM("FTM_CONTROL"),
387 fDimData("RATE_SCAN/DATA", "X:1;I:1;F:1;F:1;F:1;F:40;F:160",
388 "|Id[s]:Start time used to identify measurement (UnixTime)"
389 "|Threshold[dac]:Threshold in DAC counts"
390 "|ElapsedTime[s]:Real elapsed time"
391 "|RelOnTime[ratio]:Relative on time"
392 "|TriggerRate[Hz]:Camera trigger rate"
393 "|BoardRate[Hz]:Board trigger rates"
394 "|PatchRate[Hz]:Patch trigger rates"),
395 fDimProc("RATE_SCAN/PROCESS_DATA", "I:1;I:1;I:1",
396 "Rate scan process data"
397 "|min[DAC]:Value at which scan was started"
398 "|max[DAC]:Value at which scan will end"
399 "|step[DAC]:Step size for scan"),
400 fThreshold(-1), fReference(kCamera), fReferenceIdx(0)
401 {
402 // ba::io_service::work is a kind of keep_alive for the loop.
403 // It prevents the io_service to go to stopped state, which
404 // would prevent any consecutive calls to run()
405 // or poll() to do nothing. reset() could also revoke to the
406 // previous state but this might introduce some overhead of
407 // deletion and creation of threads and more.
408
409 fDim.Subscribe(*this);
410 fDimFTM.Subscribe(*this);
411 fDimFTM.SetCallback(bind(&StateMachineRateScan::HandleFtmStateChange, this));
412
413 Subscribe("FTM_CONTROL/TRIGGER_RATES")
414 (bind(&StateMachineRateScan::HandleTriggerRates, this, placeholders::_1));
415
416 // State names
417 AddStateName(RateScan::State::kDimNetworkNA, "DimNetworkNotAvailable",
418 "The Dim DNS is not reachable.");
419
420 AddStateName(RateScan::State::kDisconnected, "Disconnected",
421 "The Dim DNS is reachable, but the required subsystems are not available.");
422
423 AddStateName(RateScan::State::kConnected, "Connected",
424 "All needed subsystems are connected to their hardware, no action is performed.");
425
426 AddStateName(RateScan::State::kConfiguring, "Configuring",
427 "Waiting for FTM to get 'Configured'.");
428
429 AddStateName(RateScan::State::kInProgress, "InProgress",
430 "Rate scan in progress.");
431
432 AddEvent("START_THRESHOLD_SCAN", "I:3", RateScan::State::kConnected)
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", RateScan::State::kConnected)
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", RateScan::State::kInProgress)
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", RateScan::State::kInProgress)
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", RateScan::State::kConfiguring, RateScan::State::kInProgress)
457 (bind(&StateMachineRateScan::StopRateScan, this))
458 ("Stop a ratescan in progress");
459
460 AddEvent("SET_REFERENCE_CAMERA", RateScan::State::kDimNetworkNA, RateScan::State::kDisconnected, RateScan::State::kConnected)
461 (bind(&StateMachineRateScan::SetReferenceCamera, this))
462 ("Use the camera trigger rate as reference for the reolution");
463 AddEvent("SET_REFERENCE_BOARD", "I:1", RateScan::State::kDimNetworkNA, RateScan::State::kDisconnected, RateScan::State::kConnected)
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", RateScan::State::kDimNetworkNA, RateScan::State::kDisconnected, RateScan::State::kConnected)
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 127;
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.