source: trunk/FACT++/src/ratecontrol.cc@ 15784

Last change on this file since 15784 was 15361, checked in by tbretz, 11 years ago
Implemented the latest results from the ratescan fits and strengthened the limits to take action for single patches.
File size: 29.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 "externals/PixelMap.h"
11
12#include "tools.h"
13
14#include "LocalControl.h"
15
16#include "HeadersFTM.h"
17#include "HeadersDrive.h"
18#include "HeadersRateScan.h"
19#include "HeadersRateControl.h"
20
21namespace ba = boost::asio;
22namespace bs = boost::system;
23namespace dummy = ba::placeholders;
24
25using namespace std;
26
27// ------------------------------------------------------------------------
28
29#include "DimDescriptionService.h"
30#include "DimState.h"
31
32// ------------------------------------------------------------------------
33
34class StateMachineRateControl : public StateMachineDim//, public DimInfoHandler
35{
36private:
37 struct config
38 {
39 uint16_t fCalibrationType;
40 uint16_t fTargetRate;
41 uint16_t fMinThreshold;
42 uint16_t fAverageTime;
43 uint16_t fRequiredEvents;
44 };
45
46 map<string, config> fRunTypes;
47
48 PixelMap fMap;
49
50 bool fTriggerOn;
51
52 vector<bool> fBlock;
53
54 DimVersion fDim;
55 DimDescribedState fDimFTM;
56 DimDescribedState fDimRS;
57 DimDescribedState fDimDrive;
58
59 DimDescribedService fDimThreshold;
60
61 float fTargetRate;
62 float fTriggerRate;
63
64 uint16_t fThresholdMin;
65 uint16_t fThresholdReference;
66
67 uint16_t fAverageTime;
68 uint16_t fRequiredEvents;
69
70 deque<pair<Time,float>> fCurrentsMed;
71 deque<pair<Time,float>> fCurrentsDev;
72 deque<pair<Time,vector<float>>> fCurrentsVec;
73
74 bool fVerbose;
75 bool fCalibrateByCurrent;
76
77 uint64_t fCounter;
78
79 Time fCalibrationTimeStart;
80
81 bool CheckEventSize(const EventImp &evt, size_t size)
82 {
83 if (size_t(evt.GetSize())==size)
84 return true;
85
86 if (evt.GetSize()==0)
87 return false;
88
89 ostringstream msg;
90 msg << evt.GetName() << " - Received event has " << evt.GetSize() << " bytes, but expected " << size << ".";
91 Fatal(msg);
92 return false;
93 }
94
95 vector<uint16_t> fThresholds;
96
97 void PrintThresholds(const FTM::DimStaticData &sdata)
98 {
99 //if (!fVerbose)
100 // return;
101
102 if (fThresholds.size()==0)
103 return;
104
105 Out() << "Min. DAC=" << fThresholdMin << endl;
106
107 int t=0;
108 for (t=0; t<160; t++)
109 if (sdata.fThreshold[t]!=fThresholds[t])
110 break;
111
112 if (t==160)
113 return;
114
115 for (int j=0; j<10; j++)
116 {
117 for (int k=0; k<4; k++)
118 {
119 for (int i=0; i<4; i++)
120 if (fThresholds[i+k*4+j*16]!=fThresholdMin)
121 Out() << setw(3) << fThresholds[i+k*4+j*16] << " ";
122 else
123 Out() << " - ";
124 Out() << " ";
125 }
126 Out() << endl;
127 }
128 Out() << endl;
129 }
130
131 void Step(int idx, float step)
132 {
133 uint16_t diff = fThresholds[idx]+int16_t(truncf(step));
134 if (diff<fThresholdMin)
135 diff=fThresholdMin;
136
137 if (diff==fThresholds[idx])
138 return;
139
140 if (fVerbose)
141 {
142 Out() << idx/40 << "|" << (idx/4)%10 << "|" << idx%4;
143 Out() << (step>0 ? " += " : " -= ");
144 Out() << fabs(step) << " (" << diff << ")" << endl;
145 }
146
147 const uint32_t val[2] = { idx, diff };
148 DimClient::sendCommandNB("FTM_CONTROL/SET_THRESHOLD", (void*)val, 8);
149
150 fBlock[idx/4] = true;
151 }
152
153 void ProcessPatches(const FTM::DimTriggerRates &sdata)
154 {
155
156 // Caluclate Median and deviation
157 vector<float> medb(sdata.fBoardRate, sdata.fBoardRate+40);
158 vector<float> medp(sdata.fPatchRate, sdata.fPatchRate+160);
159
160 sort(medb.begin(), medb.end());
161 sort(medp.begin(), medp.end());
162
163 vector<float> devb(40);
164 for (int i=0; i<40; i++)
165 devb[i] = fabs(sdata.fBoardRate[i]-medb[i]);
166
167 vector<float> devp(160);
168 for (int i=0; i<160; i++)
169 devp[i] = fabs(sdata.fPatchRate[i]-medp[i]);
170
171 sort(devb.begin(), devb.end());
172 sort(devp.begin(), devp.end());
173
174 double mb = (medb[19]+medb[20])/2;
175 double mp = (medp[79]+medp[80])/2;
176
177 double db = devb[27];
178 double dp = devp[109];
179
180 // If any is zero there is something wrong
181 if (mb==0 || mp==0 || db==0 || dp==0)
182 return;
183
184 if (fVerbose)
185 Out() << Tools::Form("Board: Med=%3.1f +- %3.1f Patch: Med=%3.1f +- %3.1f", mb, db, mp, dp) << endl;
186
187 for (int i=0; i<40; i++)
188 {
189 if (fBlock[i])
190 {
191 fBlock[i] = false;
192 continue;
193 }
194
195 int maxi = -1;
196
197 const float dif = fabs(sdata.fBoardRate[i]-mb)/db;
198 if (dif>3)
199 {
200 if (fVerbose)
201 Out() << "B" << i << ": " << dif << endl;
202
203 float max = sdata.fPatchRate[i*4];
204 maxi = 0;
205
206 for (int j=1; j<4; j++)
207 if (sdata.fPatchRate[i*4+j]>max)
208 {
209 max = sdata.fPatchRate[i*4+j];
210 maxi = j;
211 }
212 }
213
214 for (int j=0; j<4; j++)
215 {
216 // For the noise pixel correct down to median+3*deviation
217 if (maxi==j)
218 {
219 // This is the step which has to be performed to go from
220 // a NSB rate of sdata.fPatchRate[i*4+j]
221
222
223 const float step = (log10(sdata.fPatchRate[i*4+j])-log10(mp+3.5*dp))/0.039;
224 // * (dif-5)/dif
225 Step(i*4+j, step);
226 continue;
227 }
228
229 // For pixels below the median correct also back to median+3*deviation
230 if (sdata.fPatchRate[i*4+j]<mp)
231 {
232 const float step = (log10(sdata.fPatchRate[i*4+j])-log10(mp+3.5*dp))/0.039;
233 Step(i*4+j, step);
234 continue;
235 }
236
237 const float step = -1.5*(log10(mp+dp)-log10(mp))/0.039;
238 Step(i*4+j, step);
239 }
240 }
241 }
242
243 int ProcessCamera(const FTM::DimTriggerRates &sdata)
244 {
245 if (fCounter++==0)
246 return GetCurrentState();
247
248 // Caluclate Median and deviation
249 vector<float> medb(sdata.fBoardRate, sdata.fBoardRate+40);
250
251 sort(medb.begin(), medb.end());
252
253 vector<float> devb(40);
254 for (int i=0; i<40; i++)
255 devb[i] = fabs(sdata.fBoardRate[i]-medb[i]);
256
257 sort(devb.begin(), devb.end());
258
259 double mb = (medb[19]+medb[20])/2;
260 double db = devb[27];
261
262 // If any is zero there is something wrong
263 if (mb==0 || db==0)
264 {
265 Warn("The median or the deviation of all board rates is zero... cannot calibrate.");
266 return GetCurrentState();
267 }
268
269 double avg = 0;
270 int num = 0;
271
272 for (int i=0; i<40; i++)
273 {
274 if ( fabs(sdata.fBoardRate[i]-mb)<2.5*db)
275 {
276 avg += sdata.fBoardRate[i];
277 num++;
278 }
279 }
280
281 fTriggerRate = avg/num * 40;
282
283 if (fVerbose)
284 {
285 Out() << "Board: Median=" << mb << " Dev=" << db << endl;
286 Out() << "Camera: " << fTriggerRate << " (" << sdata.fTriggerRate << ", n=" << num << ")" << endl;
287 Out() << "Target: " << fTargetRate << endl;
288 }
289
290 if (sdata.fTriggerRate<fTriggerRate)
291 fTriggerRate = sdata.fTriggerRate;
292
293 // ----------------------
294
295 /*
296 if (avg>0 && avg<fTargetRate)
297 {
298 // I am assuming here (and at other places) the the answer from the FTM when setting
299 // the new threshold always arrives faster than the next rate update.
300 fThresholdMin = fThresholds[0];
301 Out() << "Setting fThresholdMin to " << fThresholds[0] << endl;
302 }
303 */
304
305 if (fTriggerRate>0 && fTriggerRate<fTargetRate)
306 {
307 fThresholds.assign(160, fThresholdMin);
308
309 const RateControl::DimThreshold data = { fThresholdMin, fCalibrationTimeStart.Mjd(), Time().Mjd() };
310 fDimThreshold.setQuality(0);
311 fDimThreshold.Update(data);
312
313 ostringstream out;
314 out << setprecision(3);
315 out << "Measured rate " << fTriggerRate << "Hz below target rate " << fTargetRate << "... mininum threshold set to " << fThresholdMin;
316 Info(out);
317
318 return RateControl::State::kGlobalThresholdSet;
319 }
320
321 // This is a step towards a threshold at which the NSB rate is equal the target rate
322 // +1 to avoid getting a step of 0
323 const float step = (log10(fTriggerRate)-log10(fTargetRate))/0.039 + 1;
324
325 const uint16_t diff = fThresholdMin+int16_t(truncf(step));
326 if (diff<=fThresholdMin)
327 {
328 const RateControl::DimThreshold data = { fThresholdMin, fCalibrationTimeStart.Mjd(), Time().Mjd() };
329 fDimThreshold.setQuality(1);
330 fDimThreshold.Update(data);
331
332 ostringstream out;
333 out << setprecision(3);
334 out << "Next step would be 0... mininum threshold set to " << fThresholdMin;
335 Info(out);
336
337 return RateControl::State::kGlobalThresholdSet;
338 }
339
340 if (fVerbose)
341 {
342 //Out() << idx/40 << "|" << (idx/4)%10 << "|" << idx%4;
343 Out() << fThresholdMin;
344 Out() << (step>0 ? " += " : " -= ");
345 Out() << step << " (" << diff << ")" << endl;
346 }
347
348 const uint32_t val[2] = { -1, diff };
349 DimClient::sendCommandNB("FTM_CONTROL/SET_THRESHOLD", (void*)val, 8);
350
351 fThresholdMin = diff;
352
353 return GetCurrentState();
354 }
355
356 int HandleStaticData(const EventImp &evt)
357 {
358 if (!CheckEventSize(evt, sizeof(FTM::DimStaticData)))
359 return GetCurrentState();
360
361 const FTM::DimStaticData &sdata = *static_cast<const FTM::DimStaticData*>(evt.GetData());
362 fTriggerOn = sdata.HasTrigger();
363
364 PrintThresholds(sdata);
365
366 fThresholds.assign(sdata.fThreshold, sdata.fThreshold+160);
367
368 return GetCurrentState();
369 }
370
371 int HandleTriggerRates(const EventImp &evt)
372 {
373 if (fThresholds.size()==0)
374 return GetCurrentState();
375
376 if (GetCurrentState()<=RateControl::State::kConnected ||
377 GetCurrentState()==RateControl::State::kGlobalThresholdSet)
378 return GetCurrentState();
379
380 if (!CheckEventSize(evt, sizeof(FTM::DimTriggerRates)))
381 return GetCurrentState();
382
383 const FTM::DimTriggerRates &sdata = *static_cast<const FTM::DimTriggerRates*>(evt.GetData());
384
385 if (GetCurrentState()==RateControl::State::kSettingGlobalThreshold && !fCalibrateByCurrent)
386 return ProcessCamera(sdata);
387
388 if (GetCurrentState()==RateControl::State::kInProgress)
389 ProcessPatches(sdata);
390
391 return GetCurrentState();
392 }
393
394 int HandleCalibratedCurrents(const EventImp &evt)
395 {
396 // Check if received event is valid
397 if (!CheckEventSize(evt, (416+6)*4))
398 return GetCurrentState();
399
400 // Record only currents when the drive is tracking to avoid
401 // bias from the movement
402 if (fDimDrive.state()<Drive::State::kTracking)
403 return GetCurrentState();
404
405 // Get time and median current (FIXME: check N?)
406 const Time &time = evt.GetTime();
407 const float med = evt.Get<float>(416*4+4+4);
408 const float dev = evt.Get<float>(416*4+4+4+4);
409 const float *cur = evt.Ptr<float>();
410
411 // Keep all median currents of the past 10 seconds
412 fCurrentsMed.push_back(make_pair(time, med));
413 fCurrentsDev.push_back(make_pair(time, dev));
414 fCurrentsVec.push_back(make_pair(time, vector<float>(cur, cur+320)));
415 while (!fCurrentsMed.empty())
416 {
417 if (time-fCurrentsMed.front().first<boost::posix_time::seconds(fAverageTime))
418 break;
419
420 fCurrentsMed.pop_front();
421 fCurrentsDev.pop_front();
422 fCurrentsVec.pop_front();
423 }
424
425 // If we are not doing a calibration no further action necessary
426 if (!fCalibrateByCurrent)
427 return GetCurrentState();
428
429 if (GetCurrentState()!=RateControl::State::kSettingGlobalThreshold)
430 return GetCurrentState();
431
432 // We want at least 8 values for averaging
433 if (fCurrentsMed.size()<fRequiredEvents)
434 return GetCurrentState();
435
436 // Calculate avera and rms of median
437 double avg = 0;
438 double rms = 0;
439 for (auto it=fCurrentsMed.begin(); it!=fCurrentsMed.end(); it++)
440 {
441 avg += it->second;
442 rms += it->second*it->second;
443 }
444 avg /= fCurrentsMed.size();
445 rms /= fCurrentsMed.size();
446 rms = sqrt(rms-avg*avg);
447
448 double avg_dev = 0;
449 for (auto it=fCurrentsDev.begin(); it!=fCurrentsDev.end(); it++)
450 avg_dev += it->second;
451 avg_dev /= fCurrentsMed.size();
452
453 // One could recalculate the median of all pixels incluing the
454 // correction for the three crazy pixels, but that is three out
455 // of 320. The effect on the median should be negligible anyhow.
456 vector<double> vec(160);
457 for (auto it=fCurrentsVec.begin(); it!=fCurrentsVec.end(); it++)
458 for (int i=0; i<320; i++)
459 {
460 const PixelMapEntry &hv = fMap.hv(i);
461 if (!hv)
462 continue;
463
464 // The current is proportional to the rate. To calculate
465 // a measure for the rate, the average current per pixel
466 // is caluclated for the trigger patch.
467 int weight = hv.group() ? 5 : 4;
468
469 // Use only the current in the pixels with the correct
470 // resistor as a reference, ignore the crazy ones.
471 // Effects of these should be corrected by the
472 // rate control later, not the initial setup.
473 if (i==66)
474 weight = 4./(3+10);
475 if (i==191 || i==193)
476 weight = 5./(4+10);
477
478 vec[hv.hw()/9] += it->second[i] * weight;
479 }
480
481 //fThresholdMin = max(uint16_t(36.0833*pow(avg, 0.638393)+184.037), fThresholdReference);
482 //fThresholdMin = max(uint16_t(42.4*pow(avg, 0.642)+182), fThresholdReference);
483 //fThresholdMin = max(uint16_t(41.6*pow(avg+1, 0.642)+175), fThresholdReference);
484 //fThresholdMin = max(uint16_t(42.3*pow(avg, 0.655)+190), fThresholdReference);
485 fThresholdMin = max(uint16_t(46.6*pow(avg, 0.627)+187), fThresholdReference);
486 //fThresholdMin = max(uint16_t(41.6*pow(avg, 0.642)+175), fThresholdReference);
487 fThresholds.assign(160, fThresholdMin);
488
489 const int32_t val[2] = { -1, fThresholdMin };
490 Dim::SendCommand("FTM_CONTROL/SET_THRESHOLD", val);
491
492 double avg2 = 0;
493 for (int i=0; i<160; i++)
494 {
495 vec[i] /= fCurrentsVec.size()*9;
496 avg2 += vec[i];
497
498 if (vec[i]-avg>3.5*avg_dev)
499 {
500 fThresholds[i] = max(uint16_t(40.5*pow(vec[i], 0.642)+164), fThresholdReference);
501
502 const int32_t dat[2] = { i, fThresholds[i] };
503 Dim::SendCommand("FTM_CONTROL/SET_THRESHOLD", dat);
504
505 fBlock[i/4] = true;
506 }
507 }
508
509 avg2 /= 160;
510
511 const RateControl::DimThreshold data = { fThresholdMin, fCalibrationTimeStart.Mjd(), Time().Mjd() };
512 fDimThreshold.setQuality(2);
513 fDimThreshold.Update(data);
514
515 ostringstream out;
516 out << setprecision(3);
517 out << "Measured average current " << avg << "uA +- " << rms << "uA [N=" << fCurrentsMed.size() << "]... mininum threshold set to " << fThresholdMin;
518 Info(out);
519
520 return RateControl::State::kGlobalThresholdSet;
521 }
522
523 int Calibrate()
524 {
525 if (!fTriggerOn)
526 {
527 Info("Physics trigger not enabled... CALIBRATE command ignored.");
528 return RateControl::State::kGlobalThresholdSet;
529 }
530
531 const int32_t val[2] = { -1, fThresholdReference };
532 Dim::SendCommand("FTM_CONTROL/SET_THRESHOLD", val);
533
534 fThresholds.assign(160, fThresholdReference);
535
536 fThresholdMin = fThresholdReference;
537 fTriggerRate = -1;
538 fCounter = 0;
539 fBlock.assign(160, false);
540
541 fCalibrateByCurrent = false;
542 fCalibrationTimeStart = Time();
543
544 ostringstream out;
545 out << "Rate calibration started at a threshold of " << fThresholdReference << " with a target rate of " << fTargetRate << " Hz";
546 Info(out);
547
548 return RateControl::State::kSettingGlobalThreshold;
549 }
550
551 int CalibrateByCurrent()
552 {
553 if (!fTriggerOn)
554 {
555 Info("Physics trigger not enabled... CALIBRATE command ignored.");
556 return RateControl::State::kGlobalThresholdSet;
557 }
558
559 if (fDimDrive.state()<Drive::State::kMoving)
560 Warn("Drive not even moving...");
561
562 fCounter = 0;
563 fCalibrateByCurrent = true;
564 fCalibrationTimeStart = Time();
565 fBlock.assign(160, false);
566
567 ostringstream out;
568 out << "Rate calibration by current with min. threshold of " << fThresholdReference << ".";
569 Info(out);
570
571 return RateControl::State::kSettingGlobalThreshold;
572 }
573
574 int CalibrateRun(const EventImp &evt)
575 {
576 const string name = evt.GetText();
577
578 auto it = fRunTypes.find(name);
579 if (it==fRunTypes.end())
580 {
581 Info("CalibrateRun - Run-type '"+name+"' not found... trying 'default'.");
582
583 it = fRunTypes.find("default");
584 if (it==fRunTypes.end())
585 {
586 Error("CalibrateRun - Run-type 'default' not found.");
587 return GetCurrentState();
588 }
589 }
590
591 const config &conf = it->second;
592
593 switch (conf.fCalibrationType)
594 {
595 case 0:
596 Info("No calibration requested.");
597 return RateControl::State::kGlobalThresholdSet;
598
599 case 1:
600 fThresholdReference = conf.fMinThreshold;
601 fTargetRate = conf.fTargetRate;
602 return Calibrate();
603
604 case 2:
605 fThresholdReference = conf.fMinThreshold;
606 fAverageTime = conf.fAverageTime;
607 fRequiredEvents = conf.fRequiredEvents;
608 return CalibrateByCurrent();
609 }
610
611 Error("CalibrateRun - Calibration type "+to_string(conf.fCalibrationType)+" unknown.");
612 return GetCurrentState();
613 }
614
615 int StopRC()
616 {
617 return RateControl::State::kConnected;
618 }
619
620 int SetMinThreshold(const EventImp &evt)
621 {
622 if (!CheckEventSize(evt, 4))
623 return kSM_FatalError;
624
625 // FIXME: Check missing
626
627 fThresholdReference = evt.GetUShort();
628
629 return GetCurrentState();
630 }
631
632 int SetTargetRate(const EventImp &evt)
633 {
634 if (!CheckEventSize(evt, 4))
635 return kSM_FatalError;
636
637 fTargetRate = evt.GetFloat();
638
639 return GetCurrentState();
640 }
641
642 int Print() const
643 {
644 Out() << fDim << endl;
645 Out() << fDimFTM << endl;
646 Out() << fDimRS << endl;
647 Out() << fDimDrive << endl;
648
649 return GetCurrentState();
650 }
651
652 int SetVerbosity(const EventImp &evt)
653 {
654 if (!CheckEventSize(evt, 1))
655 return kSM_FatalError;
656
657 fVerbose = evt.GetBool();
658
659 return GetCurrentState();
660 }
661
662 int Execute()
663 {
664 if (!fDim.online())
665 return RateControl::State::kDimNetworkNA;
666
667 // All subsystems are not connected
668 if (fDimFTM.state()<FTM::State::kConnected || fDimDrive.state()<Drive::State::kConnected)
669 return RateControl::State::kDisconnected;
670
671 const bool inprog = fTriggerOn && fDimRS.state()<RateScan::State::kConfiguring;
672
673 switch (GetCurrentState())
674 {
675 case RateControl::State::kSettingGlobalThreshold:
676 return RateControl::State::kSettingGlobalThreshold;
677
678 case RateControl::State::kGlobalThresholdSet:
679 if (!inprog)
680 return RateControl::State::kGlobalThresholdSet;
681
682 case RateControl::State::kInProgress:
683 if (inprog)
684 return RateControl::State::kInProgress;
685 }
686
687 return RateControl::State::kConnected;
688 }
689
690public:
691 StateMachineRateControl(ostream &out=cout) : StateMachineDim(out, "RATE_CONTROL"),
692 fTriggerOn(false), fBlock(40),
693 fDimFTM("FTM_CONTROL"),
694 fDimRS("RATE_SCAN"),
695 fDimDrive("DRIVE_CONTROL"),
696 fDimThreshold("RATE_CONTROL/THRESHOLD", "S:1;D:1;D:1",
697 "Resulting threshold after calibration"
698 "|threshold[dac]:Resulting threshold from calibration"
699 "|begin[mjd]:Start time of calibration"
700 "|end[mjd]:End time of calibration")
701 {
702 // ba::io_service::work is a kind of keep_alive for the loop.
703 // It prevents the io_service to go to stopped state, which
704 // would prevent any consecutive calls to run()
705 // or poll() to do nothing. reset() could also revoke to the
706 // previous state but this might introduce some overhead of
707 // deletion and creation of threads and more.
708
709 fDim.Subscribe(*this);
710 fDimFTM.Subscribe(*this);
711 fDimRS.Subscribe(*this);
712 fDimDrive.Subscribe(*this);
713
714 Subscribe("FTM_CONTROL/TRIGGER_RATES")
715 (bind(&StateMachineRateControl::HandleTriggerRates, this, placeholders::_1));
716 Subscribe("FTM_CONTROL/STATIC_DATA")
717 (bind(&StateMachineRateControl::HandleStaticData, this, placeholders::_1));
718 Subscribe("FEEDBACK/CALIBRATED_CURRENTS")
719 (bind(&StateMachineRateControl::HandleCalibratedCurrents, this, placeholders::_1));
720
721 // State names
722 AddStateName(RateControl::State::kDimNetworkNA, "DimNetworkNotAvailable",
723 "The Dim DNS is not reachable.");
724
725 AddStateName(RateControl::State::kDisconnected, "Disconnected",
726 "The Dim DNS is reachable, but the required subsystems are not available.");
727
728 AddStateName(RateControl::State::kConnected, "Connected",
729 "All needed subsystems are connected to their hardware, no action is performed.");
730
731 AddStateName(RateControl::State::kSettingGlobalThreshold, "Calibrating",
732 "A global minimum thrshold is currently determined.");
733
734 AddStateName(RateControl::State::kGlobalThresholdSet, "GlobalThresholdSet",
735 "A global threshold has ben set, waiting for the trigger to be switched on.");
736
737 AddStateName(RateControl::State::kInProgress, "InProgress",
738 "Rate control in progress.");
739
740 AddEvent("CALIBRATE")
741 (bind(&StateMachineRateControl::Calibrate, this))
742 ("Start a search for a reasonable minimum global threshold");
743
744 AddEvent("CALIBRATE_BY_CURRENT")
745 (bind(&StateMachineRateControl::CalibrateByCurrent, this))
746 ("Set the global threshold from the median current");
747
748 AddEvent("CALIBRATE_RUN", "C")
749 (bind(&StateMachineRateControl::CalibrateRun, this, placeholders::_1))
750 ("Start a threshold calibration as defined in the setup for this run-type");
751
752 AddEvent("STOP", RateControl::State::kSettingGlobalThreshold, RateControl::State::kGlobalThresholdSet, RateControl::State::kInProgress)
753 (bind(&StateMachineRateControl::StopRC, this))
754 ("Stop a calibration or ratescan in progress");
755
756 AddEvent("SET_MIN_THRESHOLD", "I:1")
757 (bind(&StateMachineRateControl::SetMinThreshold, this, placeholders::_1))
758 ("Set a minimum threshold at which th rate control starts calibrating");
759
760 AddEvent("SET_TARGET_RATE", "F:1")
761 (bind(&StateMachineRateControl::SetTargetRate, this, placeholders::_1))
762 ("Set a target trigger rate for the calibration");
763
764 AddEvent("PRINT")
765 (bind(&StateMachineRateControl::Print, this))
766 ("Print current status");
767
768 AddEvent("SET_VERBOSE", "B")
769 (bind(&StateMachineRateControl::SetVerbosity, this, placeholders::_1))
770 ("set verbosity state"
771 "|verbosity[bool]:disable or enable verbosity for received data (yes/no), except dynamic data");
772
773 }
774
775 bool GetConfig(Configuration &conf, const string &name, const string &sub, uint16_t &rc)
776 {
777 if (conf.HasDef(name, sub))
778 {
779 rc = conf.GetDef<uint16_t>(name, sub);
780 return true;
781 }
782
783 Error("Neither "+name+"default nor "+name+sub+" found.");
784 return false;
785 }
786
787 int EvalOptions(Configuration &conf)
788 {
789 fVerbose = !conf.Get<bool>("quiet");
790
791 if (!fMap.Read(conf.Get<string>("pixel-map-file")))
792 {
793 Error("Reading mapping table from "+conf.Get<string>("pixel-map-file")+" failed.");
794 return 1;
795 }
796
797 fThresholdReference = 300;
798 fThresholdMin = 300;
799 fTargetRate = 75;
800
801 fAverageTime = 10;
802 fRequiredEvents = 8;
803
804 // ---------- Setup run types ---------
805 const vector<string> types = conf.Vec<string>("run-type");
806 if (types.size()==0)
807 Warn("No run-types defined.");
808 else
809 Message("Defining run-types");
810
811 for (auto it=types.begin(); it!=types.end(); it++)
812 {
813 Message(" -> "+ *it);
814
815 if (fRunTypes.count(*it)>0)
816 {
817 Error("Run-type "+*it+" defined twice.");
818 return 1;
819 }
820
821 config &c = fRunTypes[*it];
822 if (!GetConfig(conf, "calibration-type.", *it, c.fCalibrationType) ||
823 !GetConfig(conf, "target-rate.", *it, c.fTargetRate) ||
824 !GetConfig(conf, "min-threshold.", *it, c.fMinThreshold) ||
825 !GetConfig(conf, "average-time.", *it, c.fAverageTime) ||
826 !GetConfig(conf, "required-events.", *it, c.fRequiredEvents))
827 return 2;
828 }
829
830 return -1;
831 }
832};
833
834// ------------------------------------------------------------------------
835
836#include "Main.h"
837
838template<class T>
839int RunShell(Configuration &conf)
840{
841 return Main::execute<T, StateMachineRateControl>(conf);
842}
843
844void SetupConfiguration(Configuration &conf)
845{
846 po::options_description control("Rate control options");
847 control.add_options()
848 ("quiet,q", po_bool(), "Disable printing more informations during rate control.")
849 ("pixel-map-file", var<string>()->required(), "Pixel mapping file. Used here to get the default reference voltage.")
850 //("max-wait", var<uint16_t>(150), "The maximum number of seconds to wait to get the anticipated resolution for a point.")
851 // ("resolution", var<double>(0.05) , "The minimum resolution required for a single data point.")
852 ;
853
854 conf.AddOptions(control);
855
856 po::options_description runtype("Run type configuration");
857 runtype.add_options()
858 ("run-type", vars<string>(), "Name of run-types (replace the * in the following configuration by the case-sensitive names defined here)")
859 ("calibration-type.*", var<uint16_t>(), "Calibration type (0: none, 1: by rate, 2: by current)")
860 ("target-rate.*", var<uint16_t>(), "Target rate for calibration by rate")
861 ("min-threshold.*", var<uint16_t>(), "Minimum threshold which can be applied in a calibration")
862 ("average-time.*", var<uint16_t>(), "Time in seconds to average the currents for a calibration by current.")
863 ("required-events.*", var<uint16_t>(), "Number of required current events to start a calibration by current.");
864 ;
865
866 conf.AddOptions(runtype);
867}
868
869/*
870 Extract usage clause(s) [if any] for SYNOPSIS.
871 Translators: "Usage" and "or" here are patterns (regular expressions) which
872 are used to match the usage synopsis in program output. An example from cp
873 (GNU coreutils) which contains both strings:
874 Usage: cp [OPTION]... [-T] SOURCE DEST
875 or: cp [OPTION]... SOURCE... DIRECTORY
876 or: cp [OPTION]... -t DIRECTORY SOURCE...
877 */
878void PrintUsage()
879{
880 cout <<
881 "The ratecontrol program is a keep the rate reasonable low.\n"
882 "\n"
883 "Usage: ratecontrol [-c type] [OPTIONS]\n"
884 " or: ratecontrol [OPTIONS]\n";
885 cout << endl;
886}
887
888void PrintHelp()
889{
890 Main::PrintHelp<StateMachineRateControl>();
891
892 /* Additional help text which is printed after the configuration
893 options goes here */
894
895 /*
896 cout << "bla bla bla" << endl << endl;
897 cout << endl;
898 cout << "Environment:" << endl;
899 cout << "environment" << endl;
900 cout << endl;
901 cout << "Examples:" << endl;
902 cout << "test exam" << endl;
903 cout << endl;
904 cout << "Files:" << endl;
905 cout << "files" << endl;
906 cout << endl;
907 */
908}
909
910int main(int argc, const char* argv[])
911{
912 Configuration conf(argv[0]);
913 conf.SetPrintUsage(PrintUsage);
914 Main::SetupConfiguration(conf);
915 SetupConfiguration(conf);
916
917 if (!conf.DoParse(argc, argv, PrintHelp))
918 return 127;
919
920 if (!conf.Has("console"))
921 return RunShell<LocalStream>(conf);
922
923 if (conf.Get<int>("console")==0)
924 return RunShell<LocalShell>(conf);
925 else
926 return RunShell<LocalConsole>(conf);
927
928 return 0;
929}
Note: See TracBrowser for help on using the repository browser.