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

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