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

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