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

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