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

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