FACT++  1.0
smartfact.cc
Go to the documentation of this file.
1 #ifdef HAVE_NOVA
2 #include "externals/Prediction.h"
3 #endif
4 
5 #ifdef HAVE_SQL
6 #include "Database.h"
7 #endif
8 
9 #include <sys/stat.h> //for file stats
10 #include <sys/statvfs.h> //for file statvfs
11 
12 #include "Dim.h"
13 #include "Event.h"
14 #include "Shell.h"
15 #include "StateMachineDim.h"
16 #include "Connection.h"
17 #include "Configuration.h"
18 #include "Console.h"
19 #include "DimWriteStatistics.h"
20 #include "externals/PixelMap.h"
21 
22 #include "tools.h"
23 
24 #include "LocalControl.h"
25 
26 #include "HeadersFAD.h"
27 #include "HeadersBIAS.h"
28 #include "HeadersFTM.h"
29 #include "HeadersFSC.h"
30 #include "HeadersGPS.h"
31 #include "HeadersSQM.h"
32 #include "HeadersMCP.h"
33 #include "HeadersLid.h"
34 #include "HeadersDrive.h"
35 #include "HeadersPower.h"
36 #include "HeadersPFmini.h"
37 #include "HeadersAgilent.h"
38 #include "HeadersFeedback.h"
39 #include "HeadersRateScan.h"
40 #include "HeadersRateControl.h"
41 #include "HeadersTNGWeather.h"
42 #include "HeadersMagicLidar.h"
43 #include "HeadersMagicWeather.h"
44 #include "HeadersTemperature.h"
45 
46 #include <boost/filesystem.hpp>
47 
48 using namespace std;
49 
50 // ------------------------------------------------------------------------
51 
52 #include "DimDescriptionService.h"
53 #include "DimState.h"
54 
55 // ------------------------------------------------------------------------
56 /*
57 template<class T>
58  class buffer : public deque<T>
59  {
60  int32_t max_size;
61 
62  public:
63  buffer(int32_t max=-1) : max_size(max) { }
64  const T &operator=(const T &t) const { push_back(t); if (max_size>0 && deque<T>::size()>max_size) deque<T>::pop_front(); }
65  operator T() const { return deque<T>::size()>0 ? deque<T>::back() : T(); }
66  bool valid() const { return deque<T>::size()>0; }
67  };
68 */
69 
70 // ------------------------------------------------------------------------
71 
72 namespace HTML
73 {
74  const static string kWhite = "#ffffff";
75  const static string kYellow = "#fffff0";
76  const static string kRed = "#fff8f0";
77  const static string kGreen = "#f0fff0";
78  const static string kBlue = "#f0f0ff";
79 };
80 
81 // ========================================================================
82 // ========================================================================
83 // ========================================================================
84 
85 class Sun
86 {
87 public:
89 
90  // This is always the time of the next...
95 
100 
101  int state;
102  string description;
103  string color;
104 
105  bool isday;
106  bool visible;
107 
108  Nova::RstTime Rst(double jd, double hrz=LN_SOLAR_STANDART_HORIZON)
109  {
110  Nova::RstTime rs = Nova::GetSolarRst(jd-0.5, hrz);
111  if (jd>rs.rise || jd>rs.set)
112  {
113  const Nova::RstTime rs2 = Nova::GetSolarRst(jd+0.5, hrz);
114  if (jd>rs.rise)
115  rs.rise = rs2.rise;
116  if (jd>rs.set)
117  rs.set = rs2.set;
118  }
119  return rs;
120  }
121 
122 public:
123  Sun() : time(Time::none)
124  {
125  }
126 
127  // Could be done more efficient: Only recalcuate if
128  // the current time exceeds at least on of the stored times
129  Sun(const Time &t) : time(t)
130  {
131 #ifdef HAVE_LIBNOVA
132  // get Julian day from local time
133  const double JD = time.JD();
134 
135  // >0deg : day
136  // -6deg - 0deg : civil twilight
137  // -12deg - -6deg : nautical twilight
138  // -18deg - -12deg : astronomical twilight
139  // <-18deg : night
140 
141  const Nova::RstTime sun00 = Rst(JD);
142  const Nova::RstTime sun06 = Rst(JD, -6);
143  const Nova::RstTime sun12 = Rst(JD, -12);
144  const Nova::RstTime sun18 = Rst(JD, -18);
145 
146  fSunRise00 = sun00.rise;
147  fSunRise06 = sun06.rise;
148  fSunRise12 = sun12.rise;
149  fSunRise18 = sun18.rise;
150 
151  fSunSet00 = sun00.set;
152  fSunSet06 = sun06.set;
153  fSunSet12 = sun12.set;
154  fSunSet18 = sun18.set;
155 
156  array<double,8> arr =
157  {{
158  sun00.set,
159  sun06.set,
160  sun12.set,
161  sun18.set,
162  sun18.rise,
163  sun12.rise,
164  sun06.rise,
165  sun00.rise,
166  }};
167 
168 
169  state = std::min_element(arr.begin(), arr.end())-arr.begin();
170 
171  string name[] =
172  {
173  "day time",
174  "civil twilight",
175  "nautical twilight",
176  "astron. twilight",
177  "dark time",
178  "astron. twilight",
179  "nautical twilight",
180  "civil twilight"
181  };
182 
183  description = name[state];
184 
185  const string txt = fSunRise18<fSunSet18 ?
186  time.MinutesTo(fSunRise18)+"&uarr;" :
187  time.MinutesTo(fSunSet18)+"&darr;";
188 
189  description += " ["+txt+"]";
190 
191  isday = state==0;
192 
193  switch (state)
194  {
195  case 0: color = HTML::kRed; break;
196  case 1: case 2: color = HTML::kYellow; break;
197  case 3: case 4: case 5: color = HTML::kGreen; break;
198  case 6: case 7: color = HTML::kYellow; break;
199  }
200 
201  visible = state==0;
202 
203  /*
204  // Warning: return code of 1 means circumpolar and is not checked!
205  Nova::RstTime sun_day = Nova::GetSolarRst(JD-0.5);
206  Nova::RstTime sun_civil = Nova::GetSolarRst(JD-0.5, -6);
207  Nova::RstTime sun_astronomical = Nova::GetSolarRst(JD-0.5, -12);
208  Nova::RstTime sun_dark = Nova::GetSolarRst(JD-0.5, -18);
209 
210  fSetDayTime = Time(sun_day.set);
211  fSetCivil = Time(sun_civil.set);
212  fSetAstronomical = Time(sun_astronomical.set);
213  fSetDarkTime = Time(sun_dark.set);
214 
215  fRiseDayTime = Time(sun_day.rise);
216  fRiseCivil = Time(sun_civil.rise);
217  fRiseAstronomical = Time(sun_astronomical.rise);
218  fRiseDarkTime = Time(sun_dark.rise);
219 
220  const bool is_day = JD>sun_day.rise;
221  const bool is_night = JD>sun_dark.set;
222 
223  sun_day = Nova::GetSolarRst(JD+0.5);
224  sun_civil = Nova::GetSolarRst(JD+0.5, -6);
225  sun_astronomical = Nova::GetSolarRst(JD+0.5, -12);
226  sun_dark = Nova::GetSolarRst(JD+0.5, -18);
227 
228  if (is_day)
229  {
230  fRiseDayTime = Time(sun_day.rise);
231  fRiseCivil = Time(sun_civil.rise);
232  fRiseAstronomical = Time(sun_astronomical.rise);
233  fRiseDarkTime = Time(sun_dark.rise);
234  }
235 
236  if (is_night)
237  {
238  fSetDayTime = Time(sun_day.set);
239  fSetCivil = Time(sun_civil.set);
240  fSetAstronomical = Time(sun_astronomical.set);
241  fSetDarkTime = Time(sun_dark.set);
242  }
243 
244  // case 0: midnight to sun-rise | !is_day && !is_night | rise/set | -> isday=0
245  // case 1: sun-rise to sun-set | is_day && !is_night | set /rise | -> isday=1
246  // case 2: sun-set to midnight | is_day && is_night | rise/set | -> isday=0
247 
248  isday = is_day^is_night;
249 
250  Time fRiseDayTime; // 0: Start of day time (=end of civil twilight)
251  Time fRiseCivil; // -6: End of nautical twilight
252  Time fRiseAstronomical; // -12: End of astron. twilight
253  Time fRiseDarkTime; // -18: End of dark time
254 
255  Time fSetDayTime; // 0: End of day time (=start of civil twilight)
256  Time fSetCivil; // -6: Start of nautical twilight
257  Time fSetAstronomical; // -12: Start of astron. twilight
258  Time fSetDarkTime; // -18: Start of dark time
259 
260  state = isday ? 4 : 0; // 0 [-> Day time ]
261  if (time>fSetDayTime) state++; // 1 [-> Civil twilight]
262  if (time>fSetCivil) state++; // 2 [-> Naut. twilight]
263  if (time>fSetAstronomical) state++; // 3 [-> Astro. twilight]
264  if (time>fSetDarkTime) state++; // 4 [-> Dark time ]
265 
266  if (time>fRiseDarkTime) state++; // 5 [-> Astro. twilight]
267  if (time>fRiseAstronomical) state++; // 6 [-> Naut. twilight]
268  if (time>fRiseCivil) state++; // 7 [-> Civil twilight]
269  if (time>fRiseDayTime) state++; // 8 [-> Day time ]
270 
271  string name[] =
272  {
273  "dark time", // 0
274  "astron. twilight", // 1
275  "civil twilight", // 2
276  "sunrise", // 3
277  "day time", // 4
278  "sunset", // 5
279  "civil twilight", // 6
280  "astron. twilight", // 7
281  "dark time" // 8
282  };
283 
284  description = name[state];
285 
286  const string arr = isday ?
287  fSetDarkTime.MinutesTo(time)+"&darr;" :
288  fRiseDarkTime.MinutesTo(time)+"&uarr;";
289 
290  description += " ["+arr+"]";
291 
292  switch (state)
293  {
294  case 0: case 1: color = HTML::kGreen; break;
295  case 2: case 3: color = HTML::kYellow; break;
296  case 4: color = HTML::kRed; break;
297  case 5: case 6: color = HTML::kYellow; break;
298  case 7: case 8: color = HTML::kGreen; break;
299  }
300 
301  visible = state>=3 && state<=5;
302  */
303 #endif
304  }
305 };
306 
307 class Moon
308 {
309 public:
310  Time time;
311 
312  double ra;
313  double dec;
314 
315  double zd;
316  double az;
317 
318  double disk;
319 
320  bool visible;
321 
322  Time fRise;
323  Time fTransit;
324  Time fSet;
325 
326  string description;
327  string color;
328 
329  int state;
330 
331  Moon() : time(Time::none)
332  {
333  }
334 
335  // Could be done more efficient: Only recalcuate if
336  // the current time exceeds at least on of the stored times
337  Moon(const Time &t) : time(t)
338  {
339 #ifdef HAVE_LIBNOVA
340  const double JD = time.JD();
341 
342  Nova::RstTime moon = Nova::GetLunarRst(JD-0.5);
343 
344  fRise = Time(moon.rise);
345  fTransit = Time(moon.transit);
346  fSet = Time(moon.set);
347 
348  //visible =
349  // ((JD>moon.rise && JD<moon.set ) && moon.rise<moon.set) ||
350  // ((JD<moon.set || JD>moon.rise) && moon.rise>moon.set);
351 
352  const bool is_up = JD>moon.rise;
353  const bool is_sinking = JD>moon.transit;
354  const bool is_dn = JD>moon.set;
355 
356  moon = Nova::GetLunarRst(JD+0.5);
357  if (is_up)
358  fRise = Time(moon.rise);
359  if (is_sinking)
360  fTransit = Time(moon.transit);
361  if (is_dn)
362  fSet = Time(moon.set);
363 
364  const Nova::EquPosn pos = Nova::GetLunarEquCoords(JD);
365  const Nova::ZdAzPosn hrz = Nova::GetHrzFromEqu(pos, JD);
366 
367  az = hrz.az;
368  zd = hrz.zd;
369 
370  ra = pos.ra/15;
371  dec = pos.dec;
372 
373  disk = Nova::GetLunarDisk(JD)*100;
374  state = 0;
375  if (fRise <fTransit && fRise <fSet) state = 0; // not visible
376  if (fTransit<fSet && fTransit<fRise) state = 1; // before culm
377  if (fSet <fRise && fSet <fTransit) state = 2; // after culm
378 
379  visible = state!=0;
380 
381  // 0: not visible
382  // 1: visible before cul
383  // 2: visible after cul
384 
385  if (!visible || disk<25)
386  color = HTML::kGreen;
387  else
388  color = disk>75 ? HTML::kRed : HTML::kYellow;
389 
390  const string arr = fSet<fRise ?
391  fSet.MinutesTo(time) +"&darr;" :
392  fRise.MinutesTo(time)+"&uarr;";
393 
394  ostringstream out;
395  out << setprecision(2);
396  out << (visible?"visible ":"") << (disk<0.1?0:disk) << "% [" << arr << "]";
397 
398  description = out.str();
399 #endif
400  }
401 
402  double Angle(double r, double d) const
403  {
404  const double theta0 = M_PI/2-d*M_PI/180;
405  const double phi0 = r*M_PI/12;
406 
407  const double theta1 = M_PI/2-dec*M_PI/180;
408  const double phi1 = ra*M_PI/12;
409 
410  const double x0 = sin(theta0) * cos(phi0);
411  const double y0 = sin(theta0) * sin(phi0);
412  const double z0 = cos(theta0);
413 
414  const double x1 = sin(theta1) * cos(phi1);
415  const double y1 = sin(theta1) * sin(phi1);
416  const double z1 = cos(theta1);
417 
418  double arg = x0*x1 + y0*y1 + z0*z1;
419  if(arg > 1.0) arg = 1.0;
420  if(arg < -1.0) arg = -1.0;
421 
422  return acos(arg) * 180/M_PI;
423  }
424 
425  static string Color(double angle)
426  {
427  if (angle<10 || angle>150)
428  return HTML::kRed;
429  if (angle<20 || angle>140)
430  return HTML::kYellow;
431  return HTML::kGreen;
432  }
433 };
434 
435 // ========================================================================
436 // ========================================================================
437 // ========================================================================
438 
440 {
441 public:
442  static bool fIsServer;
443 
444 private:
445  enum states_t
446  {
447  kStateDimNetworkNA = 1,
449  };
450 
451  // ------------------------- History classes -----------------------
452 
454  {
456  string msg;
457 
458  EventElement(const Time &t, const string &s) : time(t), msg(s) { }
459  };
460 
461  class EventHist : public list<EventElement>
462  {
463  const boost::posix_time::time_duration deltat; //boost::posix_time::pos_infin
464  const uint64_t max;
465 
466  public:
467  EventHist(const boost::posix_time::time_duration &dt=boost::posix_time::hours(12), uint64_t mx=UINT64_MAX) : deltat(dt), max(mx) { }
468 
469  void add(const string &s, const Time &t=Time())
470  {
471  while (!empty() && (front().time+deltat<t || size()>max))
472  pop_front();
473 
474  emplace_back(t, s);
475  }
476 
477  void clean()
478  {
479  for (auto it=begin(); it!=end();)
480  if (!it->time)
481  {
482  const auto is = it++;
483  erase(is);
484  }
485  }
486 
487  string get() const
488  {
489  ostringstream out;
490 
491  string last = "";
492  for (auto it=begin(); it!=end(); it++)
493  {
494  const string tm = it->time.GetAsStr("%H:%M:%S ");
495  out << (tm!=last?tm:"--:--:-- ") << it->msg << "<br/>";
496  last = tm;
497  }
498 
499  return out.str();
500  }
501  string rget() const
502  {
503  ostringstream out;
504 
505  for (auto it=rbegin(); it!=rend(); it++)
506  out << it->time.GetAsStr("%H:%M:%S ") << it->msg << "<br/>";
507 
508  return out.str();
509  }
510  };
511 
512  // ------------------------- Internal variables -----------------------
513 
514  const Time fRunTime;
515 
517 
518  string fDatabase;
519 
522 
523  string fPath;
524 
525  // ----------------------------- Data storage -------------------------
526 
530 
531  int32_t fMcpConfigurationState; // For consistency
538 
539  enum weather_t { kWeatherBegin=0, kTemp = kWeatherBegin, kDew, kHum, kPress, kWind, kGusts, kDir, kWeatherEnd = kDir+1 };
540  deque<float> fMagicWeatherHist[kWeatherEnd];
541 
542  deque<float> fTngWeatherDustHist;
544 
545  vector<float> fBiasControlVoltageVec;
546 
551 
554 
556 
557  deque<float> fPfMiniHumidityHist;
559 
561 
566 
568 
572  vector<uint32_t> fFadControlDrsRuns;
573 
577 
580 
582 
583  deque<float> fRateControlThreshold;
584 
585  uint64_t fRateScanDataId;
586  uint8_t fRateScanBoard;
587  deque<float> fRateScanDataHist[41];
588 
589  set<string> fErrorList;
592 
593  uint64_t fFreeSpace;
594 
597 
598  // --------------------------- File header ----------------------------
599 
601  string fAudioName;
602 
603  string Header(const Time &d)
604  {
605  ostringstream msg;
606  msg << d.JavaDate() << '\t' << fAudioTime.JavaDate() << '\t' << fAudioName;
607  return msg.str();
608  }
609 
610  string Header(const EventImp &d)
611  {
612  return Header(d.GetTime());
613  }
614 
615  void SetAudio(const string &name)
616  {
617  fAudioName = name;
618  fAudioTime = Time();
619  }
620 
621  // ------------- Initialize variables before the Dim stuff ------------
622 
650 
651  // -------------------------------------------------------------------
652 
653  string GetDir(const double angle)
654  {
655  static const char *dir[] =
656  {
657  "N", "NNE", "NE", "ENE",
658  "E", "ESE", "SE", "SSE",
659  "S", "SSW", "SW", "WSW",
660  "W", "WNW", "NW", "NNW"
661  };
662 
663  const uint16_t idx = uint16_t(floor(angle/22.5+16.5))%16;
664  return dir[idx];
665  }
666 
667  // -------------------------------------------------------------------
668 
669  bool CheckDataSize(const EventImp &d, const char *name, size_t size, bool min=false)
670  {
671  if (d.GetSize()==0)
672  return false;
673 
674  if ((!min && d.GetSize()==size) || (min && d.GetSize()>size))
675  return true;
676 
677  ostringstream msg;
678  msg << name << " - Received service has " << d.GetSize() << " bytes, but expected ";
679  if (min)
680  msg << "more than ";
681  msg << size << ".";
682  Warn(msg);
683  return false;
684  }
685 
686  // -------------------------------------------------------------------
687 
688  template<class T>
689  void WriteBinaryVec(const Time &tm, const string &fname, const vector<T> &vec, double scale, double offset=0, const string &title="", const string &col="")
690  {
691  if (vec.empty())
692  return;
693 
694  ostringstream out;
695  out << tm.JavaDate() << '\n';
696  out << offset << '\n';
697  out << offset+scale << '\n';
698  out << setprecision(3);
699  if (!title.empty())
700  out << title << '\x7f';
701  else
702  {
703  const Statistics stat(vec[0]);
704  out << stat.min << '\n';
705  out << stat.med << '\n';
706  out << stat.max << '\x7f';
707  }
708  if (!col.empty())
709  out << col;
710  for (auto it=vec.cbegin(); it!=vec.cend(); it++)
711  {
712  // The valid range is from 1 to 127
713  // \0 is used to seperate different curves
714  vector<uint8_t> val(it->size());
715  for (uint64_t i=0; i<it->size(); i++)
716  {
717  float range = nearbyint(126*(double(it->at(i))-offset)/scale); // [-2V; 2V]
718  if (range>126)
719  range=126;
720  if (range<0)
721  range=0;
722  val[i] = (uint8_t)range;
723  }
724 
725  const char *ptr = reinterpret_cast<char*>(val.data());
726  out.write(ptr, val.size()*sizeof(uint8_t));
727  out << '\x7f';
728  }
729 
730  ofstream(fPath+"/"+fname+".bin") << out.str();
731  }
732  /*
733  template<class T>
734  void WriteBinaryVec(const EventImp &d, const string &fname, const vector<T> &vec, double scale, double offset=0, const string &title="")
735  {
736  WriteBinaryVec(d.GetTime(), fname, vec, scale, offset, title);
737  }
738 
739  template<class T>
740  void WriteBinary(const Time &tm, const string &fname, const T &t, double scale, double offset=0)
741  {
742  WriteBinaryVec(tm, fname, vector<T>(&t, &t+1), scale, offset);
743  }
744 
745  template<class T>
746  void WriteBinary(const EventImp &d, const string &fname, const T &t, double scale, double offset=0)
747  {
748  WriteBinaryVec(d.GetTime(), fname, vector<T>(&t, &t+1), scale, offset);
749  }*/
750 
751  template<class T>
752  void WriteHist(const EventImp &d, const string &fname, const T &t, double scale, double offset=0)
753  {
754  WriteBinaryVec(d.GetTime(), fname, vector<T>(&t, &t+1), scale, offset, "", "000");
755  }
756 
757  template<class T>
758  void WriteCam(const EventImp &d, const string &fname, const T &t, double scale, double offset=0)
759  {
760  WriteBinaryVec(d.GetTime(), fname, vector<T>(&t, &t+1), scale, offset, "", "");
761  }
762 
763 
764  // -------------------------------------------------------------------
765 
766  struct Statistics
767  {
768  float min;
769  float max;
770  float med;
771  float avg;
772  //float rms;
773 
774  template<class T>
775  Statistics(const T &t, size_t offset_min=0, size_t offset_max=0)
776  : min(0), max(0), med(0), avg(0)
777  {
778  if (t.empty())
779  return;
780 
781  T copy(t);
782  sort(copy.begin(), copy.end());
783 
784  if (offset_min>t.size())
785  offset_min = 0;
786  if (offset_max>t.size())
787  offset_max = 0;
788 
789  min = copy[offset_min];
790  max = copy[copy.size()-1-offset_max];
791  avg = accumulate (t.begin(), t.end(), 0.)/t.size();
792 
793  const size_t p = copy.size()/2;
794  med = copy.size()%2 ? copy[p] : (copy[p-1]+copy[p])/2.;
795  }
796  };
797 
799  {
800  if (d.GetSize()==0)
801  return;
802 
803  fControlMessageHist.add(d.GetText(), d.GetTime());
804 
805  ostringstream out;
806  out << setprecision(3);
807  out << Header(d) << '\n';
808  out << HTML::kWhite << '\t';
809  out << "<->" << fControlMessageHist.get() << "</->";
810  out << '\n';
811 
812  ofstream(fPath+"/scriptlog.data") << out.str();
813  }
814 
816  {
817  if (d.GetSize()==0)
818  return GetCurrentState();
819 
820  if (d.GetQoS()==MessageImp::kAlarm)
821  {
822  if (d.GetSize()<2)
823  for (auto it=fControlAlarmHist.begin(); it!=fControlAlarmHist.end(); it++)
824  it->time = Time(Time::none);
825  else
826  fControlAlarmHist.add(d.GetText(), d.GetTime());
827  }
828 
829  if (d.GetQoS()==MessageImp::kComment && d.GetSize()>1)
830  HandleControlMessageImp(d);
831 
832  return GetCurrentState();
833  }
834 
836  {
837  if (d.GetSize()==0)
839 
840  if (fDimControl.scriptdepth>0)
842 
843  if (d.GetQoS()>=2)
845 
846 #if BOOST_VERSION < 104600
847  const string file = boost::filesystem::path(fDimControl.file).filename();
848 #else
849  const string file = boost::filesystem::path(fDimControl.file).filename().string();
850 #endif
851 
852  // [0] DimControl::kIdle
853  // [1] DimControl::kLoading
854  // [2] DimControl::kCompiling
855  // [3] DimControl::kRunning
856  if (d.GetQoS()==1)
857  {
858  fControlMessageHist.clear();
859  HandleControlMessageImp(Event(d, "========================================", 41));
860  }
861 
862  HandleControlMessageImp(Event(d, ("----- "+fDimControl.shortmsg+" -----").data(), fDimControl.shortmsg.length()+13));
863  if (!file.empty() && d.GetQoS()<2)
864  HandleControlMessageImp(Event(d, file.data(), file.length()+1));
865 
866  // Note that this will also "ding" just after program startup
867  // if the dimctrl is still in state -3
868  if (d.GetQoS()==0)
869  {
870  HandleControlMessageImp(Event(d, "========================================", 41));
871  if (fDimControl.last.second!=DimState::kOffline)
872  SetAudio("ding");
873  }
874 
876  }
877 
878  void AddMcpConfigurationHist(const EventImp &d, const string &msg)
879  {
880  fMcpConfigurationHist.add(msg, d.GetTime());
881 
882  ostringstream out;
883  out << d.GetJavaDate() << '\n';
884  out << HTML::kWhite << '\t';
885  out << "<->" << fMcpConfigurationHist.rget() << "</->";
886  out << '\n';
887 
888  ofstream(fPath+"/observations.data") << out.str();
889  }
890 
892  {
893  const int32_t &last = fDimFscControl.last.second;
894  const int32_t &state = fDimFscControl.state();
895 
896  if (last==DimState::kOffline || state==DimState::kOffline)
898 
900  {
901  AddMcpConfigurationHist(d, "<B>FSC swiched on</B>");
902  //SetAudio("startup");
903  }
904 
906  {
907  AddMcpConfigurationHist(d, "<B>FSC swiched off</B>");
908  //SetAudio("shutdown");
909  }
910 
912  }
913 
915  {
916  if (!CheckDataSize(d, "Mcp:Configuration", 16, true))
917  {
918  fMcpConfigurationState = DimState::kOffline;
919  fMcpConfigurationMaxTime = 0;
920  fMcpConfigurationMaxEvents = 0;
921  fMcpConfigurationName = "";
922  fMcpConfigurationRunStart = Time(Time::none);
923  return GetCurrentState();
924  }
925 
926  // If a run ends...
927  if (fMcpConfigurationState==MCP::State::kTakingData && d.GetQoS()==MCP::State::kIdle)
928  {
929  // ...and no script is running just play a simple 'tick'
930  // ...and a script is running just play a simple 'tick'
931  if (/*fDimControl.state()<-2 &&*/ fDimControl.scriptdepth==0)
932  SetAudio("dong");
933  else
934  SetAudio("losticks");
935 
936  fLastRunFinishedWithZeroEvents = fFadControlNumEvents==0;
937 
938  ostringstream out;
939  out << "<#darkred>" << d.Ptr<char>(16);
940  if (!fDriveControlSourceName.empty())
941  out << " [" << fDriveControlSourceName << ']';
942  out << " (N=" << fFadControlNumEvents << ')';
943  out << "</#>";
944 
945  AddMcpConfigurationHist(d, out.str());
946  }
947 
949  {
950  fMcpConfigurationRunStart = Time();
951  SetAudio("losticks");
952 
953  ostringstream out;
954  out << "<#darkgreen>" << fMcpConfigurationName;
955  if (!fDriveControlSourceName.empty())
956  out << " [" << fDriveControlSourceName << ']';
957  if (fFadControlStartRun>0)
958  out << " (Run " << fFadControlStartRun << ')';
959  out << "</#>";
960 
961  AddMcpConfigurationHist(d, out.str());
962  }
963 
964  fMcpConfigurationState = d.GetQoS();
965  fMcpConfigurationMaxTime = d.Get<uint64_t>();
966  fMcpConfigurationMaxEvents = d.Get<uint64_t>(8);
967  fMcpConfigurationName = d.Ptr<char>(16);
968 
969  return GetCurrentState();
970  }
971 
972  void WriteWeather(const EventImp &d, const string &name, int i, float min, float max)
973  {
974  const Statistics stat(fMagicWeatherHist[i]);
975 
976  ostringstream out;
977  out << setprecision(3);
978  out << d.GetJavaDate() << '\n';
979 
980  out << HTML::kWhite << '\t' << fMagicWeatherHist[i].back() << '\n';
981  out << HTML::kWhite << '\t' << stat.min << '\n';
982  out << HTML::kWhite << '\t' << stat.avg << '\n';
983  out << HTML::kWhite << '\t' << stat.max << '\n';
984 
985  ofstream(fPath+"/"+name+".data") << out.str();
986 
987  WriteHist(d, "hist-magicweather-"+name, fMagicWeatherHist[i], max-min, min);
988  }
989 
991  {
992  if (!CheckDataSize(d, "MagicWeather:Data", 7*4+2))
993  return GetCurrentState();
994 
995  // Store a history of the last 300 entries
996  for (int i=kWeatherBegin; i<kWeatherEnd; i++)
997  {
998  fMagicWeatherHist[i].push_back(d.Ptr<float>(2)[i]);
999  if (fMagicWeatherHist[i].size()>300)
1000  fMagicWeatherHist[i].pop_front();
1001  }
1002 
1003  ostringstream out;
1004  out << d.GetJavaDate() << '\n';
1005  if (fSun.time.IsValid() && fMoon.time.IsValid())
1006  {
1007  out << fSun.color << '\t' << fSun.description << '\n';
1008  out << setprecision(2);
1009  out << (fSun.isday?HTML::kWhite:fMoon.color) << '\t' << fMoon.description << '\n';
1010  }
1011  else
1012  out << "\n\n";
1013  out << setprecision(3);
1014  for (int i=0; i<6; i++)
1015  out << HTML::kWhite << '\t' << fMagicWeatherHist[i].back() << '\n';
1016  out << HTML::kWhite << '\t' << GetDir(fMagicWeatherHist[kDir].back()) << '\n';
1017  out << HTML::kWhite << '\t';
1018  if (!fTngWeatherDustHist.empty())
1019  out << fTngWeatherDustHist.back() << '\t' << fTngWeatherDustTime.GetAsStr("%H:%M") << '\n';
1020  else
1021  out << "\t\n";
1022 
1023  ofstream(fPath+"/weather.data") << out.str();
1024 
1025  WriteWeather(d, "temp", kTemp, -5, 35);
1026  WriteWeather(d, "dew", kDew, -5, 35);
1027  WriteWeather(d, "hum", kHum, 0, 100);
1028  WriteWeather(d, "wind", kWind, 0, 100);
1029  WriteWeather(d, "gusts", kGusts, 0, 100);
1030  WriteWeather(d, "press", kPress, 700, 1000);
1031 
1032  return GetCurrentState();
1033  }
1034 
1036  {
1037  if (!CheckDataSize(d, "TngWeather:Dust", 4))
1038  return GetCurrentState();
1039 
1040  fTngWeatherDustTime = d.GetTime();
1041 
1042  fTngWeatherDustHist.push_back(d.GetFloat());
1043  if (fTngWeatherDustHist.size()>300)
1044  fTngWeatherDustHist.pop_front();
1045 
1046  const Statistics stat(fTngWeatherDustHist);
1047 
1048  const double scale = stat.max>0 ? pow(10, ceil(log10(stat.max))) : 0;
1049 
1050  WriteHist(d, "hist-tng-dust", fTngWeatherDustHist, scale);
1051 
1052  ostringstream out;
1053  out << d.GetJavaDate() << '\n';
1054 
1055  ofstream(fPath+"/tngdust.data") << out.str();
1056 
1057  return GetCurrentState();
1058  }
1059 
1061  {
1062  const int32_t &last = fDimFscControl.last.second;
1063  const int32_t &state = fDimFscControl.state();
1064 
1065  if (last==DimState::kOffline || state==DimState::kOffline)
1067 
1068  if (last<Drive::State::kInitialized && state>=Drive::State::kInitialized)
1069  AddMcpConfigurationHist(d, "Drive ready");
1070 
1072  AddMcpConfigurationHist(d, "Drive not ready");
1073 
1075  }
1076 
1078  {
1079  if (!CheckDataSize(d, "DriveControl:Pointing", 16))
1080  return GetCurrentState();
1081 
1082  fDriveControlPointingZd = d.Get<double>();
1083 
1084  const double az = d.Get<double>(8);
1085 
1086  fDriveControlPointingAz = GetDir(az);
1087 
1088  ostringstream out;
1089  out << d.GetJavaDate() << '\n';
1090 
1091  out << setprecision(0) << fixed;
1092  out << HTML::kWhite << '\t' << az << '\t' << fDriveControlPointingAz << '\n';
1093  out << HTML::kWhite << '\t' << fDriveControlPointingZd << '\n';
1094 
1095  ofstream(fPath+"/pointing.data") << out.str();
1096 
1097  return GetCurrentState();
1098  }
1099 
1101  {
1102  if (!CheckDataSize(d, "DriveControl:Tracking", 96))
1103  return GetCurrentState();
1104 
1105 
1106 
1107  const double Ra = d.Get<double>(0*8);
1108  const double Dec = d.Get<double>(1*8);
1109  const double Zd = d.Get<double>(6*8);
1110  const double Az = d.Get<double>(7*8);
1111 
1112  const double dev = d.Get<double>(11*8);
1113 
1114  fDriveControlTrackingDevHist.push_back(dev);
1115  if (fDriveControlTrackingDevHist.size()>300)
1116  fDriveControlTrackingDevHist.pop_front();
1117 
1118  WriteHist(d, "hist-control-deviation", fDriveControlTrackingDevHist, 120);
1119 
1120  ostringstream out;
1121  out << d.GetJavaDate() << '\n';
1122 
1123  out << HTML::kWhite << '\t' << fDriveControlSourceName << '\n';
1124  out << setprecision(5);
1125  out << HTML::kWhite << '\t' << Ra << '\n';
1126  out << HTML::kWhite << '\t' << Dec << '\n';
1127  out << setprecision(3);
1128  out << HTML::kWhite << '\t' << Zd << '\n';
1129  out << HTML::kWhite << '\t' << Az << '\n';
1130  out << HTML::kWhite << '\t' << dev << '\n';
1131 
1132  fDriveControlMoonDist = -1;
1133 
1134  if (fMoon.visible)
1135  {
1136  const double angle = fMoon.Angle(Ra, Dec);
1137  out << Moon::Color(angle) << '\t' << setprecision(3) << angle << '\n';
1138 
1139  fDriveControlMoonDist = angle;
1140  }
1141  else
1142  out << HTML::kWhite << "\t&mdash; \n";
1143 
1144  ofstream(fPath+"/tracking.data") << out.str();
1145 
1146  return GetCurrentState();
1147  }
1148 
1150  {
1151  if (!CheckDataSize(d, "DriveControl:Source", 5*8+31))
1152  return GetCurrentState();
1153 
1154  const double *ptr = d.Ptr<double>();
1155 
1156  const double ra = ptr[0]; // Ra[h]
1157  const double dec = ptr[1]; // Dec[deg]
1158  const double woff = ptr[2]; // Wobble offset [deg]
1159  const double wang = ptr[3]; // Wobble angle [deg]
1160  const double period = ptr[4]; // Wobble angle [deg]
1161 
1162  fDriveControlSourceName = d.Ptr<char>(5*8);
1163 
1164  ostringstream out;
1165  out << d.GetJavaDate() << '\n';
1166 
1167  out << HTML::kWhite << '\t' << fDriveControlSourceName << '\n';
1168  out << setprecision(5);
1169  out << HTML::kWhite << '\t' << ra << '\n';
1170  out << HTML::kWhite << '\t' << dec << '\n';
1171  out << setprecision(3);
1172  out << HTML::kWhite << '\t' << woff << '\n';
1173  out << HTML::kWhite << '\t' << wang << '\n';
1174  out << HTML::kWhite << '\t' << period << '\n';
1175 
1176  ofstream(fPath+"/source.data") << out.str();
1177 
1178  return GetCurrentState();
1179  }
1180 
1182  {
1183  if (!CheckDataSize(d, "Feedback:CalibratedCurrents", (416+1+1+1+1+1+416+1+1)*sizeof(float)+sizeof(uint32_t)))
1184  return GetCurrentState();
1185 
1186  const float *ptr = d.Ptr<float>();
1187 
1188  double power_tot = 0;
1189  double power_apd = 0;
1190 
1191  if (fBiasControlVoltageVec.size()>0)
1192  {
1193  // Calibrate the data (subtract offset)
1194  for (int i=0; i<320; i++)
1195  {
1196  // Exclude crazy pixels
1197  if (i==66 || i==191 || i==193)
1198  continue;
1199 
1200  // Group index (0 or 1) of the of the pixel (4 or 5 pixel patch)
1201  const int N = fPixelMap.hv(i).count();
1202 
1203  // Serial resistor of the individual G-APDs
1204  double R5 = 3900/N;
1205 
1206  // This is also valid for the patches with wrong resistors,
1207  // because Iapd is a factor f larger but R a factor f smaller
1208  double Iapd = ptr[i] * 1e-6; // [A]
1209  double Iout = Iapd*N; // [A]
1210 
1211  double UdrpCam = 1000 *Iout; // Voltage seen by everything in Camera
1212  double UdrpApd = (R5+2000)*Iout; // Voltage seen by G-APD
1213 
1214  const double pwrCam = Iout * (fBiasControlVoltageVec[i]-UdrpCam);
1215  const double pwrApd = Iout * (fBiasControlVoltageVec[i]-UdrpApd);
1216 
1217  // Total power participated in the camera at the G-APD
1218  // and the serial resistors (total voltage minus voltage
1219  // drop at resistors in bias crate)
1220  power_tot += pwrCam;
1221 
1222  // Power consumption per G-APD
1223  power_apd += pwrApd;
1224  }
1225  }
1226 
1227  // Divide by number of summed channels, convert to mW
1228  power_apd /= (320-3)*1e-3; // [mW]
1229 
1230  if (power_tot<1e-3)
1231  power_tot = 0;
1232  if (power_apd<1e-3)
1233  power_apd = 0;
1234 
1235  fBiasControlPowerTot = power_tot;
1236 
1237  // --------------------------------------------------------
1238 
1239  // Get the maximum of each patch
1240  vector<float> val(320, 0);
1241  for (int i=0; i<320; i++)
1242  {
1243  const int idx = (fPixelMap.hv(i).hw()/9)*2+fPixelMap.hv(i).group();
1244  val[idx] = ptr[i];
1245  }
1246 
1247  // Write the 160 patch values to a file
1248  WriteCam(d, "cam-biascontrol-current", val, 100);
1249 
1250  // --------------------------------------------------------
1251 
1252  // After being displayed, exclude the patches with
1253  // the crazy pixels from the statsitics
1254 
1255  vector<float> cpy(ptr, ptr+320);
1256  cpy[66] = 0;
1257  cpy[191] = 0;
1258  cpy[193] = 0;
1259  const Statistics stat(cpy);
1260 
1261  // Exclude the three crazy channels
1262  fBiasControlCurrentMed = stat.med;
1263  fBiasControlCurrentMax = stat.max;
1264 
1265  // Store a history of the last 60 entries
1266  fBiasControlCurrentHist.push_back(fBiasControlCurrentMed);
1267  if (fBiasControlCurrentHist.size()>360)
1268  fBiasControlCurrentHist.pop_front();
1269 
1270  // write the history to a file
1271  WriteHist(d, "hist-biascontrol-current", fBiasControlCurrentHist, 125);
1272 
1273  // --------------------------------------------------------
1274 
1275  string col1 = HTML::kGreen;
1276  string col2 = HTML::kGreen;
1277  string col3 = HTML::kGreen;
1278  string col4 = HTML::kGreen;
1279 
1280  if (stat.min>90)
1281  col1 = HTML::kYellow;
1282  if (stat.min>110)
1283  col1 = HTML::kRed;
1284 
1285  if (stat.med>90)
1286  col2 = HTML::kYellow;
1287  if (stat.med>110)
1288  col2 = HTML::kRed;
1289 
1290  if (stat.avg>90)
1291  col3 = HTML::kYellow;
1292  if (stat.avg>110)
1293  col3 = HTML::kRed;
1294 
1295  if (stat.max>90)
1296  col4 = HTML::kYellow;
1297  if (stat.max>110)
1298  col4 = HTML::kRed;
1299 
1300  ostringstream out;
1301  out << setprecision(3);
1302  out << d.GetJavaDate() << '\n';
1303  out << HTML::kGreen << '\t' << "yes" << '\n';
1304  out << col1 << '\t' << stat.min << '\n';
1305  out << col2 << '\t' << stat.med << '\n';
1306  out << col3 << '\t' << stat.avg << '\n';
1307  out << col4 << '\t' << stat.max << '\n';
1308  out << HTML::kWhite << '\t' << power_tot << "W [" << power_apd << "mW]\n";
1309  ofstream(fPath+"/current.data") << out.str();
1310 
1311  // --------------------------------------------------------
1312 
1313  const float Unom = ptr[2*416+6];
1314  const float Utmp = ptr[2*416+7];
1315 
1316  vector<float> Uov(ptr+416+6, ptr+416+6+320);
1317 
1318  WriteCam(d, "cam-feedback-overvoltage", Uov, 0.2, -0.1);
1319 
1320  const Statistics stat2(Uov);
1321 
1322  out.str("");
1323  out << d.GetJavaDate() << '\n';
1324  out << setprecision(3);
1325  out << HTML::kWhite << '\t' << Utmp << '\n';
1326  out << HTML::kWhite << '\t' << Unom << '\n';
1327  out << HTML::kWhite << '\t' << stat2.min << '\n';
1328  out << HTML::kWhite << '\t' << stat2.med << '\n';
1329  out << HTML::kWhite << '\t' << stat2.avg << '\n';
1330  out << HTML::kWhite << '\t' << stat2.max << '\n';
1331  ofstream(fPath+"/feedback.data") << out.str();
1332 
1333  return GetCurrentState();
1334  }
1335 
1337  {
1338  if (fDimFeedback.state()>=Feedback::State::kCalibrated)
1339  return GetCurrentState();
1340 
1341  if (!CheckDataSize(d, "BiasControl:Current", 832))
1342  return GetCurrentState();
1343 
1344  // Convert dac counts to uA
1345  vector<float> v(320);
1346  for (int i=0; i<320; i++)
1347  v[i] = d.Ptr<uint16_t>()[i] * 5000./4096;
1348 
1349  fBiasControlPowerTot = 0;
1350 
1351  // Get the maximum of each patch
1352  vector<float> val(320, 0);
1353  for (int i=0; i<320; i++)
1354  {
1355  const PixelMapEntry &hv = fPixelMap.hv(i);
1356  if (!hv)
1357  continue;
1358 
1359  const int idx = (hv.hw()/9)*2+hv.group();
1360  val[idx] = v[i];
1361  }
1362 
1363  // Write the 160 patch values to a file
1364  WriteCam(d, "cam-biascontrol-current", val, 1000);
1365 
1366  const Statistics stat(v, 0, 3);
1367 
1368  // Exclude the three crazy channels
1369  fBiasControlCurrentMed = stat.med;
1370  fBiasControlCurrentMax = stat.max;
1371 
1372  // Store a history of the last 60 entries
1373  fBiasControlCurrentHist.push_back(fBiasControlCurrentMed);
1374  if (fBiasControlCurrentHist.size()>360)
1375  fBiasControlCurrentHist.pop_front();
1376 
1377  // write the history to a file
1378  WriteHist(d, "hist-biascontrol-current", fBiasControlCurrentHist, 1000);
1379 
1380  ostringstream out;
1381  out << setprecision(3);
1382  out << d.GetJavaDate() << '\n';
1383  out << HTML::kWhite<< '\t' << "no" << '\n';
1384  out << HTML::kWhite << '\t' << stat.min << '\n';
1385  out << HTML::kWhite << '\t' << stat.med << '\n';
1386  out << HTML::kWhite << '\t' << stat.avg << '\n';
1387  out << HTML::kWhite << '\t' << stat.max << '\n';
1388  out << HTML::kWhite << '\t' << "---\n";
1389  ofstream(fPath+"/current.data") << out.str();
1390 
1391  return GetCurrentState();
1392  }
1393 
1395  {
1396  if (!CheckDataSize(d, "BiasControl:Voltage", 1664))
1397  {
1398  fBiasControlVoltageVec.clear();
1399  return GetCurrentState();
1400  }
1401 
1402  fBiasControlVoltageVec.assign(d.Ptr<float>(), d.Ptr<float>()+320);
1403 
1404  const Statistics stat(fBiasControlVoltageVec);
1405 
1406  fBiasControlVoltageMed = stat.med;
1407 
1408  vector<float> val(320, 0);
1409  for (int i=0; i<320; i++)
1410  {
1411  const int idx = (fPixelMap.hv(i).hw()/9)*2+fPixelMap.hv(i).group();
1412  val[idx] = fBiasControlVoltageVec[i];
1413  }
1414 
1415  if (fDimBiasControl.state()==BIAS::State::kVoltageOn || fDimBiasControl.state()==BIAS::State::kRamping)
1416  WriteCam(d, "cam-biascontrol-voltage", val, 10, 65);
1417  else
1418  WriteCam(d, "cam-biascontrol-voltage", val, 75);
1419 
1420  ostringstream out;
1421  out << setprecision(3);
1422  out << d.GetJavaDate() << '\n';
1423  out << HTML::kWhite << '\t' << stat.min << '\n';
1424  out << HTML::kWhite << '\t' << stat.med << '\n';
1425  out << HTML::kWhite << '\t' << stat.avg << '\n';
1426  out << HTML::kWhite << '\t' << stat.max << '\n';
1427  ofstream(fPath+"/voltage.data") << out.str();
1428 
1429  return GetCurrentState();
1430  }
1431 
1433  {
1434  if (!CheckDataSize(d, "FadControl:Events", 4*4))
1435  {
1436  fFadControlNumEvents = -1;
1437  return GetCurrentState();
1438  }
1439 
1440  fFadControlNumEvents = d.Get<uint32_t>();
1441 
1442  return GetCurrentState();
1443  }
1444 
1446  {
1447  if (!CheckDataSize(d, "FadControl:StartRun", 16))
1448  {
1449  fFadControlStartRun = -1;
1450  return GetCurrentState();
1451  }
1452 
1453  fFadControlStartRun = d.Get<int64_t>();
1454 
1455  return GetCurrentState();
1456  }
1457 
1459  {
1460  if (!CheckDataSize(d, "FadControl:DrsRuns", 5*4))
1461  {
1462  fFadControlDrsStep = -1;
1463  return GetCurrentState();
1464  }
1465 
1466  const uint32_t *ptr = d.Ptr<uint32_t>();
1467  fFadControlDrsStep = ptr[0];
1468  fFadControlDrsRuns[0] = ptr[1];
1469  fFadControlDrsRuns[1] = ptr[2];
1470  fFadControlDrsRuns[2] = ptr[3];
1471 
1472  return GetCurrentState();
1473  }
1474 
1476  {
1477  if (!CheckDataSize(d, "FadControl:Connections", 41))
1478  {
1479  //fStatusEventBuilderLabel->setText("Offline");
1480  return GetCurrentState();
1481  }
1482 
1483  string rc(40, '-'); // orange/red [45]
1484 
1485  const uint8_t *ptr = d.Ptr<uint8_t>();
1486 
1487  int c[4] = { '.', '.', '.', '.' };
1488 
1489  for (int i=0; i<40; i++)
1490  {
1491  const uint8_t stat1 = ptr[i]&3;
1492  const uint8_t stat2 = ptr[i]>>3;
1493 
1494  if (stat1==0 && stat2==0)
1495  rc[i] = '.'; // gray [46]
1496  else
1497  if (stat1>=2 && stat2==8)
1498  rc[i] = stat1==2?'+':'*'; // green [43] : check [42]
1499 
1500  if (rc[i]<c[i/10])
1501  c[i/10] = rc[i];
1502  }
1503 
1504  string col[4];
1505  for (int i=0; i<4; i++)
1506  switch (c[i])
1507  {
1508  case '.': col[i]=HTML::kWhite; break;
1509  case '-': col[i]=HTML::kRed; break;
1510  case '+': col[i]=HTML::kYellow; break;
1511  case '*': col[i]=HTML::kGreen; break;
1512  }
1513 
1514  ostringstream out;
1515  out << setprecision(3);
1516  out << d.GetJavaDate() << '\n';
1517  out << col[0] << '\t' << rc.substr( 0, 10) << '\n';
1518  out << col[1] << '\t' << rc.substr(10, 10) << '\n';
1519  out << col[2] << '\t' << rc.substr(20, 10) << '\n';
1520  out << col[3] << '\t' << rc.substr(30, 10) << '\n';
1521  ofstream(fPath+"/fad.data") << out.str();
1522 
1523  return GetCurrentState();
1524  }
1525 
1526  /*
1527  int HandleFtmControlStateChange()
1528  {
1529  const int32_t &last = fDimFtmControl.last.second;
1530  const int32_t &state = fDimFtmControl.state();
1531 
1532  // If a new run has been started ensure that the counter
1533  // is reset. The reset in HandleFtmTriggerRates might
1534  // arrive only after the run was started.
1535  if (last!=FTM::State::kTriggerOn && state==MCP::State::kTriggerOn)
1536  fFtmControlTriggerRateTooLow = -1;
1537 
1538  return StateMachineImp::kSM_KeepState;
1539  }*/
1540 
1541 
1543  {
1544  if (!CheckDataSize(d, "FtmControl:TriggerRates", 24+160+640+8))
1545  {
1546  fFtmControlTriggerRateTooLow = 0;
1547  return GetCurrentState();
1548  }
1549 
1550  const FTM::DimTriggerRates &dim = d.Ref<FTM::DimTriggerRates>();
1551 
1552  // If the trigger rate is too low...
1553  // ... and the run was not just started (can lead to very small elapsed times)
1554  // ... and the trigger is switched on
1555  // ... and there was no state change (then the trigger was started or stopped)
1556  fFtmControlTriggerRateTooLow =
1557  dim.fTriggerRate<1 && dim.fElapsedTime>0.45 &&
1558  (fFtmControlState&FTM::kFtmStates)==FTM::kFtmRunning &&
1559  (fFtmControlState&FTM::kFtmStates)==(d.GetQoS()&FTM::kFtmStates);
1560 
1561  fFtmControlState = d.GetQoS();
1562 
1563  const float *brates = dim.fBoardRate; // Board rate
1564  const float *prates = dim.fPatchRate; // Patch rate
1565 
1566  // Store a history of the last 60 entries
1567  fFtmControlTriggerRateHist.push_back(dim.fTriggerRate);
1568  if (fFtmControlTriggerRateHist.size()>300)
1569  fFtmControlTriggerRateHist.pop_front();
1570 
1571  // FIXME: Add statistics for all kind of rates
1572 
1573  WriteHist(d, "hist-ftmcontrol-triggerrate",
1574  fFtmControlTriggerRateHist, 100);
1575  WriteCam(d, "cam-ftmcontrol-boardrates",
1576  vector<float>(brates, brates+40), 10);
1577  WriteCam(d, "cam-ftmcontrol-patchrates",
1578  vector<float>(prates, prates+160), 10);
1579 
1580  ostringstream out;
1581  out << setprecision(3);
1582  out << d.GetJavaDate() << '\n';
1583  out << HTML::kWhite << '\t' << dim.fTriggerRate << '\n';
1584 
1585  ofstream(fPath+"/trigger.data") << out.str();
1586 
1587  const Statistics bstat(vector<float>(brates, brates+ 40));
1588  const Statistics pstat(vector<float>(prates, prates+160));
1589 
1590  out.str("");
1591  out << d.GetJavaDate() << '\n';
1592  out << HTML::kWhite << '\t' << bstat.min << '\n';
1593  out << HTML::kWhite << '\t' << bstat.med << '\n';
1594  out << HTML::kWhite << '\t' << bstat.avg << '\n';
1595  out << HTML::kWhite << '\t' << bstat.max << '\n';
1596  ofstream(fPath+"/boardrates.data") << out.str();
1597 
1598  out.str("");
1599  out << d.GetJavaDate() << '\n';
1600  out << HTML::kWhite << '\t' << pstat.min << '\n';
1601  out << HTML::kWhite << '\t' << pstat.med << '\n';
1602  out << HTML::kWhite << '\t' << pstat.avg << '\n';
1603  out << HTML::kWhite << '\t' << pstat.max << '\n';
1604  ofstream(fPath+"/patchrates.data") << out.str();
1605 
1606  return GetCurrentState();
1607  }
1608 
1610  {
1611  if (!CheckDataSize(d, "FtmControl:StaticData", sizeof(FTM::DimStaticData)))
1612  return GetCurrentState();
1613 
1614  // If the FTM is in state Configuring, the clock conditioner
1615  // is always reported to be unlocked
1616  fFtmControlState = d.GetQoS();
1617 
1618  const FTM::DimStaticData &dat = d.Ref<FTM::DimStaticData>();
1619 
1620  vector<uint16_t> vecp(dat.fThreshold, dat.fThreshold+160);
1621  vector<uint16_t> vecb(dat.fMultiplicity, dat.fMultiplicity+40);
1622 
1623  WriteCam(d, "cam-ftmcontrol-thresholds-patch", vecp, 1000);
1624  WriteCam(d, "cam-ftmcontrol-thresholds-board", vecb, 100);
1625 
1626  const Statistics statp(vecp);
1627  const Statistics statb(vecb);
1628 
1629  fFtmPatchThresholdMed = statp.med;
1630  fFtmBoardThresholdMed = statb.med;
1631 
1632  ostringstream out;
1633  out << d.GetJavaDate() << '\n';
1634  out << HTML::kWhite << '\t' << statb.min << '\n';
1635  out << HTML::kWhite << '\t' << statb.med << '\n';
1636  out << HTML::kWhite << '\t' << statb.max << '\n';
1637  ofstream(fPath+"/thresholds-board.data") << out.str();
1638 
1639  out.str("");
1640  out << d.GetJavaDate() << '\n';
1641  out << HTML::kWhite << '\t' << statp.min << '\n';
1642  out << HTML::kWhite << '\t' << statp.med << '\n';
1643  out << HTML::kWhite << '\t' << statp.max << '\n';
1644  ofstream(fPath+"/thresholds-patch.data") << out.str();
1645 
1646  out.str("");
1647  out << d.GetJavaDate() << '\n';
1648  out << HTML::kWhite << '\t' << statb.med << '\n';
1649  out << HTML::kWhite << '\t' << statp.med << '\n';
1650  ofstream(fPath+"/thresholds.data") << out.str();
1651 
1652  out.str("");
1653  out << d.GetJavaDate() << '\n';
1654  out << HTML::kWhite << '\t' << dat.fTriggerInterval << '\n';
1655  out << HTML::kWhite << '\t';
1656  if (dat.HasPedestal())
1657  out << dat.fTriggerSeqPed;
1658  else
1659  out << "&ndash;";
1660  out << ':';
1661  if (dat.HasLPext())
1662  out << dat.fTriggerSeqLPext;
1663  else
1664  out << "&ndash;";
1665  out << ':';
1666  if (dat.HasLPint())
1667  out << dat.fTriggerSeqLPint;
1668  else
1669  out << "&ndash;";
1670  out << '\n';
1671 
1672  out << HTML::kWhite << '\t' << (dat.HasTrigger()?"on":"off") << " / " << (dat.HasExt1()?"on":"off") << " / " << (dat.HasExt2()?"on":"off") << '\n';
1673  out << HTML::kWhite << '\t' << (dat.HasVeto()?"on":"off") << " / " << (dat.HasClockConditioner()?"time cal":"marker") << '\n';
1674  out << HTML::kWhite << '\t' << dat.fMultiplicityPhysics << " / " << dat.fMultiplicityCalib << '\n';
1675  out << HTML::kWhite << '\t' << dat.fWindowPhysics << '\t' << dat.fWindowCalib << '\n';
1676  out << HTML::kWhite << '\t' << dat.fDelayTrigger << '\t' << dat.fDelayTimeMarker << '\n';
1677  out << HTML::kWhite << '\t' << dat.fDeadTime << '\n';
1678 
1679  int64_t vp = dat.fPrescaling[0];
1680  for (int i=1; i<40; i++)
1681  if (vp!=dat.fPrescaling[i])
1682  vp = -1;
1683 
1684  if (vp<0)
1685  out << HTML::kYellow << "\tdifferent\n";
1686  else
1687  out << HTML::kWhite << '\t' << 0.5*vp << "\n";
1688 
1689  ofstream(fPath+"/ftm.data") << out.str();
1690 
1691  // Active FTUs: IsActive(i)
1692  // Enabled Pix: IsEnabled(i)
1693 
1694  return GetCurrentState();
1695  }
1696 
1698  {
1699  if (!CheckDataSize(d, "FtmControl:FtuList", sizeof(FTM::DimFtuList)))
1700  return GetCurrentState();
1701 
1702  const FTM::DimFtuList &sdata = d.Ref<FTM::DimFtuList>();
1703 
1704  ostringstream out;
1705  out << d.GetJavaDate() << '\n';
1706 
1707  int cnt = 0;
1708  for (int i=0; i<4; i++)
1709  {
1710  out << HTML::kWhite << '\t';
1711  for (int j=0; j<10; j++)
1712  if (sdata.IsActive(i*10+j))
1713  {
1714  if (sdata.fPing[i*10+j]==1)
1715  {
1716  out << '*';
1717  cnt++;
1718  }
1719  else
1720  out << sdata.fPing[i*10+j];
1721  }
1722  else
1723  out << '-';
1724  out << '\n';
1725  }
1726 
1727  fFtmControlFtuOk = cnt==40;
1728 
1729  ofstream(fPath+"/ftu.data") << out.str();
1730 
1731  return GetCurrentState();
1732  }
1733 
1735  {
1736  if (!CheckDataSize(d, "FadControl:EventData", 23040+8))
1737  return GetCurrentState();
1738 
1739  const float *dat = d.Ptr<float>(1440*sizeof(float)*2)+2;
1740 
1741  /*
1742  vector<float> max(320, 0);
1743  for (int i=0; i<1440; i++)
1744  {
1745  if (i%9==8)
1746  continue;
1747 
1748  const int idx = (fPixelMap.hw(i).hw()/9)*2+fPixelMap.hw(i).group();
1749  const double v = dat[i]/1000;
1750  //if (v>max[idx])
1751  // max[idx]=v;
1752 
1753  max[idx] += v/4;
1754  } */
1755 
1756  vector<float> val(1440);
1757  for (int i=0; i<1440; i++)
1758  val[i] = dat[i%9==8 ? i-2 : i]/1000;
1759 
1760  vector<float> sorted(val);
1761  nth_element(sorted.begin(), sorted.begin()+3, sorted.end(),
1762  std::greater<float>());
1763 
1764  const uint32_t trig = d.GetQoS() & FAD::EventHeader::kLPext;
1765 
1766  const float min = fFadControlDrsRuns[0]==0 ? -1 : 0;
1767 
1768  float scale = 2;
1769  if (trig&FAD::EventHeader::kLPext)
1770  scale = 1;
1771  if (trig&FAD::EventHeader::kPedestal)
1772  scale = 0.25;
1773  if (trig==0)
1774  scale = max(0.25f, sorted[3]);
1775 
1776  // assume it is drs-gain
1777  //if ((trig&FAD::EventHeader::kPedestal) && fFadControlDrsRuns[0]>0 && fFadControlDrsRuns[1]==0)
1778  // min = 0.75;
1779 
1780  WriteCam(d, "cam-fadcontrol-eventdata", val, scale, min);
1781 
1782  return GetCurrentState();
1783  }
1784 
1785  int HandleStats(const EventImp &d)
1786  {
1787  if (!CheckDataSize(d, "Stats", 4*8))
1788  {
1789  fFreeSpace = UINT64_MAX;
1790  return GetCurrentState();
1791  }
1792 
1794  fFreeSpace = s.freeSpace;
1795 
1796  return GetCurrentState();
1797  }
1798 
1800  {
1801  if (!CheckDataSize(d, "FscControl:Temperature", 240))
1802  return GetCurrentState();
1803 
1804  const float *ptr = d.Ptr<float>(4);
1805 
1806  double avg = 0;
1807  double rms = 0;
1808  double min = 99;
1809  double max = -99;
1810 
1811  int num = 0;
1812  for (const float *t=ptr; t<ptr+31; t++)
1813  {
1814  if (*t==0)
1815  continue;
1816 
1817  if (*t>max)
1818  max = *t;
1819 
1820  if (*t<min)
1821  min = *t;
1822 
1823  avg += *t;
1824  rms += *t * *t;
1825 
1826  num++;
1827  }
1828 
1829  avg /= num;
1830  rms /= num;
1831  rms += avg*avg;
1832  rms = rms<0 ? 0 : sqrt(rms);
1833 
1834  // Clean broken reports
1835  static double pre_rms1 = 1.5;
1836  static double pre_rms2 = 0;
1837 
1838  const double cut = pre_rms1 + 0.1;
1839 
1840  const bool reject = rms>cut && pre_rms2<cut;
1841 
1842  pre_rms2 = pre_rms1;
1843  pre_rms1 = rms;
1844 
1845  if (reject)
1846  return GetCurrentState();
1847 
1848 
1849  if (!fMagicWeatherHist[kTemp].empty())
1850  {
1851  fFscControlTemperatureHist.push_back(avg-fMagicWeatherHist[kTemp].back());
1852  if (fFscControlTemperatureHist.size()>300)
1853  fFscControlTemperatureHist.pop_front();
1854  }
1855 
1856  const Statistics stat(fFscControlTemperatureHist);
1857 
1858  ostringstream out;
1859  out << setprecision(3);
1860  out << d.GetJavaDate() << '\n';
1861  out << HTML::kWhite << '\t' << fFscControlHumidityAvg << '\n';
1862  out << HTML::kWhite << '\t' << stat.min << '\n';
1863  out << HTML::kWhite << '\t' << stat.avg << '\n';
1864  out << HTML::kWhite << '\t' << stat.max << '\n';
1865 
1866  ofstream(fPath+"/fsc.data") << out.str();
1867 
1868  WriteHist(d, "hist-fsccontrol-temperature",
1869  fFscControlTemperatureHist, 10);
1870 
1871  out.str("");
1872  out << setprecision(3);
1873  out << d.GetJavaDate() << '\n';
1874  out << HTML::kWhite << '\t' << max << '\n';
1875  out << HTML::kWhite << '\t' << avg << '\n';
1876  out << HTML::kWhite << '\t' << min << '\n';
1877 
1878  ofstream(fPath+"/camtemp.data") << out.str();
1879 
1880  return GetCurrentState();
1881  }
1882 
1884  {
1885  if (!CheckDataSize(d, "FscControl:BiasTemp", 323*4))
1886  return GetCurrentState();
1887 
1888  const float *ptr = d.Ptr<float>(4);
1889  const float avg = d.Get<float>(321*4);
1890  //const float rms = d.Get<float>(322*4);
1891 
1892  vector<double> tout(320);
1893  for (int i=0; i<320; i++)
1894  {
1895  const int idx = (fPixelMap.hv(i).hw()/9)*2+fPixelMap.hv(i).group();
1896  tout[idx] = ptr[i];
1897  }
1898 
1899  WriteCam(d, "cam-fsccontrol-temperature", tout, 3, avg-1.75);
1900 
1901  return GetCurrentState();
1902  }
1903 
1905  {
1906  if (!CheckDataSize(d, "FscControl:Humidity", 5*4))
1907  return GetCurrentState();
1908 
1909  const float *ptr = d.Ptr<float>(4);
1910 
1911  double avg =0;
1912  int num = 0;
1913 
1914  for (const float *t=ptr; t<ptr+4; t++)
1915  if (*t>0 && *t<=100 && t!=ptr+2 /*excl broken sensor*/)
1916  {
1917  avg += *t;
1918  num++;
1919  }
1920 
1921  fFscControlHumidityAvg = num>0 ? avg/num : 0;
1922 
1923  return GetCurrentState();
1924  }
1925 
1927  {
1928  if (!CheckDataSize(d, "PfMini:Data", sizeof(PFmini::Data)))
1929  return GetCurrentState();
1930 
1931  const PFmini::Data &data = d.Ref<PFmini::Data>();
1932 
1933  ostringstream out;
1934 
1935  out << fixed << setprecision(1);
1936  out << d.GetJavaDate() << '\n';
1937 
1938  out << HTML::kGreen << '\t' << data.temp << '\n';
1939  out << HTML::kGreen << '\t' << data.hum << '\n';
1940 
1941  ofstream(fPath+"/pfmini.data") << out.str();
1942 
1943  fPfMiniTemperatureHist.push_back(data.temp);
1944  if (fPfMiniTemperatureHist.size()>60*4) // 1h
1945  fPfMiniTemperatureHist.pop_front();
1946 
1947  fPfMiniHumidityHist.push_back(data.hum);
1948  if (fPfMiniHumidityHist.size()>60*4) // 1h
1949  fPfMiniHumidityHist.pop_front();
1950 
1951  WriteHist(d, "hist-pfmini-temp",
1952  fPfMiniTemperatureHist, 45, 0);
1953 
1954  WriteHist(d, "hist-pfmini-hum",
1955  fPfMiniHumidityHist, 100, 0);
1956 
1957  return GetCurrentState();
1958  }
1959 
1960  int HandleGpsNema(const EventImp &d)
1961  {
1962  if (!CheckDataSize(d, "GpsControl:Nema", sizeof(GPS::NEMA)))
1963  return GetCurrentState();
1964 
1965  const GPS::NEMA &nema = d.Ref<GPS::NEMA>();
1966 
1967  ostringstream out;
1968 
1969  out << fixed;
1970  out << d.GetJavaDate() << '\n';
1971 
1972  switch (nema.qos)
1973  {
1974  case 1: out << HTML::kGreen << "\tGPS fix [1]\n"; break;
1975  case 2: out << HTML::kGreen << "\tDifferential fix [2]\n"; break;
1976  default: out << HTML::kRed << "\tinvalid [" << nema.qos << "]\n"; break;
1977  }
1978 
1979  out << HTML::kWhite << '\t' << nema.count << '\n';
1980  out << HTML::kWhite << '\t' << Time(floor(Time().Mjd())+nema.time).GetAsStr("%H:%M:%S") << '\n';
1981  out << HTML::kWhite << '\t' << setprecision(4) << nema.lat << '\n';
1982  out << HTML::kWhite << '\t' << setprecision(4) << nema.lng << '\n';
1983  out << HTML::kWhite << '\t' << setprecision(1) << nema.height << "\n";
1984  out << HTML::kWhite << '\t' << setprecision(1) << nema.hdop << "\n";
1985  out << HTML::kWhite << '\t' << setprecision(1) << nema.geosep << "\n";
1986 
1987  ofstream(fPath+"/gps.data") << out.str();
1988 
1989  return GetCurrentState();
1990  }
1991 
1992  int HandleSqmData(const EventImp &d)
1993  {
1994  if (!CheckDataSize(d, "SqmControl:Data", sizeof(SQM::Data)))
1995  return GetCurrentState();
1996 
1997  const SQM::Data &data = d.Ref<SQM::Data>();
1998 
1999  ostringstream out;
2000 
2001  out << fixed;
2002  out << d.GetJavaDate() << '\n';
2003  out << HTML::kWhite << '\t' << setprecision(2) << data.mag << '\n';
2004  out << HTML::kWhite << '\t' << data.freq << '\n';
2005  out << HTML::kWhite << '\t' << data.counts << '\n';
2006  out << HTML::kWhite << '\t' << setprecision(3) << data.period << '\n';
2007  out << HTML::kWhite << '\t' << setprecision(1) << data.temp << "\n";
2008 
2009  ofstream(fPath+"/sqm.data") << out.str();
2010 
2011  return GetCurrentState();
2012  }
2013 
2014  string GetTempColor(float t)
2015  {
2016  if (t>25 && t<30)
2017  return HTML::kGreen;
2018 
2019  if (t<20 || t>35)
2020  return HTML::kRed;
2021 
2022  return HTML::kYellow;
2023  }
2024 
2026  {
2027  if (!CheckDataSize(d, "Temperature:Data", 3*sizeof(float)))
2028  return GetCurrentState();
2029 
2030  const float *temp = d.Ptr<float>();
2031 
2032  ostringstream out;
2033 
2034  out << fixed << setprecision(1);
2035  out << d.GetJavaDate() << '\n';
2036 
2037  out << GetTempColor(temp[1]) << '\t' << temp[1] << '\n';
2038  out << GetTempColor(temp[0]) << '\t' << temp[0] << '\n';
2039  out << GetTempColor(temp[2]) << '\t' << temp[2] << '\n';
2040 
2041  ofstream(fPath+"/temperature.data") << out.str();
2042 
2043  fTemperatureControlHist.push_back(temp[0]);
2044  if (fTemperatureControlHist.size()>60) // 1h
2045  fTemperatureControlHist.pop_front();
2046 
2047  WriteHist(d, "hist-temperaturecontrol",
2048  fTemperatureControlHist, 45, 0);
2049 
2050  return GetCurrentState();
2051  }
2052 
2053  int HandleAgilentData(const EventImp &d, const string &ext)
2054  {
2055  if (!CheckDataSize(d, ("Agilent"+ext+":Data").c_str(), 4*sizeof(float)))
2056  return GetCurrentState();
2057 
2058  const float *data = d.Ptr<float>();
2059 
2060  ostringstream out;
2061 
2062  out << fixed << setprecision(1);
2063  out << d.GetJavaDate() << '\n';
2064 
2065  out << HTML::kWhite << '\t' << data[0] << '\n';
2066  out << HTML::kWhite << '\t' << data[1] << '\n';
2067  out << HTML::kWhite << '\t' << data[2] << '\n';
2068  out << HTML::kWhite << '\t' << data[3] << '\n';
2069 
2070  ofstream(fPath+"/agilent"+ext+".data") << out.str();
2071 
2072  return GetCurrentState();
2073  }
2074 
2076  {
2077  if (!CheckDataSize(d, "RateScan:Data", 824))
2078  return GetCurrentState();
2079 
2080  const uint64_t id = d.Get<uint64_t>();
2081  const float *rate = d.Ptr<float>(20);
2082 
2083  if (fRateScanDataId!=id)
2084  {
2085  for (int i=0; i<41; i++)
2086  fRateScanDataHist[i].clear();
2087  fRateScanDataId = id;
2088  }
2089  fRateScanDataHist[0].push_back(log10(rate[0]));
2090 
2091  double max = 0;
2092  for (int i=1; i<41; i++)
2093  {
2094  fRateScanDataHist[i].push_back(log10(rate[i]));
2095  if (rate[i]>max)
2096  max = rate[i];
2097  }
2098 
2099  // Cycle by time!
2100  fRateScanBoard ++;
2101  fRateScanBoard %= 40;
2102 
2103  WriteHist(d, "hist-ratescan", fRateScanDataHist[0], 10, -2);
2104  WriteCam(d, "cam-ratescan-board", fRateScanDataHist[fRateScanBoard+1], 10, -4);
2105 
2106  ostringstream out;
2107  out << setprecision(3);
2108  out << d.GetJavaDate() << '\n';
2109  out << HTML::kWhite << '\t' << fFtmBoardThresholdMed << '\n';
2110  out << HTML::kWhite << '\t' << fFtmPatchThresholdMed << '\n';
2111  out << HTML::kWhite << '\t' << floor(pow(10, fRateScanDataHist[0].back())+.5) << '\n';
2112  out << HTML::kWhite << '\t' << floor(max+.5) << '\n';
2113 
2114  ofstream(fPath+"/ratescan.data") << out.str();
2115 
2116  out.str("");
2117  out << d.GetJavaDate() << '\n';
2118  out << HTML::kWhite << '\t' << int(fRateScanBoard) << '\n';
2119  out << HTML::kWhite << '\t' << pow(10, fRateScanDataHist[fRateScanBoard+1].back()) << '\n';
2120 
2121  ofstream(fPath+"/ratescan_board.data") << out.str();
2122 
2123  return GetCurrentState();
2124  }
2125 
2127  {
2128  if (!CheckDataSize(d, "RateControl:Threshold", 18))
2129  return GetCurrentState();
2130 
2131  const uint16_t th = d.Get<uint16_t>();
2132 
2133  fRateControlThreshold.push_back(th);
2134  if (fRateControlThreshold.size()>300)
2135  fRateControlThreshold.pop_front();
2136 
2137  WriteHist(d, "hist-ratecontrol-threshold", fRateControlThreshold, 1000);
2138 
2139  return GetCurrentState();
2140  }
2141 
2142  int HandleChatMsg(const EventImp &d)
2143  {
2144  if (d.GetSize()==0 || d.GetQoS()!=MessageImp::kComment)
2145  return GetCurrentState();
2146 
2147  if (Time()<d.GetTime()+boost::posix_time::minutes(1))
2148  SetAudio("message");
2149 
2150  fChatHist.add(d.GetText(), d.GetTime());
2151 
2152  ostringstream out;
2153  out << setprecision(3);
2154  out << Header(d) << '\n';
2155  out << HTML::kWhite << '\t';
2156  out << "<->" << fChatHist.rget() << "</->";
2157  out << '\n';
2158 
2159  ofstream(fPath+"/chat.data") << out.str();
2160 
2161  return GetCurrentState();
2162  }
2163 
2164  // -------------------------------------------------------------------
2165 
2166  int HandleDoTest(const EventImp &d)
2167  {
2168  ostringstream out;
2169  out << d.GetJavaDate() << '\n';
2170 
2171  switch (d.GetQoS())
2172  {
2173  case -3: out << HTML::kWhite << "\tNot running\n"; break;
2174  case -2: out << HTML::kBlue << "\tLoading\n"; break;
2175  case -1: out << HTML::kBlue << "\tStarted\n"; break;
2176  default: out << HTML::kGreen << "\tRunning [" << d.GetQoS() << "]\n"; break;
2177  }
2178 
2179  ofstream(fPath+"/dotest.data") << out.str();
2180 
2182  }
2183 
2184  // -------------------------------------------------------------------
2185 
2186  /*
2187  bool CheckEventSize(size_t has, const char *name, size_t size)
2188  {
2189  if (has==size)
2190  return true;
2191 
2192  ostringstream msg;
2193  msg << name << " - Received event has " << has << " bytes, but expected " << size << ".";
2194  Fatal(msg);
2195  return false;
2196  }*/
2197 
2198  int Print() const
2199  {
2200  Out() << fDimDNS << endl;
2201  Out() << fDimMcp << endl;
2202  Out() << fDimControl << endl;
2203  Out() << fDimDataLogger << endl;
2204  Out() << fDimDriveControl << endl;
2205  Out() << fDimTimeCheck << endl;
2206  Out() << fDimFadControl << endl;
2207  Out() << fDimFtmControl << endl;
2208  Out() << fDimBiasControl << endl;
2209  Out() << fDimFeedback << endl;
2210  Out() << fDimRateControl << endl;
2211  Out() << fDimFscControl << endl;
2212  Out() << fDimAgilentControl24 << endl;
2213  Out() << fDimAgilentControl50 << endl;
2214  Out() << fDimAgilentControl80 << endl;
2215  Out() << fDimPwrControl << endl;
2216  Out() << fDimLidControl << endl;
2217  Out() << fDimMagicWeather << endl;
2218  Out() << fDimTngWeather << endl;
2219  Out() << fDimMagicLidar << endl;
2220  Out() << fDimTemperature << endl;
2221  Out() << fDimRateScan << endl;
2222  Out() << fDimChat << endl;
2223  Out() << fDimSkypeClient << endl;
2224 
2225  return GetCurrentState();
2226  }
2227 
2228  string GetStateHtml(const DimState &state, int green) const
2229  {
2230  if (!state.online())
2231  return HTML::kWhite+"\t&mdash;\n";
2232 
2233  if (&state==&fDimControl)
2234  return HTML::kGreen +'\t'+(state.state()==0?"Idle":fDimControl.shortmsg)+'\n';
2235 
2236  const State rc = state.description();
2237 
2238  // Sate not found in list, server online (-3: offline; -2: not found)
2239  if (rc.index==-2)
2240  {
2241  ostringstream out;
2242  out << HTML::kWhite << '\t' << state.state() << '\n';
2243  return out.str();
2244  }
2245 
2246  //ostringstream msg;
2247  //msg << HTML::kWhite << '\t' << rc.name << " [" << rc.index << "]\n";
2248  //return msg.str();
2249 
2250  if (rc.index<0)
2251  return HTML::kWhite + "\t&mdash;\n";
2252 
2253  string col = HTML::kGreen;
2254  if (rc.index<green)
2255  col = HTML::kYellow;
2256  if (rc.index>0xff)
2257  col = HTML::kRed;
2258 
2259  return col + '\t' + rc.name + '\n';
2260  }
2261 
2262  bool SetError(bool b, const string &err)
2263  {
2264  if (!b)
2265  {
2266  fErrorList.erase(err);
2267  return 0;
2268  }
2269 
2270  const bool isnew = fErrorList.insert(err).second;
2271  if (isnew)
2272  fErrorHist.add(err);
2273 
2274  return isnew;
2275  }
2276 
2277 #ifdef HAVE_NOVA
2278 
2279  //vector<pair<Nova::EquPosn, double>> fMoonCoords;
2280 
2281  vector<Nova::SolarObjects> fCoordinates;
2282 
2283  void CalcCoordinates(double jd)
2284  {
2285  jd = floor(jd);
2286 
2287  fCoordinates.clear();
2288  for (double h=0; h<1; h+=1./(24*12))
2289  fCoordinates.emplace_back(jd+h);
2290  }
2291 
2292  pair<vector<float>, pair<Time, float>> GetVisibility(Nova::EquPosn *src=0)
2293  {
2294  const double sunset = fSun.fSunSet12.JD()-1;
2295  const double sunrise = fSun.fSunRise12.JD();
2296 
2297  Nova::EquPosn moon;
2298  Nova::EquPosn *pos = src ? src : &moon;
2299 
2300  double max = 0;
2301  double maxjd = 0;
2302 
2303  int cnt = 0;
2304 
2305  vector<float> alt;
2306  for (auto it=fCoordinates.begin(); it!=fCoordinates.end(); it++)
2307  {
2308  if (src==0)
2309  moon = it->fMoonEqu;
2310 
2311  const Nova::HrzPosn hrz = Nova::GetHrzFromEqu(*pos, it->fJD);
2312 
2313  if (it->fJD>sunset && it->fJD<sunrise)
2314  alt.push_back(hrz.alt);
2315 
2316  if (hrz.alt>max)
2317  {
2318  max = hrz.alt;
2319  maxjd = it->fJD;
2320  }
2321 
2322  if (it->fJD>sunset && it->fJD<sunrise && hrz.alt>15)
2323  cnt++;
2324  }
2325 
2326  if (max<=15 || cnt==0)
2327  return make_pair(vector<float>(), make_pair(Time(), 0));
2328 
2329  return make_pair(alt, make_pair(maxjd, maxjd>sunset&&maxjd<sunrise?max:0));
2330  }
2331 
2332  pair<vector<float>, pair<Time, float>> GetLightCondition(const Nova::EquPosn &src_pos)
2333  {
2334  const double sunset = fSun.fSunSet12.JD()-1;
2335  const double sunrise = fSun.fSunRise12.JD();
2336 
2337  double max = -1;
2338  double maxjd = 0;
2339 
2340  int cnt = 0;
2341 
2342  vector<float> vec;
2343  for (auto it=fCoordinates.begin(); it!=fCoordinates.end(); it++)
2344  {
2345  double cur = -1;
2346 
2347  if (it->fJD>sunset && it->fJD<sunrise)
2348  {
2349  cur = FACT::PredictI(*it, src_pos);
2350  vec.push_back(cur);
2351  }
2352 
2353  if (cur>max)
2354  {
2355  max = cur;
2356  maxjd = it->fJD;
2357  }
2358 
2359  if (it->fJD>sunset && it->fJD<sunrise && cur>0)
2360  cnt++;
2361  }
2362 
2363  if (max<=0 || cnt==0)
2364  return make_pair(vector<float>(), make_pair(Time(), 0));
2365 
2366  return make_pair(vec, make_pair(maxjd, maxjd>sunset&&maxjd<sunrise?max:-1));
2367  }
2368 #endif
2369 
2371  {
2372  Time now;
2373 
2374  CalcCoordinates(now.JD());
2375 
2376  fSun = Sun (now);
2377  fMoon = Moon(now);
2378 
2379  vector<string> color(8, HTML::kWhite);
2380  color[fSun.state] = HTML::kBlue;
2381 
2382  ostringstream out;
2383  out << setprecision(3);
2384  out << now.JavaDate() << '\n';
2385  out << color[4] << '\t' << fSun.fSunRise18.GetAsStr("%H:%M") << '\n';
2386  out << color[5] << '\t' << fSun.fSunRise12.GetAsStr("%H:%M") << '\n';
2387  out << color[6] << '\t' << fSun.fSunRise06.GetAsStr("%H:%M") << '\n';
2388  out << color[7] << '\t' << fSun.fSunRise00.GetAsStr("%H:%M") << '\n';
2389 
2390  out << color[0] << '\t' << fSun.fSunSet00.GetAsStr("%H:%M") << '\n';
2391  out << color[1] << '\t' << fSun.fSunSet06.GetAsStr("%H:%M") << '\n';
2392  out << color[2] << '\t' << fSun.fSunSet12.GetAsStr("%H:%M") << '\n';
2393  out << color[3] << '\t' << fSun.fSunSet18.GetAsStr("%H:%M") << '\n';
2394 
2395  ofstream(fPath+"/sun.data") << out.str();
2396 
2397  color.assign(3, HTML::kWhite);
2398  color[fMoon.state%3] = HTML::kBlue;
2399 
2400  out.str("");
2401  out << now.JavaDate() << '\n';
2402 
2403  out << color[0] << '\t' << fMoon.fRise.GetAsStr("%H:%M") << '\n';
2404  out << color[1] << '\t' << fMoon.fTransit.GetAsStr("%H:%M") << '\n';
2405  out << color[2] << '\t' << fMoon.fSet.GetAsStr("%H:%M") << '\n';
2406 
2407  out << (fSun.isday?HTML::kWhite:fMoon.color) << '\t' << fMoon.description << '\n';
2408 
2409  if (!fMoon.visible)
2410  out << HTML::kWhite << "\t&mdash;\t\n";
2411  else
2412  {
2413  string col = HTML::kWhite;
2414  if (!fSun.isday)
2415  {
2416  col = HTML::kGreen;
2417  if (fMoon.zd>25)
2418  col = HTML::kYellow;
2419  if (fMoon.zd>45 && fMoon.zd<80)
2420  col = HTML::kRed;
2421  if (fMoon.zd>=80)
2422  col = HTML::kRed;
2423  }
2424  out << col << '\t' << fMoon.zd << '\t' << GetDir(fMoon.az) << '\n';
2425  }
2426 
2427  ostringstream out2, out3, out4;
2428  out2 << setprecision(3);
2429  out2 << now.JavaDate() << '\n';
2430  out3 << now.JavaDate() << '\n';
2431  out4 << now.JavaDate() << '\n';
2432 
2433  struct Entry
2434  {
2435  string name;
2436  float value;
2437  int color;
2438  Entry(const string &n, float v, int c) : name(n), value(v), color(c%8) { }
2439 
2440  const string &Col() const
2441  {
2442  // If this list is updatd the number count in the constructor needs
2443  // to be updated, too
2444  static const string hcol[] = { "888", "8cf", "c8f", "bbb", "8fc", "cf8", "f8c", "fc8" };
2445  return hcol[color];
2446  }
2447 
2448  vector<float> GetColor(double scale, double offset=0) const
2449  {
2450  vector<float> rc(3);
2451  rc[0] = double(Col()[0])*scale/126+offset;
2452  rc[1] = double(Col()[1])*scale/126+offset;
2453  rc[2] = double(Col()[2])*scale/126+offset;
2454  return rc;
2455  }
2456  };
2457 
2458  multimap<Time, Entry> culmination;
2459  multimap<Time, Entry> lightcond;
2460  vector<vector<float>> alt;
2461  vector<vector<float>> cur;
2462 
2463 #ifdef HAVE_NOVA
2464  int ccol = 0;
2465  int lcol = 0;
2466 
2467  /*const*/ pair<vector<float>, pair<Time, float>> vism = GetVisibility();
2468  if (!vism.first.empty())
2469  {
2470  const Entry entry("Moon", vism.second.second, ccol);
2471  culmination.insert(make_pair(vism.second.first, entry));
2472  const vector<float> col = entry.GetColor(75, 15);
2473  vism.first.insert(vism.first.begin(), col.begin(), col.end());
2474  alt.push_back(vism.first);
2475 
2476  ccol++;
2477  }
2478 #endif
2479 
2480 #ifdef HAVE_SQL
2481  try
2482  {
2483  const mysqlpp::StoreQueryResult res =
2484  Database(fDatabase).query("SELECT fSourceName, fRightAscension, fDeclination FROM Source WHERE fSourceTypeKEY=1").store();
2485 
2486  out << HTML::kWhite << '\t';
2487  out2 << HTML::kWhite << '\t';
2488  out3 << HTML::kWhite << '\t';
2489  out4 << HTML::kWhite << '\t';
2490 
2491  for (vector<mysqlpp::Row>::const_iterator v=res.begin(); v<res.end(); v++)
2492  {
2493  const string name = (*v)[0].c_str();
2494  const double ra = (*v)[1];
2495  const double dec = (*v)[2];
2496 #ifdef HAVE_NOVA
2497  Nova::EquPosn pos;
2498  pos.ra = ra*15;
2499  pos.dec = dec;
2500 
2501  const Nova::ZdAzPosn hrz = Nova::GetHrzFromEqu(pos, now.JD());
2502 
2503  /*const*/ pair<vector<float>, pair<Time, float>> vis = GetVisibility(&pos);
2504  if (!vis.first.empty())
2505  {
2506  const Entry entry(name, vis.second.second, ccol);
2507  culmination.insert(make_pair(vis.second.first, entry));
2508  const vector<float> col = entry.GetColor(75, 15);
2509  vis.first.insert(vis.first.begin(), col.begin(), col.end());
2510  alt.push_back(vis.first);
2511 
2512  ccol++;
2513 
2514  /*const*/ pair<vector<float>, pair<Time, float>> lc = GetLightCondition(pos);
2515  if (!lc.first.empty())
2516  {
2517  const Entry entry2(name, lc.second.second, lcol);
2518  lightcond.insert(make_pair(lc.second.first, entry2));
2519  const vector<float> col2 = entry2.GetColor(100);
2520  lc.first.insert(lc.first.begin(), col2.begin(), col2.end());
2521  cur.push_back(lc.first);
2522 
2523  lcol++;
2524  }
2525  }
2526 
2527  string col = HTML::kWhite;
2528  if (hrz.zd<85)
2529  col = HTML::kRed;
2530  if (hrz.zd<65)
2531  col = HTML::kYellow;
2532  if (hrz.zd<30)
2533  col = HTML::kGreen;
2534 
2535  out2 << "<tr bgcolor='" << col << "'>";
2536  out2 << "<td>" << name << "</td>";
2537  if (hrz.zd<85)
2538  {
2539  out2 << "<td>" << hrz.zd << "&deg;</td>";
2540  out2 << "<td>" << GetDir(hrz.az) << "</td>";
2541  }
2542  else
2543  out2 << "<td/><td/>";
2544  out2 << "</tr>";
2545 #endif
2546  const int32_t angle = fMoon.Angle(ra, dec);
2547 
2548  out << "<tr bgcolor='" << Moon::Color(angle) << "'>";
2549  out << "<td>" << name << "</td>";
2550  out << "<td>" << round(angle) << "&deg;</td>";
2551  out << "</tr>";
2552  }
2553 
2554  for (auto it=culmination.begin(); it!=culmination.end(); it++)
2555  {
2556  const Entry &e = it->second;
2557  if (it!=culmination.begin())
2558  out3 << ", ";
2559  out3 << "<B#" << e.Col() << ">" << e.name << "</B>";
2560  if (e.value>0)
2561  out3 << " [" << nearbyint(90-e.value) << "&deg;]";
2562  }
2563 
2564  out4 << setprecision(3);
2565 
2566  for (auto it=lightcond.begin(); it!=lightcond.end(); it++)
2567  {
2568  const Entry &e = it->second;
2569  if (it!=lightcond.begin())
2570  out4 << ", ";
2571  out4 << "<B#" << e.Col() << ">" << e.name << "</B>";
2572  if (e.value>0)
2573  out4 << " [" << nearbyint(e.value) << "]";
2574  }
2575 
2576  const Time st = fSun.fSunSet12;;
2577  const Time rs = fSun.fSunRise12;
2578 
2579  ostringstream title;
2580  title << st.GetAsStr("%H:%M");
2581  title << " / ";
2582  title << ((rs>st?rs-st:st-rs)/20).minutes();
2583  title << "' / ";
2584  title << rs.GetAsStr("%H:%M");
2585 
2586  out << '\n';
2587  out2 << '\n';
2588  out3 << '\n';
2589  out4 << '\n';
2590  out << HTML::kWhite << '\t' << Time()-now << '\n';
2591  out2 << HTML::kWhite << '\t' << Time()-now << '\n';
2592 
2593  WriteBinaryVec(now, "hist-visibility", alt, 75, 15, "Alt "+title.str());
2594  WriteBinaryVec(now, "hist-current-prediction", cur, 100, 0, "I " +title.str());
2595  }
2596  catch (const exception &e)
2597  {
2598  out << '\n';
2599  out2 << '\n';
2600  out << HTML::kWhite << '\t' << "ERROR - "+string(e.what()) << '\n';
2601  out2 << HTML::kWhite << '\t' << "ERROR - "+string(e.what()) << '\n';
2602  out3 << HTML::kWhite << '\t' << "ERROR - "+string(e.what()) << '\n';
2603  out4 << HTML::kWhite << '\t' << "ERROR - "+string(e.what()) << '\n';
2604  }
2605 #endif
2606 
2607  ofstream(fPath+"/moon.data") << out.str();
2608  ofstream(fPath+"/source-list.data") << out2.str();
2609  ofstream(fPath+"/visibility.data") << out3.str();
2610  ofstream(fPath+"/current-prediction.data") << out4.str();
2611  }
2612 
2613  int Execute()
2614  {
2615  Time now;
2616  if (now-fLastUpdate<boost::posix_time::seconds(1))
2617  return fDimDNS.online() ? kStateRunning : kStateDimNetworkNA;
2618  fLastUpdate=now;
2619 
2620  // ==============================================================
2621 
2622  bool reqscript = false;
2623 
2624 #ifdef HAVE_SQL
2625  try
2626  {
2627  const string query = Tools::Form("SELECT COUNT(*) FROM calendar.Data WHERE NOT u LIKE 'moon' AND y=%d AND m=%d AND d=%d",
2628  now.NightAsInt()/10000, (now.NightAsInt()/100)%100-1, now.NightAsInt()%100);
2629 
2630  const mysqlpp::StoreQueryResult res = Database(fDatabase).query(query).store();
2631 
2632  const uint32_t cnt = res[0][0];
2633 
2634  reqscript = cnt>0 && (fSun.state==3 || fSun.state==4);
2635  }
2636  catch (const exception &e)
2637  {
2638  Out() << e.what() << endl;
2639  }
2640 #endif
2641  // ==============================================================
2642 
2643  struct statvfs vfs;
2644  statvfs("/daq", &vfs);
2645 
2646  const uint64_t freedaq = vfs.f_bsize*vfs.f_bavail;
2647 
2648  // ==============================================================
2649 
2650  const bool data_taking =
2651  fDimMcp.state()==MCP::State::kTriggerOn ||
2652  fDimMcp.state()==MCP::State::kTakingData;
2653 
2654  const bool data_run =
2655  fMcpConfigurationName=="data" ||
2656  fMcpConfigurationName=="data-rt";
2657 
2658  const bool bias_on =
2659  fDimBiasControl.state()==BIAS::State::kRamping ||
2660  fDimBiasControl.state()==BIAS::State::kOverCurrent ||
2661  fDimBiasControl.state()==BIAS::State::kVoltageOn;
2662 
2663  const bool calibrated =
2664  fDimFeedback.state()>=Feedback::State::kCalibrated;
2665 
2666  const bool haderr = !fErrorList.empty();
2667 
2668  bool newerr = false;
2669 
2670  newerr |= SetError(!fDimDNS.online(),
2671  "<b><#darkred>DIM network not available</#></b>");
2672  newerr |= SetError(!fDimControl.online(),
2673  "<b>no dimctrl server available</b>");
2674  newerr |= SetError(fDimDataLogger.state()<20 || fDimDataLogger.state()>40,
2675  "<b>datalogger not ready</b>");
2676 
2677  newerr |= SetError(fDimControl.state()!=3 && reqscript,
2678  "<b>No script running during datataking time.</b>");
2679 
2680  //newerr |= SetError(fDimDriveControl.state()==Drive::State::kLocked,
2681  // "<b><#darkred>Drive in LOCKED state, drive was automatically parked</#></b>");
2682 
2683  newerr |= SetError(fDimDriveControl.state()>0xff && data_taking && data_run,
2684  "Drive in ERROR state during data-run");
2685  newerr |= SetError(fDriveControlMoonDist>155,
2686  "Moon within the field-of-view of the cones");
2687  newerr |= SetError(fDriveControlMoonDist>=0 && fDriveControlMoonDist<3,
2688  "Moon within the field-of-view of the camera");
2689 
2690  newerr |= SetError(fDimBiasControl.state()<BIAS::State::kRamping && data_taking && data_run,
2691  "BIAS not operating during data-run");
2692  newerr |= SetError(fDimBiasControl.state()==BIAS::State::kOverCurrent,
2693  "BIAS channels in OverCurrent");
2694  newerr |= SetError(fDimBiasControl.state()==BIAS::State::kNotReferenced,
2695  "BIAS voltage not at reference");
2696 
2697  newerr |= SetError(fDimFeedback.state()==Feedback::State::kOnStandby,
2698  "Feedback in standby due to high currents");
2699 
2700 
2701  newerr |= SetError(bias_on && calibrated && fBiasControlCurrentMed>115,
2702  "Median current (excl. crazy) exceeds 115&micro;A/pix");
2703  newerr |= SetError(bias_on && calibrated && fBiasControlCurrentMax>160,
2704  "Maximum current (excl. crazy) exceeds 160&micro;A/pix");
2705 
2706  newerr |= SetError(fFscControlHumidityAvg>60,
2707  "Average camera humidity exceed 60%");
2708 
2709  newerr |= SetError(!fPfMiniHumidityHist.empty() && fPfMiniHumidityHist.back()>50,
2710  "Camera humidity inside camera exceeds 50% (PFmini)");
2711  newerr |= SetError(!fTemperatureControlHist.empty() && (fTemperatureControlHist.back()<26.5 || fTemperatureControlHist.back()>29),
2712  "Container temperature outside [26.5;29]&deg;C");
2713 
2714  newerr |= SetError(!fMagicWeatherHist[kHum].empty() && fMagicWeatherHist[kHum].back()>98 && fDimLidControl.state()==Lid::State::kOpen,
2715  "Outside humidity exceeds 98% while lid is open");
2716  newerr |= SetError(!fMagicWeatherHist[kGusts].empty() && fMagicWeatherHist[kGusts].back()>50 && (fDimDriveControl.state()==Drive::State::kTracking||fDimDriveControl.state()==Drive::State::kOnTrack),
2717  "Wind gusts exceed 50km/h during tracking");
2718 
2719  newerr |= SetError(fDimFscControl.state()>=FSC::State::kConnected && !fFscControlTemperatureHist.empty() && fFscControlTemperatureHist.back()>15,
2720  "Sensor temperature exceeds outside temperature by more than 15&deg;C");
2721 
2722  newerr |= SetError(fFtmControlTriggerRateTooLow>0,
2723  "Trigger rate below 1Hz while trigger switched on");
2724 
2725  newerr |= SetError(fFtmControlState!=FTM::kFtmConfig && (fFtmControlState&FTM::kFtmLocked)==0,
2726  "FTM - clock conditioner not locked!");
2727 
2728  newerr |= SetError(fDimTimeCheck.state()==1,
2729  "Warning NTP time difference of drive PC exceeds 1s");
2730  newerr |= SetError(fDimTimeCheck.state()<1,
2731  "Warning timecheck not running");
2732 
2733  newerr |= SetError(fDimBiasControl.state()==BIAS::State::kVoltageOn &&
2734  fDimFeedback.state()<Feedback::State::kCalibrating &&
2735  fBiasControlVoltageMed>3,
2736  "Bias voltage switched on, but bias crate not calibrated");
2737 
2738  newerr |= SetError(fLastRunFinishedWithZeroEvents,
2739  "Last run finshed, but contained zero events.");
2740 
2741  newerr |= SetError(fFreeSpace<uint64_t(50000000000),
2742  "Less than 50GB disk space left on newdaq.");
2743 
2744  newerr |= SetError(freedaq<uint64_t(800000000000),
2745  "Less than 800GB disk space left on daq.");
2746 
2747  newerr |= SetError(fDimPwrControl.state()==Power::State::kCoolingFailure,
2748  "Cooling unit reports failure!");
2749 
2750  for (auto it=fControlAlarmHist.begin(); it!=fControlAlarmHist.end(); it++)
2751  newerr |= SetError(it->time.IsValid(), it->msg);
2752  fControlAlarmHist.clean();;
2753 
2754  fLastRunFinishedWithZeroEvents = false;
2755 
2756  // FTM in Connected instead of Idle --> power cyclen
2757 
2758  /* // Check offline and disconnected status?
2759  Out() << fDimMcp << endl;
2760  Out() << fDimControl << endl;
2761  Out() << fDimDataLogger << endl;
2762  Out() << fDimDriveControl << endl;
2763  Out() << fDimFadControl << endl;
2764  Out() << fDimFtmControl << endl;
2765  Out() << fDimBiasControl << endl;
2766  Out() << fDimFeedback << endl;
2767  Out() << fDimRateControl << endl;
2768  Out() << fDimFscControl << endl;
2769  Out() << fDimMagicWeather << endl;
2770  Out() << fDimRateScan << endl;
2771  Out() << fDimChat << endl;
2772  */
2773 
2774  // FTU in error
2775  // FAD lost
2776 
2777  // --------------------------------------------------------------
2778  ostringstream out;
2779 
2780  if (newerr)
2781  {
2782  SetAudio("error");
2783 
2784  out << now.JavaDate() << '\n';
2785  out << HTML::kWhite << '\t';
2786  out << "<->" << fErrorHist.rget() << "<->";
2787  out << '\n';
2788 
2789  ofstream(fPath+"/errorhist.data") << out.str();
2790  }
2791 
2792  out.str("");
2793  out << Header(now) << '\t' << (!fErrorList.empty()) << '\t' << (fDimControl.state()>0) << '\n';
2794  out << setprecision(3);
2795  out << HTML::kWhite << '\t';
2796  for (auto it=fErrorList.begin(); it!=fErrorList.end(); it++)
2797  out << *it << "<br/>";
2798  out << '\n';
2799 
2800  if (haderr || !fErrorList.empty())
2801  ofstream(fPath+"/error.data") << out.str();
2802 
2803  // ==============================================================
2804 
2805  out.str("");
2806  out << Header(now) << '\t' << (!fErrorList.empty()) << '\t' << (fDimControl.state()>0) << '\n';
2807  out << setprecision(3);
2808 
2809  // -------------- System status --------------
2810  if (fDimDNS.online() && fDimMcp.state()>=MCP::State::kIdle) // Idle
2811  {
2812  string col = HTML::kBlue;
2813  switch (fMcpConfigurationState)
2814  {
2815  case MCP::State::kIdle:
2816  case DimState::kOffline:
2817  col = HTML::kWhite;
2818  break;
2824  col = HTML::kBlue;
2825  break;
2827  col = HTML::kBlue;
2828  if (fDimFadControl.state()==FAD::State::kRunInProgress)
2829  col = HTML::kGreen;
2830  break;
2831  }
2832 
2833  const bool other =
2835  fDimLidControl.state()==Lid::State::kMoving ||
2836  fDimRateScan.state()==RateScan::State::kInProgress;
2837 
2838  if (other)
2839  col = HTML::kBlue;
2840 
2841  out << col << '\t';
2842 
2843  if (!other)
2844  {
2845  const string conf = fMcpConfigurationName.length()>0?" ["+fMcpConfigurationName+"]":"";
2846  switch (fMcpConfigurationState)
2847  {
2848  case MCP::State::kIdle:
2849  out << "Idle" << conf;
2850  break;
2854  out << "Configuring" << conf;
2855  break;
2857  out << "Configured" << conf;
2858  break;
2861  out << fMcpConfigurationName;
2862  if (fFadControlDrsRuns[2]>0)
2863  out << "(" << fFadControlDrsRuns[2] << ")";
2864  break;
2865  }
2866  }
2867  else
2868  if (fDimRateControl.state()==RateControl::State::kSettingGlobalThreshold)
2869  out << "Calibrating threshold";
2870  else
2871  if (fDimRateScan.state()==RateScan::State::kInProgress)
2872  out << "Rate scan in progress";
2873  else
2874  if (fDimLidControl.state()==Lid::State::kMoving)
2875  out << "Lid moving";
2876 
2877 
2878  if (fMcpConfigurationState>MCP::State::kConfigured &&
2880  {
2881  ostringstream evt;
2882  if (fMcpConfigurationMaxEvents>0)
2883  {
2884  const int64_t de = int64_t(fMcpConfigurationMaxEvents) - int64_t(fFadControlNumEvents);
2885  if (de>=0 && fMcpConfigurationState==MCP::State::kTakingData)
2886  evt << de;
2887  else
2888  evt << fMcpConfigurationMaxEvents;
2889  }
2890  else
2891  {
2892  if (fMcpConfigurationState==MCP::State::kTakingData)
2893  {
2894  if (fFadControlNumEvents>2999)
2895  evt << floor(fFadControlNumEvents/1000) << 'k';
2896  else
2897  evt << fFadControlNumEvents;
2898  }
2899  }
2900 
2901  ostringstream tim;
2902  if (fMcpConfigurationMaxTime>0)
2903  {
2904  const uint32_t dt = (Time()-fMcpConfigurationRunStart).total_seconds();
2905  if (dt<=fMcpConfigurationMaxTime && fMcpConfigurationState==MCP::State::kTakingData)
2906  tim << fMcpConfigurationMaxTime-dt << 's';
2907  else
2908  tim << fMcpConfigurationMaxTime << 's';
2909  }
2910  else
2911  {
2912  if (fMcpConfigurationState==MCP::State::kTakingData)
2913  tim << fMcpConfigurationRunStart.SecondsTo();
2914  }
2915 
2916  const bool has_evt = !evt.str().empty();
2917  const bool has_tim = !tim.str().empty();
2918 
2919  if (has_evt || has_tim)
2920  out << " [";
2921  out << evt.str();
2922  if (has_evt && has_tim)
2923  out << '/';
2924  out << tim.str();
2925  if (has_evt || has_tim)
2926  out << ']';
2927  }
2928  }
2929  else
2930  out << HTML::kWhite;
2931  out << '\n';
2932 
2933  // ------------------ Drive -----------------
2934  if (fDimDNS.online() && fDimDriveControl.state()>=Drive::State::kInitialized) // Armed, Moving, Tracking, OnTrack, Error
2935  {
2936  const uint32_t dev = !fDriveControlTrackingDevHist.empty() ? round(fDriveControlTrackingDevHist.back()) : 0;
2937  const State rc = fDimDriveControl.description();
2938  string col = HTML::kGreen;
2939  if (fDimDriveControl.state()==Drive::State::kInitialized) // Armed
2940  col = HTML::kWhite;
2941  if (fDimDriveControl.state()>Drive::State::kInitialized && // Moving
2942  fDimDriveControl.state()<Drive::State::kTracking)
2943  col = HTML::kBlue;
2944  if (fDimDriveControl.state()==Drive::State::kTracking || // Tracking
2945  fDimDriveControl.state()==Drive::State::kOnTrack)
2946  {
2947  if (dev>60) // ~1.5mm
2948  col = HTML::kYellow;
2949  if (dev>120) // ~1/4 of a pixel ~ 2.5mm
2950  col = HTML::kRed;
2951  }
2952  if (fDimDriveControl.state()>0xff)
2953  col = HTML::kRed;
2954  out << col << '\t';
2955 
2956  //out << rc.name << '\t';
2957  out << fDriveControlPointingAz << ' ';
2958  out << fDriveControlPointingZd << "&deg;";
2959  out << setprecision(2);
2960  if (fDimDriveControl.state()==Drive::State::kTracking ||
2961  fDimDriveControl.state()==Drive::State::kOnTrack) // Tracking
2962  {
2963  out << " &plusmn; " << dev << '"';
2964  if (!fDriveControlSourceName.empty())
2965  out << " [" << fDriveControlSourceName << ']';
2966  }
2967  if (fDimDriveControl.state()>Drive::State::kInitialized && // Moving
2968  fDimDriveControl.state()<Drive::State::kTracking)
2969  out << " &#10227;";
2970  out << setprecision(3);
2971  }
2972  else
2973  out << HTML::kWhite << '\t';
2974 
2975  if (fSun.time.IsValid() && fMoon.time.IsValid())
2976  {
2977  if (fSun.visible)
2978  {
2979  out << " &#9788;";
2980  if (fDimDriveControl.state()<Drive::State::kInitialized)
2981  out << " [" << fSun.fSunSet12.MinutesTo() << "&darr;]";
2982  }
2983  else
2984  if (!fSun.visible && fMoon.visible)
2985  {
2986  out << " &#9790;";
2987  if (fDimDriveControl.state()<Drive::State::kInitialized)
2988  out << " [" << fMoon.disk << "%]";
2989  }
2990  }
2991  if (fDimDNS.online() && fDimDriveControl.state()>0xff)
2992  out << " <ERR>";
2993  if (fDimDNS.online() && fDimDriveControl.state()==Drive::State::kLocked)
2994  out << " &otimes;";
2995  out << '\n';
2996 
2997  // ------------------- FSC ------------------
2998  if (fDimDNS.online() && fDimFscControl.state()>FSC::State::kDisconnected && !fFscControlTemperatureHist.empty())
2999  {
3000  string col = HTML::kGreen;
3001  if (fFscControlTemperatureHist.back()>9)
3002  col = HTML::kYellow;
3003  if (fFscControlTemperatureHist.back()>15)
3004  col = HTML::kRed;
3005 
3006  out << col << '\t' << fFscControlTemperatureHist.back() << '\n';
3007  }
3008  else
3009  out << HTML::kWhite << '\n';
3010 
3011  // --------------- MagicWeather -------------
3012  if (fDimDNS.online() && fDimMagicWeather.state()==MagicWeather::State::kReceiving && !fMagicWeatherHist[kWeatherBegin].empty())
3013  {
3014  /*
3015  const float diff = fMagicWeatherHist[kTemp].back()-fMagicWeatherHist[kDew].back();
3016  string col1 = HTML::kRed;
3017  if (diff>0.3)
3018  col1 = HTML::kYellow;
3019  if (diff>0.7)
3020  col1 = HTML::kGreen;
3021  */
3022 
3023  const float wind = fMagicWeatherHist[kGusts].back();
3024  const float hum = fMagicWeatherHist[kHum].back();
3025  string col = HTML::kGreen;
3026  if (wind>35 || hum>95)
3027  col = HTML::kYellow;
3028  if (wind>45 || hum>98)
3029  col = HTML::kRed;
3030 
3031  out << col << '\t';
3032  out << fMagicWeatherHist[kHum].back() << '\t';
3033  out << setprecision(2);
3034  out << fMagicWeatherHist[kGusts].back() << '\n';
3035  out << setprecision(3);
3036  }
3037  else
3038  out << HTML::kWhite << "\n";
3039 
3040  // --------------- FtmControl -------------
3041  if (fDimDNS.online() && fDimFtmControl.state()==FTM::State::kTriggerOn)
3042  {
3043  string col = HTML::kGreen;
3044  if (!fFtmControlTriggerRateHist.empty())
3045  {
3046  if (fFtmControlTriggerRateHist.back()<15)
3047  col = HTML::kYellow;
3048  if (fFtmControlTriggerRateHist.back()>100)
3049  col = HTML::kRed;
3050 
3051  out << col << '\t' << fFtmControlTriggerRateHist.back() << " Hz";
3052  }
3053 
3054  if (bias_on)
3055  out << " (" << setprecision(4) << fFtmPatchThresholdMed << ')';
3056  out << '\n';
3057  }
3058  else
3059  out << HTML::kWhite << '\n';
3060 
3061  // --------------- BiasControl -------------
3062  const bool bias_off = fDimBiasControl.state()==BIAS::State::kVoltageOff;
3063  const bool bias_oc = fDimBiasControl.state()==BIAS::State::kOverCurrent;
3064 
3065  if (fDimDNS.online() && (bias_on || bias_off))
3066  {
3067 
3068  string col = fBiasControlVoltageMed>3?HTML::kGreen:HTML::kWhite;
3069  if (bias_on)
3070  {
3071  if (fBiasControlCurrentMed>95 || fBiasControlCurrentMax>135)
3072  col = HTML::kYellow;
3073  if (fBiasControlCurrentMed>100 || fBiasControlCurrentMax>140)
3074  col = HTML::kRed;
3075  }
3076 
3077  // Bias in overcurrent => Red
3078  if (bias_oc)
3079  col = HTML::kRed;
3080 
3081  // MCP in ReadyForDatataking/Configuring/Configured/TriggerOn/TakingData
3082  // and Bias not in "data-taking state' => Red
3083  if (fMcpConfigurationState>MCP::State::kIdle && !bias_on)
3084  col = HTML::kWhite;
3085 
3086  const bool cal = fDimFeedback.state()>=Feedback::State::kCalibrated;
3087 
3088  // Feedback is currently calibrating => Blue
3089  if (fDimFeedback.state()==Feedback::State::kCalibrating)
3090  {
3091  out << HTML::kBlue << '\t';
3092  out << "***\t";
3093  out << "***\t";
3094  }
3095  else
3096  {
3097  out << col << '\t';
3098  out << setprecision(fBiasControlCurrentMed<100?2:3);
3099  out << (bias_off ? 0 : (fBiasControlCurrentMed<10?fBiasControlCurrentMed:floor(fBiasControlCurrentMed))) << '\t';
3100  if (bias_oc)
3101  out << "(OC) ";
3102  else
3103  {
3104  if (cal)
3105  {
3106  out << setprecision(fBiasControlCurrentMax<100?2:3);
3107  out << (bias_off ? 0 : (fBiasControlCurrentMax<10?fBiasControlCurrentMax:floor(fBiasControlCurrentMax)));
3108  }
3109  else
3110  out << "&mdash; ";
3111  }
3112  out << '\t';
3113  }
3114  if (cal && fDimFeedback.state()!=Feedback::State::kCalibrating)
3115  out << setprecision(2) << fBiasControlPowerTot << " W";
3116  else
3117  out << setprecision(3) << (bias_off ? 0 : fBiasControlVoltageMed) << " V";
3118  out << '\n';
3119  }
3120  else
3121  out << HTML::kWhite << '\n';
3122 
3123  ofstream(fPath+"/fact.data") << out.str();
3124 
3125  // ==============================================================
3126 
3127  out.str("");
3128  out << Header(now) << '\t' << (!fErrorList.empty()) << '\t' << (fDimControl.state()>0) << '\n';
3129 
3130  if (!fDimDNS.online())
3131  out << HTML::kWhite << "\tOffline\n\n\n\n\n\n\n\n\n\n\n\n\n";
3132  else
3133  {
3134  ostringstream dt;
3135  dt << (Time()-fRunTime);
3136 
3137  out << HTML::kGreen << '\t' << fDimDNS.version() << '\n';
3138 
3139  out << GetStateHtml(fDimControl, 0);
3140  out << GetStateHtml(fDimMcp, MCP::State::kConnected);
3141  out << GetStateHtml(fDimDataLogger, 1);
3142  out << GetStateHtml(fDimDriveControl, Drive::State::kConnected);
3143  out << GetStateHtml(fDimTimeCheck, 1);
3144  out << GetStateHtml(fDimFadControl, FAD::State::kConnected);
3145  out << GetStateHtml(fDimFtmControl, FTM::State::kConnected);
3146  out << GetStateHtml(fDimBiasControl, BIAS::State::kConnected);
3147  out << GetStateHtml(fDimFeedback, Feedback::State::kConnected);
3148  out << GetStateHtml(fDimRateControl, RateControl::State::kConnected);
3149  out << GetStateHtml(fDimFscControl, FSC::State::kConnected);
3150  out << GetStateHtml(fDimPfMiniControl, PFmini::State::kConnected);
3151  out << GetStateHtml(fDimGpsControl, GPS::State::kConnected);
3152  out << GetStateHtml(fDimSqmControl, SQM::State::kConnected);
3153  out << GetStateHtml(fDimAgilentControl24, Agilent::State::kVoltageOff);
3154  out << GetStateHtml(fDimAgilentControl50, Agilent::State::kVoltageOff);
3155  out << GetStateHtml(fDimAgilentControl80, Agilent::State::kVoltageOff);
3156  out << GetStateHtml(fDimPwrControl, Power::State::kSystemOff);
3157  out << GetStateHtml(fDimLidControl, Lid::State::kConnected);
3158  out << GetStateHtml(fDimRateScan, RateScan::State::kConnected);
3159  out << GetStateHtml(fDimMagicWeather, MagicWeather::State::kConnected);
3160  out << GetStateHtml(fDimTngWeather, TNGWeather::State::kConnected);
3161  out << GetStateHtml(fDimMagicLidar, MagicLidar::State::kConnected);
3162  out << GetStateHtml(fDimTemperature, Temperature::State::kValid);
3163  out << GetStateHtml(fDimChat, 0);
3164  out << GetStateHtml(fDimSkypeClient, 1);
3165 
3166  string col = HTML::kRed;
3167  if (fFreeSpace>uint64_t(199999999999))
3168  col = HTML::kYellow;
3169  if (fFreeSpace>uint64_t(999999999999))
3170  col = HTML::kGreen;
3171  if (fFreeSpace==UINT64_MAX)
3172  col = HTML::kWhite;
3173 
3174  out << col << '\t' << Tools::Scientific(fFreeSpace) << "B\n";
3175 
3176  col = HTML::kRed;
3177  if (freedaq>uint64_t(999999999999))
3178  col = HTML::kYellow;
3179  if (freedaq>uint64_t(149999999999))
3180  col = HTML::kGreen;
3181  if (freedaq==UINT64_MAX)
3182  col = HTML::kWhite;
3183 
3184  out << col << '\t' << Tools::Scientific(freedaq) << "B\n";
3185 
3186  out << HTML::kGreen << '\t' << dt.str().substr(0, dt.str().length()-7) << '\n';
3187  }
3188 
3189  ofstream(fPath+"/status.data") << out.str();
3190 
3191  if (now-fLastAstroCalc>boost::posix_time::seconds(15))
3192  {
3193  UpdateAstronomy();
3194  fLastAstroCalc = now;
3195  }
3196 
3197  return fDimDNS.online() ? kStateRunning : kStateDimNetworkNA;
3198  }
3199 
3200 
3201 public:
3202  StateMachineSmartFACT(ostream &out=cout) : StateMachineDim(out, fIsServer?"SMART_FACT":""),
3203  fLastAstroCalc(boost::date_time::neg_infin),
3204  fPath("www/smartfact/data"),
3205  fControlScriptDepth(0),
3206  fMcpConfigurationState(DimState::kOffline),
3207  fMcpConfigurationMaxTime(0),
3208  fMcpConfigurationMaxEvents(0),
3209  fLastRunFinishedWithZeroEvents(false),
3210  fTngWeatherDustTime(Time::none),
3211  fBiasControlVoltageMed(0),
3212  fBiasControlCurrentMed(0),
3213  fBiasControlCurrentMax(0),
3214  fFscControlHumidityAvg(0),
3215  fDriveControlMoonDist(-1),
3216  fFadControlNumEvents(0),
3217  fFadControlDrsRuns(3),
3218  fFtmControlState(FTM::kFtmLocked),
3219  fRateScanDataId(0),
3220  fRateScanBoard(0),
3221  fFreeSpace(UINT64_MAX),
3222  // ---
3223  fDimMcp ("MCP"),
3224  fDimDataLogger ("DATA_LOGGER"),
3225  fDimDriveControl ("DRIVE_CONTROL"),
3226  fDimTimeCheck ("TIME_CHECK"),
3227  fDimMagicWeather ("MAGIC_WEATHER"),
3228  fDimMagicLidar ("MAGIC_LIDAR"),
3229  fDimTngWeather ("TNG_WEATHER"),
3230  fDimTemperature ("TEMPERATURE"),
3231  fDimFeedback ("FEEDBACK"),
3232  fDimBiasControl ("BIAS_CONTROL"),
3233  fDimFtmControl ("FTM_CONTROL"),
3234  fDimFadControl ("FAD_CONTROL"),
3235  fDimFscControl ("FSC_CONTROL"),
3236  fDimPfMiniControl ("PFMINI_CONTROL"),
3237  fDimGpsControl ("GPS_CONTROL"),
3238  fDimSqmControl ("SQM_CONTROL"),
3239  fDimAgilentControl24("AGILENT_CONTROL_24V"),
3240  fDimAgilentControl50("AGILENT_CONTROL_50V"),
3241  fDimAgilentControl80("AGILENT_CONTROL_80V"),
3242  fDimPwrControl ("PWR_CONTROL"),
3243  fDimLidControl ("LID_CONTROL"),
3244  fDimRateControl ("RATE_CONTROL"),
3245  fDimRateScan ("RATE_SCAN"),
3246  fDimChat ("CHAT"),
3247  fDimSkypeClient ("SKYPE_CLIENT")
3248  {
3249  fDimDNS.Subscribe(*this);
3250  fDimControl.Subscribe(*this);
3251  fDimMcp.Subscribe(*this);
3252  fDimDataLogger.Subscribe(*this);
3253  fDimDriveControl.Subscribe(*this);
3254  fDimTimeCheck.Subscribe(*this);
3255  fDimMagicWeather.Subscribe(*this);
3256  fDimMagicLidar.Subscribe(*this);
3257  fDimTngWeather.Subscribe(*this);
3258  fDimTemperature.Subscribe(*this);
3259  fDimFeedback.Subscribe(*this);
3260  fDimBiasControl.Subscribe(*this);
3261  fDimFtmControl.Subscribe(*this);
3262  fDimFadControl.Subscribe(*this);
3263  fDimFscControl.Subscribe(*this);
3264  fDimPfMiniControl.Subscribe(*this);
3265  fDimGpsControl.Subscribe(*this);
3266  fDimSqmControl.Subscribe(*this);
3267  fDimAgilentControl24.Subscribe(*this);
3268  fDimAgilentControl50.Subscribe(*this);
3269  fDimAgilentControl80.Subscribe(*this);
3270  fDimPwrControl.Subscribe(*this);
3271  fDimLidControl.Subscribe(*this);
3272  fDimRateControl.Subscribe(*this);
3273  fDimRateScan.Subscribe(*this);
3274  fDimChat.Subscribe(*this);
3275  fDimSkypeClient.Subscribe(*this);
3276 
3277  fDimFscControl.SetCallback(bind(&StateMachineSmartFACT::HandleFscControlStateChange, this, placeholders::_1));
3278  //fDimFtmControl.SetCallback(bind(&StateMachineSmartFACT::HandleFtmControlStateChange, this));
3279  fDimDriveControl.SetCallback(bind(&StateMachineSmartFACT::HandleDriveControlStateChange, this, placeholders::_1));
3280  fDimControl.SetCallback(bind(&StateMachineSmartFACT::HandleControlStateChange, this, placeholders::_1));
3281  fDimControl.AddCallback("dotest.dim", bind(&StateMachineSmartFACT::HandleDoTest, this, placeholders::_1));
3282 
3283  Subscribe("DIM_CONTROL/MESSAGE")
3284  (bind(&StateMachineSmartFACT::HandleDimControlMessage, this, placeholders::_1));
3285 
3286  Subscribe("MCP/CONFIGURATION")
3287  (bind(&StateMachineSmartFACT::HandleMcpConfiguration, this, placeholders::_1));
3288 
3289  Subscribe("DRIVE_CONTROL/POINTING_POSITION")
3290  (bind(&StateMachineSmartFACT::HandleDrivePointing, this, placeholders::_1));
3291  Subscribe("DRIVE_CONTROL/TRACKING_POSITION")
3292  (bind(&StateMachineSmartFACT::HandleDriveTracking, this, placeholders::_1));
3293  Subscribe("DRIVE_CONTROL/SOURCE_POSITION")
3294  (bind(&StateMachineSmartFACT::HandleDriveSource, this, placeholders::_1));
3295 
3296  Subscribe("FSC_CONTROL/TEMPERATURE")
3297  (bind(&StateMachineSmartFACT::HandleFscTemperature, this, placeholders::_1));
3298  Subscribe("FSC_CONTROL/HUMIDITY")
3299  (bind(&StateMachineSmartFACT::HandleFscHumidity, this, placeholders::_1));
3300  Subscribe("FSC_CONTROL/BIAS_TEMP")
3301  (bind(&StateMachineSmartFACT::HandleFscBiasTemp, this, placeholders::_1));
3302 
3303  Subscribe("PFMINI_CONTROL/DATA")
3304  (bind(&StateMachineSmartFACT::HandlePfMiniData, this, placeholders::_1));
3305 
3306  Subscribe("GPS_CONTROL/NEMA")
3307  (bind(&StateMachineSmartFACT::HandleGpsNema, this, placeholders::_1));
3308 
3309  Subscribe("SQM_CONTROL/DATA")
3310  (bind(&StateMachineSmartFACT::HandleSqmData, this, placeholders::_1));
3311 
3312  Subscribe("TEMPERATURE/DATA")
3313  (bind(&StateMachineSmartFACT::HandleTemperatureData, this, placeholders::_1));
3314 
3315  Subscribe("AGILENT_CONTROL_24V/DATA")
3316  (bind(&StateMachineSmartFACT::HandleAgilentData, this, placeholders::_1, "24"));
3317  Subscribe("AGILENT_CONTROL_50V/DATA")
3318  (bind(&StateMachineSmartFACT::HandleAgilentData, this, placeholders::_1, "50"));
3319  Subscribe("AGILENT_CONTROL_80V/DATA")
3320  (bind(&StateMachineSmartFACT::HandleAgilentData, this, placeholders::_1, "80"));
3321 
3322  Subscribe("MAGIC_WEATHER/DATA")
3323  (bind(&StateMachineSmartFACT::HandleMagicWeatherData, this, placeholders::_1));
3324  Subscribe("TNG_WEATHER/DUST")
3325  (bind(&StateMachineSmartFACT::HandleTngWeatherDust, this, placeholders::_1));
3326 
3327  Subscribe("FEEDBACK/CALIBRATED_CURRENTS")
3328  (bind(&StateMachineSmartFACT::HandleFeedbackCalibratedCurrents, this, placeholders::_1));
3329 
3330  Subscribe("BIAS_CONTROL/VOLTAGE")
3331  (bind(&StateMachineSmartFACT::HandleBiasVoltage, this, placeholders::_1));
3332  Subscribe("BIAS_CONTROL/CURRENT")
3333  (bind(&StateMachineSmartFACT::HandleBiasCurrent, this, placeholders::_1));
3334 
3335  Subscribe("FAD_CONTROL/CONNECTIONS")
3336  (bind(&StateMachineSmartFACT::HandleFadConnections, this, placeholders::_1));
3337  Subscribe("FAD_CONTROL/EVENTS")
3338  (bind(&StateMachineSmartFACT::HandleFadEvents, this, placeholders::_1));
3339  Subscribe("FAD_CONTROL/START_RUN")
3340  (bind(&StateMachineSmartFACT::HandleFadStartRun, this, placeholders::_1));
3341  Subscribe("FAD_CONTROL/DRS_RUNS")
3342  (bind(&StateMachineSmartFACT::HandleFadDrsRuns, this, placeholders::_1));
3343  Subscribe("FAD_CONTROL/EVENT_DATA")
3344  (bind(&StateMachineSmartFACT::HandleFadEventData, this, placeholders::_1));
3345  Subscribe("FAD_CONTROL/STATS")
3346  (bind(&StateMachineSmartFACT::HandleStats, this, placeholders::_1));
3347 
3348  Subscribe("DATA_LOGGER/STATS")
3349  (bind(&StateMachineSmartFACT::HandleStats, this, placeholders::_1));
3350 
3351  Subscribe("FTM_CONTROL/TRIGGER_RATES")
3352  (bind(&StateMachineSmartFACT::HandleFtmTriggerRates, this, placeholders::_1));
3353  Subscribe("FTM_CONTROL/STATIC_DATA")
3354  (bind(&StateMachineSmartFACT::HandleFtmStaticData, this, placeholders::_1));
3355  Subscribe("FTM_CONTROL/FTU_LIST")
3356  (bind(&StateMachineSmartFACT::HandleFtmFtuList, this, placeholders::_1));
3357 
3358  Subscribe("RATE_CONTROL/THRESHOLD")
3359  (bind(&StateMachineSmartFACT::HandleRateControlThreshold,this, placeholders::_1));
3360 
3361  Subscribe("RATE_SCAN/DATA")
3362  (bind(&StateMachineSmartFACT::HandleRateScanData, this, placeholders::_1));
3363 
3364  Subscribe("CHAT/MESSAGE")
3365  (bind(&StateMachineSmartFACT::HandleChatMsg, this, placeholders::_1));
3366 
3367 
3368  // =================================================================
3369 
3370  // State names
3371  AddStateName(kStateDimNetworkNA, "DimNetworkNotAvailable",
3372  "The Dim DNS is not reachable.");
3373 
3374  AddStateName(kStateRunning, "Running", "");
3375 
3376  // =================================================================
3377 
3378  AddEvent("PRINT")
3379  (bind(&StateMachineSmartFACT::Print, this))
3380  ("Print a list of the states of all connected servers.");
3381 
3382  }
3384  {
3385  if (!fPixelMap.Read(conf.Get<string>("pixel-map-file")))
3386  {
3387  Error("Reading mapping table from "+conf.Get<string>("pixel-map-file")+" failed.");
3388  return 1;
3389  }
3390 
3391  fPath = conf.Get<string>("path");
3392  fDatabase = conf.Get<string>("source-database");
3393 
3394  struct stat st;
3395  if (stat(fPath.c_str(), &st))
3396  {
3397  Error(fPath+" does not exist!");
3398  return 2;
3399  }
3400 
3401  if ((st.st_mode&S_IFDIR)==0)
3402  {
3403  Error(fPath+" not a directory!");
3404  return 3;
3405  }
3406 
3407  if ((st.st_mode&S_IWUSR)==0)
3408  {
3409  Error(fPath+" has no write permission!");
3410  return 4;
3411  }
3412 
3413  if ((st.st_mode&S_IXUSR)==0)
3414  {
3415  Error(fPath+" has no execute permission!");
3416  return 5;
3417  }
3418 
3419  ostringstream out;
3420  out << Time().JavaDate() << '\n';
3421 
3422  ofstream(fPath+"/error.data") << out.str();
3423 
3424  return -1;
3425  }
3426 };
3427 
3429 
3430 // ------------------------------------------------------------------------
3431 
3432 #include "Main.h"
3433 
3434 template<class T>
3436 {
3437  StateMachineSmartFACT::fIsServer = !conf.Get<bool>("client");
3438  return Main::execute<T, StateMachineSmartFACT>(conf);
3439 }
3440 
3442 {
3443  po::options_description control("Smart FACT");
3444  control.add_options()
3445  ("pixel-map-file", var<string>()->required(), "Pixel mapping file. Used here to get the default reference voltage")
3446  ("path", var<string>("www/smartfact/data"), "Output path for the data-files")
3447  ("source-database", var<string>(""), "Database link as in\n\tuser:password@server[:port]/database.")
3448  ("client", po_bool(false), "For a standalone client choose this option.")
3449  ;
3450 
3451  conf.AddOptions(control);
3452 }
3453 
3454 /*
3455  Extract usage clause(s) [if any] for SYNOPSIS.
3456  Translators: "Usage" and "or" here are patterns (regular expressions) which
3457  are used to match the usage synopsis in program output. An example from cp
3458  (GNU coreutils) which contains both strings:
3459  Usage: cp [OPTION]... [-T] SOURCE DEST
3460  or: cp [OPTION]... SOURCE... DIRECTORY
3461  or: cp [OPTION]... -t DIRECTORY SOURCE...
3462  */
3464 {
3465  cout <<
3466  "SmartFACT is a tool writing the files needed for the SmartFACT web interface.\n"
3467  "\n"
3468  "The default is that the program is started without user intercation. "
3469  "All actions are supposed to arrive as DimCommands. Using the -c "
3470  "option, a local shell can be initialized. With h or help a short "
3471  "help message about the usuage can be brought to the screen.\n"
3472  "\n"
3473  "Usage: smartfact [-c type] [OPTIONS]\n"
3474  " or: smartfact [OPTIONS]\n";
3475  cout << endl;
3476 }
3477 
3479 {
3480  Main::PrintHelp<StateMachineSmartFACT>();
3481 
3482  /* Additional help text which is printed after the configuration
3483  options goes here */
3484 
3485  /*
3486  cout << "bla bla bla" << endl << endl;
3487  cout << endl;
3488  cout << "Environment:" << endl;
3489  cout << "environment" << endl;
3490  cout << endl;
3491  cout << "Examples:" << endl;
3492  cout << "test exam" << endl;
3493  cout << endl;
3494  cout << "Files:" << endl;
3495  cout << "files" << endl;
3496  cout << endl;
3497  */
3498 }
3499 
3500 int main(int argc, const char* argv[])
3501 {
3502  Configuration conf(argv[0]);
3503  conf.SetPrintUsage(PrintUsage);
3505  SetupConfiguration(conf);
3506 
3507  if (!conf.DoParse(argc, argv, PrintHelp))
3508  return 127;
3509 
3510  if (!conf.Has("console"))
3511  return RunShell<LocalStream>(conf);
3512 
3513  if (conf.Get<int>("console")==0)
3514  return RunShell<LocalShell>(conf);
3515  else
3516  return RunShell<LocalConsole>(conf);
3517 
3518  return 0;
3519 }
string description
Definition: smartfact.cc:326
int HandleSqmData(const EventImp &d)
Definition: smartfact.cc:1992
char * ext
Definition: webServer.c:19
DimDescribedState fDimGpsControl
Definition: smartfact.cc:639
int state
Definition: moon.cc:32
string GetTempColor(float t)
Definition: smartfact.cc:2014
void WriteWeather(const EventImp &d, const string &name, int i, float min, float max)
Definition: smartfact.cc:972
DimDescribedState fDimPwrControl
Definition: smartfact.cc:644
Sun(const Time &t)
Definition: smartfact.cc:129
bool HasTrigger() const
Definition: HeadersFTM.h:415
DimDescribedState fDimPfMiniControl
Definition: smartfact.cc:638
int32_t fFtmControlTriggerRateTooLow
Definition: smartfact.cc:575
uint16_t fTriggerSeqPed
Definition: HeadersFTM.h:390
Moon()
Definition: smartfact.cc:331
string description
Definition: smartfact.cc:102
int HandlePfMiniData(const EventImp &d)
Definition: smartfact.cc:1926
virtual State description() const
Definition: DimState.h:84
deque< float > fDriveControlTrackingDevHist
Definition: smartfact.cc:567
DimDescribedState fDimMagicWeather
Definition: smartfact.cc:629
virtual void Subscribe(StateMachineImp &imp)
Definition: DimState.h:134
float period
Definition: HeadersSQM.h:92
Time fSunRise18
Definition: smartfact.cc:94
int HandleStats(const EventImp &d)
Definition: smartfact.cc:1785
Set color White.
Definition: WindowLog.h:23
uint32_t counts
Definition: HeadersSQM.h:21
float GetFloat() const
Definition: EventImp.h:97
static const string kYellow
Definition: smartfact.cc:75
uint64_t JavaDate() const
Definition: Time.h:111
A general base-class describing events issues in a state machine.
Definition: EventImp.h:11
int HandleFadConnections(const EventImp &d)
Definition: smartfact.cc:1475
const char * GetText() const
Definition: EventImp.h:88
deque< float > fFscControlTemperatureHist
Definition: smartfact.cc:553
deque< float > fTngWeatherDustHist
Definition: smartfact.cc:542
DimDescribedState fDimDriveControl
Definition: smartfact.cc:627
EquPosn GetLunarEquCoords(double jd, double precision=0)
Definition: nova.h:136
void SetupConfiguration(Configuration &conf)
Definition: Main.h:25
bool CheckDataSize(const EventImp &d, const char *name, size_t size, bool min=false)
Definition: smartfact.cc:669
float hdop
Definition: HeadersGPS.h:23
int HandleDrivePointing(const EventImp &d)
Definition: smartfact.cc:1077
int i
Definition: db_dim_client.c:21
int group() const
Definition: PixelMap.h:40
Set color Green.
Definition: WindowLog.h:18
bool HasPedestal() const
Definition: HeadersFTM.h:416
Adds some functionality to boost::posix_time::ptime for our needs.
Definition: Time.h:30
deque< float > fPfMiniHumidityHist
Definition: smartfact.cc:557
void SetPrintUsage(const std::function< void(void)> &func)
T Get(const std::string &var)
Set color Yellow.
Definition: WindowLog.h:19
uint32_t NightAsInt() const
Definition: Time.cc:397
int scriptdepth
Definition: DimState.h:301
int HandleFscHumidity(const EventImp &d)
Definition: smartfact.cc:1904
Set color Red.
Definition: WindowLog.h:17
bool visible
Definition: smartfact.cc:106
DimDescribedState fDimLidControl
Definition: smartfact.cc:645
deque< float > fBiasControlCurrentHist
Definition: smartfact.cc:552
void WriteHist(const EventImp &d, const string &fname, const T &t, double scale, double offset=0)
Definition: smartfact.cc:752
float fBoardRate[40]
Definition: HeadersFTM.h:589
float time
Definition: HeadersGPS.h:20
Header()
Definition: HeadersFTM.h:195
uint8_t fPing[40]
Address of FTU board.
Definition: HeadersFTM.h:682
STL namespace.
Definition: moon.cc:13
Time fSunSet12
Definition: smartfact.cc:98
int HandleGpsNema(const EventImp &d)
Definition: smartfact.cc:1960
int main(int argc, const char *argv[])
Definition: smartfact.cc:3500
uint16_t fMultiplicityPhysics
Intensity of LEDs (0-127)
Definition: HeadersFTM.h:397
double begin
const int32_t & state() const
Definition: DimState.h:80
int HandleFtmStaticData(const EventImp &d)
Definition: smartfact.cc:1609
uint16_t fWindowPhysics
Definition: HeadersFTM.h:400
int HandleRateControlThreshold(const EventImp &d)
Definition: smartfact.cc:2126
char id[4]
Definition: FITS.h:71
DimDescribedState fDimDataLogger
Definition: smartfact.cc:626
int HandleDriveControlStateChange(const EventImp &d)
Definition: smartfact.cc:1060
EventHist fMcpConfigurationHist
Definition: smartfact.cc:536
DimDescribedState fDimMagicLidar
Definition: smartfact.cc:630
std::pair< Time, int32_t > last
Definition: DimState.h:64
int RunShell(Configuration &conf)
Definition: smartfact.cc:3435
DimDescribedState fDimChat
Definition: smartfact.cc:648
double GetLunarDisk(double jd)
Definition: nova.h:121
State description() const
Definition: DimState.h:160
FTM and FTUs are being reconfigured.
Definition: HeadersFTM.h:22
float temp
Definition: HeadersPFmini.h:56
uint32_t fDeadTime
Definition: HeadersFTM.h:405
int Print() const
Definition: smartfact.cc:2198
void add(const string &s, const Time &t=Time())
Definition: smartfact.cc:469
DimDescribedState fDimAgilentControl80
Definition: smartfact.cc:643
uint16_t fDelayTimeMarker
Definition: HeadersFTM.h:404
uint16_t fPrescaling[40]
Definition: HeadersFTM.h:412
EventHist fControlAlarmHist
Definition: smartfact.cc:528
Time fSunRise12
Definition: smartfact.cc:93
int count() const
Definition: PixelMap.h:41
DimDescribedState fDimFeedback
Definition: smartfact.cc:633
std::string SecondsTo(const Time &=Time()) const
Definition: Time.cc:291
double zd
Definition: nova.h:30
void WriteBinaryVec(const Time &tm, const string &fname, const vector< T > &vec, double scale, double offset=0, const string &title="", const string &col="")
Definition: smartfact.cc:689
std::string version() const
Definition: DimState.h:236
int32_t fFadControlDrsStep
Definition: smartfact.cc:571
double JD() const
Definition: Time.h:87
bool fLastRunFinishedWithZeroEvents
Definition: smartfact.cc:537
DimDescribedState fDimMcp
Definition: smartfact.cc:625
DimDescribedState fDimSkypeClient
Definition: smartfact.cc:649
static bool fIsServer
Definition: smartfact.cc:442
deque< float > fFtmControlTriggerRateHist
Definition: smartfact.cc:574
int HandleDoTest(const EventImp &d)
Definition: smartfact.cc:2166
Time time
Definition: moon.cc:16
string Header(const EventImp &d)
Definition: smartfact.cc:610
DimDescribedState fDimAgilentControl24
Definition: smartfact.cc:641
int HandleRateScanData(const EventImp &d)
Definition: smartfact.cc:2075
vector< float > fBiasControlVoltageVec
Definition: smartfact.cc:545
DimDescribedState fDimTngWeather
Definition: smartfact.cc:631
int HandleDriveTracking(const EventImp &d)
Definition: smartfact.cc:1100
std::string shortmsg
Definition: DimState.h:300
int HandleMagicWeatherData(const EventImp &d)
Definition: smartfact.cc:990
int HandleDimControlMessage(const EventImp &d)
Definition: smartfact.cc:815
bool Has(const std::string &var)
Moon(const Time &t)
Definition: smartfact.cc:337
float lng
Definition: HeadersGPS.h:22
DimDescribedState fDimAgilentControl50
Definition: smartfact.cc:642
void AddOptions(const po::options_description &opt, bool visible=true)
Definition: Configuration.h:92
void SetupConfiguration(Configuration &conf)
Definition: smartfact.cc:3441
double zd
Definition: moon.cc:21
Time fTransit
Definition: moon.cc:29
int HandleFadEvents(const EventImp &d)
Definition: smartfact.cc:1432
float period
Definition: HeadersSQM.h:22
string Header(const Time &d)
Definition: smartfact.cc:603
uint64_t fRateScanDataId
Definition: smartfact.cc:585
int HandleBiasCurrent(const EventImp &d)
Definition: smartfact.cc:1336
string fDriveControlSourceName
Definition: smartfact.cc:564
void AddCallback(const std::string &script, const callback &cb)
Definition: DimState.h:303
int HandleTngWeatherDust(const EventImp &d)
Definition: smartfact.cc:1035
string fDriveControlPointingAz
Definition: smartfact.cc:563
uint16_t fMultiplicity[40]
Definition: HeadersFTM.h:411
static const string kBlue
Definition: smartfact.cc:78
DimDescribedState fDimTimeCheck
Definition: smartfact.cc:628
string GetStateHtml(const DimState &state, int green) const
Definition: smartfact.cc:2228
virtual Time GetTime() const
Definition: EventImp.h:57
int HandleFadEventData(const EventImp &d)
Definition: smartfact.cc:1734
static const string kWhite
Definition: smartfact.cc:74
bool HasExt1() const
Definition: HeadersFTM.h:420
void AddMcpConfigurationHist(const EventImp &d, const string &msg)
Definition: smartfact.cc:878
float mag
Definition: HeadersSQM.h:19
float height
Definition: HeadersGPS.h:24
Set color Blue.
Definition: WindowLog.h:20
virtual int GetQoS() const
Definition: EventImp.h:58
double az
Definition: moon.cc:22
Nova::RstTime Rst(double jd, double hrz=LN_SOLAR_STANDART_HORIZON)
Definition: smartfact.cc:108
void PrintUsage()
Definition: smartfact.cc:3463
int HandleFeedbackCalibratedCurrents(const EventImp &d)
Definition: smartfact.cc:1181
Pedestal trigger (artifical)
Definition: HeadersFTM.h:207
Time fSunSet06
Definition: smartfact.cc:97
Warning because the service this data corrsponds to might have been last updated longer ago than Local time
Definition: smartfact.txt:92
int HandleChatMsg(const EventImp &d)
Definition: smartfact.cc:2142
bool IsValid() const
Definition: Time.h:90
RstTime GetLunarRst(double jd, const LnLatPosn &obs=ORM())
Definition: nova.h:108
uint16_t qos
Definition: HeadersGPS.h:27
string fMcpConfigurationName
Definition: smartfact.cc:534
uint16_t fWindowCalib
Definition: HeadersFTM.h:401
bool isday
Definition: smartfact.cc:105
double end
int HandleFtmTriggerRates(const EventImp &d)
Definition: smartfact.cc:1542
float hum
Definition: HeadersPFmini.h:55
int state
Definition: smartfact.cc:101
Commandline parsing, resource file parsing and database access.
Definition: Configuration.h:9
EventElement(const Time &t, const string &s)
Definition: smartfact.cc:458
uint64_t GetJavaDate() const
Definition: EventImp.cc:303
Time fSet
Definition: moon.cc:30
Time fSunSet00
Definition: smartfact.cc:96
std::string Form(const char *fmt,...)
Definition: tools.cc:45
float lat
Definition: HeadersGPS.h:21
bool SetError(bool b, const string &err)
Definition: smartfact.cc:2262
std::string Scientific(uint64_t val)
Definition: tools.cc:148
uint16_t fTriggerInterval
Definition: HeadersFTM.h:386
int HandleFtmFtuList(const EventImp &d)
Definition: smartfact.cc:1697
int32_t fControlScriptDepth
Definition: smartfact.cc:529
static const string kGreen
Definition: smartfact.cc:77
RstTime GetSolarRst(double jd, const LnLatPosn &obs, double hrz=LN_SOLAR_STANDART_HORIZON)
Definition: nova.h:97
Statistics(const T &t, size_t offset_min=0, size_t offset_max=0)
Definition: smartfact.cc:775
int size
Definition: db_dim_server.c:17
int64_t fMcpConfigurationMaxEvents
Definition: smartfact.cc:533
DimDescribedState fDimRateScan
Definition: smartfact.cc:647
void PrintHelp()
Definition: smartfact.cc:3478
int HandleDriveSource(const EventImp &d)
Definition: smartfact.cc:1149
int HandleFscTemperature(const EventImp &d)
Definition: smartfact.cc:1799
float data[4 *1440]
int Execute()
Is called continously to execute actions in the current state.
Definition: smartfact.cc:2613
vector< uint32_t > fFadControlDrsRuns
Definition: smartfact.cc:572
void SetAudio(const string &name)
Definition: smartfact.cc:615
uint16_t fMultiplicityCalib
Definition: HeadersFTM.h:398
DimDescribedState fDimBiasControl
Definition: smartfact.cc:634
virtual void Subscribe(StateMachineImp &imp)
Definition: DimState.h:68
HrzPosn GetHrzFromEqu(const EquPosn &equ, const LnLatPosn &obs, double jd)
Definition: nova.h:75
bool HasClockConditioner() const
Definition: HeadersFTM.h:422
deque< float > fRateControlThreshold
Definition: smartfact.cc:583
static string Color(double angle)
Definition: smartfact.cc:425
Class for a state machine implementation within a DIM network.
int HandleFadStartRun(const EventImp &d)
Definition: smartfact.cc:1445
uint16_t fTriggerSeqLPint
Definition: HeadersFTM.h:388
bool HasLPext() const
Definition: HeadersFTM.h:417
double disk
Definition: moon.cc:24
A comment which is always printed.
Definition: MessageImp.h:22
float geosep
Definition: HeadersGPS.h:25
Time fSunRise00
Definition: smartfact.cc:91
uint16_t fDelayTrigger
Definition: HeadersFTM.h:403
uint16_t fThreshold[160]
Definition: HeadersFTM.h:410
Concerete implementation of an EventImp stroring name, format, data and time.
Definition: Event.h:6
uint16_t fTriggerSeqLPext
Definition: HeadersFTM.h:389
const boost::posix_time::time_duration deltat
Definition: smartfact.cc:463
deque< float > fPfMiniTemperatureHist
Definition: smartfact.cc:558
Error, something unexpected happened, but needs user intervention (i.e. it needs a signal to the user...
Definition: MessageImp.h:20
set< string > fErrorList
Definition: smartfact.cc:589
DimDescribedState fDimTemperature
Definition: smartfact.cc:632
double az
Definition: nova.h:31
int64_t fFadControlStartRun
Definition: smartfact.cc:570
Time fRise
Definition: moon.cc:28
void clear()
Definition: HeadersFTM.h:216
TT t
Definition: test_client.c:26
DimDescribedState fDimSqmControl
Definition: smartfact.cc:640
bool HasVeto() const
Definition: HeadersFTM.h:421
Return to feeserver c CVS log Up to[MAIN] dcscvs FeeServer feeserver src Wed FeeServer_v0 v0 dev
Definition: feeserver.c:5
bool online() const
Definition: DimState.h:82
Error()
Definition: HeadersFTM.h:197
function color(col)
Definition: color.js:31
if(extraDns) new Dns
int64_t fMcpConfigurationMaxTime
Definition: smartfact.cc:532
int HandleMcpConfiguration(const EventImp &d)
Definition: smartfact.cc:914
string GetDir(const double angle)
Definition: smartfact.cc:653
ln_rst_time RstTime
Definition: nova.h:13
int hw() const
Definition: PixelMap.h:39
int HandleControlStateChange(const EventImp &d)
Definition: smartfact.cc:835
double Angle(double r, double d) const
Definition: smartfact.cc:402
DimDescribedState fDimFtmControl
Definition: smartfact.cc:635
std::string file
Definition: DimState.h:299
Definition: HeadersFTM.h:14
string color
Definition: smartfact.cc:327
Time fSunRise06
Definition: smartfact.cc:92
std::string MinutesTo(const Time &=Time()) const
Definition: Time.cc:281
int HandleFscControlStateChange(const EventImp &d)
Definition: smartfact.cc:891
po::typed_value< bool > * po_bool(bool def=false)
Time time
Definition: smartfact.cc:88
static const string kRed
Definition: smartfact.cc:76
DimDescribedState fDimFadControl
Definition: smartfact.cc:636
deque< float > fTemperatureControlHist
Definition: smartfact.cc:560
EventHist(const boost::posix_time::time_duration &dt=boost::posix_time::hours(12), uint64_t mx=UINT64_MAX)
Definition: smartfact.cc:467
DimDescribedState fDimFscControl
Definition: smartfact.cc:637
int64_t fFadControlNumEvents
Definition: smartfact.cc:569
T Get(size_t offset=0) const
Definition: EventImp.h:66
bool IsActive(int i) const
Definition: HeadersFTM.h:703
std::string GetAsStr(const char *fmt="%Y-%m-%d %H:%M:%S") const
Definition: Time.cc:240
uint16_t count
Definition: HeadersGPS.h:26
string color
Definition: smartfact.cc:103
bool Read(const std::string &fname)
Definition: PixelMap.h:56
DimDescribedState fDimRateControl
Definition: smartfact.cc:646
bool DoParse(int argc, const char **argv, const std::function< void()> &func=std::function< void()>())
const T & Ref(size_t offset=0) const
Definition: EventImp.h:82
int HandleBiasVoltage(const EventImp &d)
Definition: smartfact.cc:1394
DimControl fDimControl
Definition: smartfact.cc:624
StateMachineSmartFACT(ostream &out=cout)
Definition: smartfact.cc:3202
Sun()
Definition: smartfact.cc:123
void WriteCam(const EventImp &d, const string &fname, const T &t, double scale, double offset=0)
Definition: smartfact.cc:758
Do not initialize the time.
Definition: Time.h:51
double PredictI(const Nova::SolarObjects &so, const Nova::EquPosn &srcEqu)
Definition: Prediction.h:10
Trigger output enabled, configuration ignored.
Definition: HeadersFTM.h:23
bool visible
Definition: moon.cc:26
void SetCallback(const callback &cb)
Definition: DimState.h:74
int HandleAgilentData(const EventImp &d, const string &ext)
Definition: smartfact.cc:2053
EventHist fControlMessageHist
Definition: smartfact.cc:527
float temp
Definition: HeadersSQM.h:23
Time fSunSet18
Definition: smartfact.cc:99
const T * Ptr(size_t offset=0) const
Definition: EventImp.h:74
Enable trigger decision after light pulse (CalibrationTrigger, LP1)
Definition: HeadersFTM.h:209
uint32_t freq
Definition: HeadersSQM.h:20
int HandleTemperatureData(const EventImp &d)
Definition: smartfact.cc:2025
Definition: smartfact.cc:85
int EvalOptions(Configuration &conf)
Definition: smartfact.cc:3383
bool HasLPint() const
Definition: HeadersFTM.h:418
int HandleFscBiasTemp(const EventImp &d)
Definition: smartfact.cc:1883
int HandleFadDrsRuns(const EventImp &d)
Definition: smartfact.cc:1458
int32_t fMcpConfigurationState
Definition: smartfact.cc:531
bool HasExt2() const
Definition: HeadersFTM.h:419
const PixelMapEntry & hv(int board, int channel) const
Definition: PixelMap.h:139
float fPatchRate[160]
Definition: HeadersFTM.h:590
virtual size_t GetSize() const
Definition: EventImp.h:55
void HandleControlMessageImp(const EventImp &d)
Definition: smartfact.cc:798