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

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