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

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