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

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