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

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