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

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