source: branches/FACT++_lidctrl_usb/src/ratecontrol.cc@ 19736

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