source: branches/FACT++_lidctrl_usb/src/smartfact.cc@ 19688

Last change on this file since 19688 was 18654, checked in by tbretz, 8 years ago
Changed lmits as diccussed in the telcon yesterday.
File size: 116.3 KB
Line 
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
48using namespace std;
49
50// ------------------------------------------------------------------------
51
52#include "DimDescriptionService.h"
53#include "DimState.h"
54
55// ------------------------------------------------------------------------
56/*
57template<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
72namespace 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
85class Sun
86{
87public:
88 Time time;
89
90 // This is always the time of the next...
91 Time fSunRise00;
92 Time fSunRise06;
93 Time fSunRise12;
94 Time fSunRise18;
95
96 Time fSunSet00;
97 Time fSunSet06;
98 Time fSunSet12;
99 Time fSunSet18;
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
122public:
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
307class Moon
308{
309public:
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
439class StateMachineSmartFACT : public StateMachineDim
440{
441public:
442 static bool fIsServer;
443
444private:
445 enum states_t
446 {
447 kStateDimNetworkNA = 1,
448 kStateRunning,
449 };
450
451 // ------------------------- History classes -----------------------
452
453 struct EventElement
454 {
455 Time time;
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
516 PixelMap fPixelMap;
517
518 string fDatabase;
519
520 Time fLastUpdate;
521 Time fLastAstroCalc;
522
523 string fPath;
524
525 // ----------------------------- Data storage -------------------------
526
527 EventHist fControlMessageHist;
528 EventHist fControlAlarmHist;
529 int32_t fControlScriptDepth;
530
531 int32_t fMcpConfigurationState; // For consistency
532 int64_t fMcpConfigurationMaxTime;
533 int64_t fMcpConfigurationMaxEvents;
534 string fMcpConfigurationName;
535 Time fMcpConfigurationRunStart;
536 EventHist fMcpConfigurationHist;
537 bool fLastRunFinishedWithZeroEvents;
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;
543 Time fTngWeatherDustTime;
544
545 vector<float> fBiasControlVoltageVec;
546
547 float fBiasControlPowerTot;
548 float fBiasControlVoltageMed;
549 float fBiasControlCurrentMed;
550 float fBiasControlCurrentMax;
551
552 deque<float> fBiasControlCurrentHist;
553 deque<float> fFscControlTemperatureHist;
554
555 float fFscControlHumidityAvg;
556
557 deque<float> fPfMiniHumidityHist;
558 deque<float> fPfMiniTemperatureHist;
559
560 deque<float> fTemperatureControlHist;
561
562 float fDriveControlPointingZd;
563 string fDriveControlPointingAz;
564 string fDriveControlSourceName;
565 float fDriveControlMoonDist;
566
567 deque<float> fDriveControlTrackingDevHist;
568
569 int64_t fFadControlNumEvents;
570 int64_t fFadControlStartRun;
571 int32_t fFadControlDrsStep;
572 vector<uint32_t> fFadControlDrsRuns;
573
574 deque<float> fFtmControlTriggerRateHist;
575 int32_t fFtmControlTriggerRateTooLow;
576 int fFtmControlState;
577
578 float fFtmPatchThresholdMed;
579 float fFtmBoardThresholdMed;
580
581 bool fFtmControlFtuOk;
582
583 deque<float> fRateControlThreshold;
584
585 uint64_t fRateScanDataId;
586 uint8_t fRateScanBoard;
587 deque<float> fRateScanDataHist[41];
588
589 set<string> fErrorList;
590 EventHist fErrorHist;
591 EventHist fChatHist;
592
593 uint64_t fFreeSpace;
594
595 Sun fSun;
596 Moon fMoon;
597
598 // --------------------------- File header ----------------------------
599
600 Time fAudioTime;
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
623 DimVersion fDimDNS;
624 DimControl fDimControl;
625 DimDescribedState fDimMcp;
626 DimDescribedState fDimDataLogger;
627 DimDescribedState fDimDriveControl;
628 DimDescribedState fDimTimeCheck;
629 DimDescribedState fDimMagicWeather;
630 DimDescribedState fDimMagicLidar;
631 DimDescribedState fDimTngWeather;
632 DimDescribedState fDimTemperature;
633 DimDescribedState fDimFeedback;
634 DimDescribedState fDimBiasControl;
635 DimDescribedState fDimFtmControl;
636 DimDescribedState fDimFadControl;
637 DimDescribedState fDimFscControl;
638 DimDescribedState fDimPfMiniControl;
639 DimDescribedState fDimGpsControl;
640 DimDescribedState fDimSqmControl;
641 DimDescribedState fDimAgilentControl24;
642 DimDescribedState fDimAgilentControl50;
643 DimDescribedState fDimAgilentControl80;
644 DimDescribedState fDimPwrControl;
645 DimDescribedState fDimLidControl;
646 DimDescribedState fDimRateControl;
647 DimDescribedState fDimRateScan;
648 DimDescribedState fDimChat;
649 DimDescribedState fDimSkypeClient;
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
798 void HandleControlMessageImp(const EventImp &d)
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
815 int HandleDimControlMessage(const EventImp &d)
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
835 int HandleControlStateChange(const EventImp &d)
836 {
837 if (d.GetSize()==0)
838 return StateMachineImp::kSM_KeepState;
839
840 if (fDimControl.scriptdepth>0)
841 return StateMachineImp::kSM_KeepState;
842
843 if (d.GetQoS()>=2)
844 return StateMachineImp::kSM_KeepState;
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
875 return StateMachineImp::kSM_KeepState;
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
891 int HandleFscControlStateChange(const EventImp &d)
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)
897 return StateMachineImp::kSM_KeepState;
898
899 if (last<FSC::State::kConnected && state==FSC::State::kConnected)
900 {
901 AddMcpConfigurationHist(d, "<B>FSC swiched on</B>");
902 //SetAudio("startup");
903 }
904
905 if (last==FSC::State::kConnected && state<FSC::State::kConnected)
906 {
907 AddMcpConfigurationHist(d, "<B>FSC swiched off</B>");
908 //SetAudio("shutdown");
909 }
910
911 return StateMachineImp::kSM_KeepState;
912 }
913
914 int HandleMcpConfiguration(const EventImp &d)
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
948 if (d.GetQoS()==MCP::State::kTakingData)
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
990 int HandleMagicWeatherData(const EventImp &d)
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
1035 int HandleTngWeatherDust(const EventImp &d)
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
1060 int HandleDriveControlStateChange(const EventImp &d)
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)
1066 return StateMachineImp::kSM_KeepState;
1067
1068 if (last<Drive::State::kInitialized && state>=Drive::State::kInitialized)
1069 AddMcpConfigurationHist(d, "Drive ready");
1070
1071 if (last>=Drive::State::kInitialized && state<Drive::State::kInitialized)
1072 AddMcpConfigurationHist(d, "Drive not ready");
1073
1074 return StateMachineImp::kSM_KeepState;
1075 }
1076
1077 int HandleDrivePointing(const EventImp &d)
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
1100 int HandleDriveTracking(const EventImp &d)
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
1149 int HandleDriveSource(const EventImp &d)
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
1181 int HandleFeedbackCalibratedCurrents(const EventImp &d)
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
1336 int HandleBiasCurrent(const EventImp &d)
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
1394 int HandleBiasVoltage(const EventImp &d)
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
1432 int HandleFadEvents(const EventImp &d)
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
1445 int HandleFadStartRun(const EventImp &d)
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
1458 int HandleFadDrsRuns(const EventImp &d)
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
1475 int HandleFadConnections(const EventImp &d)
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
1542 int HandleFtmTriggerRates(const EventImp &d)
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
1609 int HandleFtmStaticData(const EventImp &d)
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
1697 int HandleFtmFtuList(const EventImp &d)
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
1734 int HandleFadEventData(const EventImp &d)
1735 {
1736 if (!CheckDataSize(d, "FadControl:EventData", 23048))
1737 return GetCurrentState();
1738
1739 //const uint32_t run = d.GetUint();
1740 //const uint32_t evt = d.GetUint(4);
1741
1742 const float *dat = d.Ptr<float>(8+1440*sizeof(float)*2);
1743
1744 /*
1745 vector<float> max(320, 0);
1746 for (int i=0; i<1440; i++)
1747 {
1748 if (i%9==8)
1749 continue;
1750
1751 const int idx = (fPixelMap.hw(i).hw()/9)*2+fPixelMap.hw(i).group();
1752 const double v = dat[i]/1000;
1753 //if (v>max[idx])
1754 // max[idx]=v;
1755
1756 max[idx] += v/4;
1757 } */
1758
1759 vector<float> val(1440);
1760 for (int i=0; i<1440; i++)
1761 val[i] = dat[i%9==8 ? i-2 : i]/1000;
1762
1763 vector<float> sorted(val);
1764 nth_element(sorted.begin(), sorted.begin()+3, sorted.end(),
1765 std::greater<float>());
1766
1767 const uint32_t trig = d.GetQoS() & FAD::EventHeader::kLPext;
1768
1769 const float min = fFadControlDrsRuns[0]==0 ? -1 : 0;
1770
1771 float scale = 2;
1772 if (trig&FAD::EventHeader::kLPext)
1773 scale = 1;
1774 if (trig&FAD::EventHeader::kPedestal)
1775 scale = 0.25;
1776 if (trig==0)
1777 scale = max(0.25f, sorted[3]);
1778
1779 // assume it is drs-gain
1780 //if ((trig&FAD::EventHeader::kPedestal) && fFadControlDrsRuns[0]>0 && fFadControlDrsRuns[1]==0)
1781 // min = 0.75;
1782
1783 WriteCam(d, "cam-fadcontrol-eventdata", val, scale, min);
1784
1785 return GetCurrentState();
1786 }
1787
1788 int HandleStats(const EventImp &d)
1789 {
1790 if (!CheckDataSize(d, "Stats", 4*8))
1791 {
1792 fFreeSpace = UINT64_MAX;
1793 return GetCurrentState();
1794 }
1795
1796 const DimWriteStatistics::Stats &s = d.Ref<DimWriteStatistics::Stats>();
1797 fFreeSpace = s.freeSpace;
1798
1799 return GetCurrentState();
1800 }
1801
1802 int HandleFscTemperature(const EventImp &d)
1803 {
1804 if (!CheckDataSize(d, "FscControl:Temperature", 240))
1805 return GetCurrentState();
1806
1807 const float *ptr = d.Ptr<float>(4);
1808
1809 double avg = 0;
1810 double rms = 0;
1811 double min = 99;
1812 double max = -99;
1813
1814 int num = 0;
1815 for (const float *t=ptr; t<ptr+31; t++)
1816 {
1817 if (*t==0)
1818 continue;
1819
1820 if (*t>max)
1821 max = *t;
1822
1823 if (*t<min)
1824 min = *t;
1825
1826 avg += *t;
1827 rms += *t * *t;
1828
1829 num++;
1830 }
1831
1832 avg /= num;
1833 rms /= num;
1834 rms += avg*avg;
1835 rms = rms<0 ? 0 : sqrt(rms);
1836
1837 // Clean broken reports
1838 static double pre_rms1 = 1.5;
1839 static double pre_rms2 = 0;
1840
1841 const double cut = pre_rms1 + 0.1;
1842
1843 const bool reject = rms>cut && pre_rms2<cut;
1844
1845 pre_rms2 = pre_rms1;
1846 pre_rms1 = rms;
1847
1848 if (reject)
1849 return GetCurrentState();
1850
1851
1852 if (!fMagicWeatherHist[kTemp].empty())
1853 {
1854 fFscControlTemperatureHist.push_back(avg-fMagicWeatherHist[kTemp].back());
1855 if (fFscControlTemperatureHist.size()>300)
1856 fFscControlTemperatureHist.pop_front();
1857 }
1858
1859 const Statistics stat(fFscControlTemperatureHist);
1860
1861 ostringstream out;
1862 out << setprecision(3);
1863 out << d.GetJavaDate() << '\n';
1864 out << HTML::kWhite << '\t' << fFscControlHumidityAvg << '\n';
1865 out << HTML::kWhite << '\t' << stat.min << '\n';
1866 out << HTML::kWhite << '\t' << stat.avg << '\n';
1867 out << HTML::kWhite << '\t' << stat.max << '\n';
1868
1869 ofstream(fPath+"/fsc.data") << out.str();
1870
1871 WriteHist(d, "hist-fsccontrol-temperature",
1872 fFscControlTemperatureHist, 10);
1873
1874 out.str("");
1875 out << setprecision(3);
1876 out << d.GetJavaDate() << '\n';
1877 out << HTML::kWhite << '\t' << max << '\n';
1878 out << HTML::kWhite << '\t' << avg << '\n';
1879 out << HTML::kWhite << '\t' << min << '\n';
1880
1881 ofstream(fPath+"/camtemp.data") << out.str();
1882
1883 return GetCurrentState();
1884 }
1885
1886 int HandleFscBiasTemp(const EventImp &d)
1887 {
1888 if (!CheckDataSize(d, "FscControl:BiasTemp", 323*4))
1889 return GetCurrentState();
1890
1891 const float *ptr = d.Ptr<float>(4);
1892 const float avg = d.Get<float>(321*4);
1893 //const float rms = d.Get<float>(322*4);
1894
1895 vector<double> tout(320);
1896 for (int i=0; i<320; i++)
1897 {
1898 const int idx = (fPixelMap.hv(i).hw()/9)*2+fPixelMap.hv(i).group();
1899 tout[idx] = ptr[i];
1900 }
1901
1902 WriteCam(d, "cam-fsccontrol-temperature", tout, 3, avg-1.75);
1903
1904 return GetCurrentState();
1905 }
1906
1907 int HandleFscHumidity(const EventImp &d)
1908 {
1909 if (!CheckDataSize(d, "FscControl:Humidity", 5*4))
1910 return GetCurrentState();
1911
1912 const float *ptr = d.Ptr<float>(4);
1913
1914 double avg =0;
1915 int num = 0;
1916
1917 for (const float *t=ptr; t<ptr+4; t++)
1918 if (*t>0 && *t<=100 && t!=ptr+2 /*excl broken sensor*/)
1919 {
1920 avg += *t;
1921 num++;
1922 }
1923
1924 fFscControlHumidityAvg = num>0 ? avg/num : 0;
1925
1926 return GetCurrentState();
1927 }
1928
1929 int HandlePfMiniData(const EventImp &d)
1930 {
1931 if (!CheckDataSize(d, "PfMini:Data", sizeof(PFmini::Data)))
1932 return GetCurrentState();
1933
1934 const PFmini::Data &data = d.Ref<PFmini::Data>();
1935
1936 ostringstream out;
1937
1938 out << fixed << setprecision(1);
1939 out << d.GetJavaDate() << '\n';
1940
1941 out << HTML::kGreen << '\t' << data.temp << '\n';
1942 out << HTML::kGreen << '\t' << data.hum << '\n';
1943
1944 ofstream(fPath+"/pfmini.data") << out.str();
1945
1946 fPfMiniTemperatureHist.push_back(data.temp);
1947 if (fPfMiniTemperatureHist.size()>60*4) // 1h
1948 fPfMiniTemperatureHist.pop_front();
1949
1950 fPfMiniHumidityHist.push_back(data.hum);
1951 if (fPfMiniHumidityHist.size()>60*4) // 1h
1952 fPfMiniHumidityHist.pop_front();
1953
1954 WriteHist(d, "hist-pfmini-temp",
1955 fPfMiniTemperatureHist, 45, 0);
1956
1957 WriteHist(d, "hist-pfmini-hum",
1958 fPfMiniHumidityHist, 100, 0);
1959
1960 return GetCurrentState();
1961 }
1962
1963 int HandleGpsNema(const EventImp &d)
1964 {
1965 if (!CheckDataSize(d, "GpsControl:Nema", sizeof(GPS::NEMA)))
1966 return GetCurrentState();
1967
1968 const GPS::NEMA &nema = d.Ref<GPS::NEMA>();
1969
1970 ostringstream out;
1971
1972 out << fixed;
1973 out << d.GetJavaDate() << '\n';
1974
1975 switch (nema.qos)
1976 {
1977 case 1: out << HTML::kGreen << "\tGPS fix [1]\n"; break;
1978 case 2: out << HTML::kGreen << "\tDifferential fix [2]\n"; break;
1979 default: out << HTML::kRed << "\tinvalid [" << nema.qos << "]\n"; break;
1980 }
1981
1982 out << HTML::kWhite << '\t' << nema.count << '\n';
1983 out << HTML::kWhite << '\t' << Time(floor(Time().Mjd())+nema.time).GetAsStr("%H:%M:%S") << '\n';
1984 out << HTML::kWhite << '\t' << setprecision(4) << nema.lat << '\n';
1985 out << HTML::kWhite << '\t' << setprecision(4) << nema.lng << '\n';
1986 out << HTML::kWhite << '\t' << setprecision(1) << nema.height << "\n";
1987 out << HTML::kWhite << '\t' << setprecision(1) << nema.hdop << "\n";
1988 out << HTML::kWhite << '\t' << setprecision(1) << nema.geosep << "\n";
1989
1990 ofstream(fPath+"/gps.data") << out.str();
1991
1992 return GetCurrentState();
1993 }
1994
1995 int HandleSqmData(const EventImp &d)
1996 {
1997 if (!CheckDataSize(d, "SqmControl:Data", sizeof(SQM::Data)))
1998 return GetCurrentState();
1999
2000 const SQM::Data &data = d.Ref<SQM::Data>();
2001
2002 ostringstream out;
2003
2004 out << fixed;
2005 out << d.GetJavaDate() << '\n';
2006 out << HTML::kWhite << '\t' << setprecision(2) << data.mag << '\n';
2007 out << HTML::kWhite << '\t' << data.freq << '\n';
2008 out << HTML::kWhite << '\t' << data.counts << '\n';
2009 out << HTML::kWhite << '\t' << setprecision(3) << data.period << '\n';
2010 out << HTML::kWhite << '\t' << setprecision(1) << data.temp << "\n";
2011
2012 ofstream(fPath+"/sqm.data") << out.str();
2013
2014 return GetCurrentState();
2015 }
2016
2017 string GetTempColor(float t)
2018 {
2019 if (t>25 && t<30)
2020 return HTML::kGreen;
2021
2022 if (t<20 || t>35)
2023 return HTML::kRed;
2024
2025 return HTML::kYellow;
2026 }
2027
2028 int HandleTemperatureData(const EventImp &d)
2029 {
2030 if (!CheckDataSize(d, "Temperature:Data", 3*sizeof(float)))
2031 return GetCurrentState();
2032
2033 const float *temp = d.Ptr<float>();
2034
2035 ostringstream out;
2036
2037 out << fixed << setprecision(1);
2038 out << d.GetJavaDate() << '\n';
2039
2040 out << GetTempColor(temp[1]) << '\t' << temp[1] << '\n';
2041 out << GetTempColor(temp[0]) << '\t' << temp[0] << '\n';
2042 out << GetTempColor(temp[2]) << '\t' << temp[2] << '\n';
2043
2044 ofstream(fPath+"/temperature.data") << out.str();
2045
2046 fTemperatureControlHist.push_back(temp[0]);
2047 if (fTemperatureControlHist.size()>60) // 1h
2048 fTemperatureControlHist.pop_front();
2049
2050 WriteHist(d, "hist-temperaturecontrol",
2051 fTemperatureControlHist, 45, 0);
2052
2053 return GetCurrentState();
2054 }
2055
2056 int HandleAgilentData(const EventImp &d, const string &ext)
2057 {
2058 if (!CheckDataSize(d, ("Agilent"+ext+":Data").c_str(), 4*sizeof(float)))
2059 return GetCurrentState();
2060
2061 const float *data = d.Ptr<float>();
2062
2063 ostringstream out;
2064
2065 out << fixed << setprecision(1);
2066 out << d.GetJavaDate() << '\n';
2067
2068 out << HTML::kWhite << '\t' << data[0] << '\n';
2069 out << HTML::kWhite << '\t' << data[1] << '\n';
2070 out << HTML::kWhite << '\t' << data[2] << '\n';
2071 out << HTML::kWhite << '\t' << data[3] << '\n';
2072
2073 ofstream(fPath+"/agilent"+ext+".data") << out.str();
2074
2075 return GetCurrentState();
2076 }
2077
2078 int HandleRateScanData(const EventImp &d)
2079 {
2080 if (!CheckDataSize(d, "RateScan:Data", 824))
2081 return GetCurrentState();
2082
2083 const uint64_t id = d.Get<uint64_t>();
2084 const float *rate = d.Ptr<float>(20);
2085
2086 if (fRateScanDataId!=id)
2087 {
2088 for (int i=0; i<41; i++)
2089 fRateScanDataHist[i].clear();
2090 fRateScanDataId = id;
2091 }
2092 fRateScanDataHist[0].push_back(log10(rate[0]));
2093
2094 double max = 0;
2095 for (int i=1; i<41; i++)
2096 {
2097 fRateScanDataHist[i].push_back(log10(rate[i]));
2098 if (rate[i]>max)
2099 max = rate[i];
2100 }
2101
2102 // Cycle by time!
2103 fRateScanBoard ++;
2104 fRateScanBoard %= 40;
2105
2106 WriteHist(d, "hist-ratescan", fRateScanDataHist[0], 10, -2);
2107 WriteCam(d, "cam-ratescan-board", fRateScanDataHist[fRateScanBoard+1], 10, -4);
2108
2109 ostringstream out;
2110 out << setprecision(3);
2111 out << d.GetJavaDate() << '\n';
2112 out << HTML::kWhite << '\t' << fFtmBoardThresholdMed << '\n';
2113 out << HTML::kWhite << '\t' << fFtmPatchThresholdMed << '\n';
2114 out << HTML::kWhite << '\t' << floor(pow(10, fRateScanDataHist[0].back())+.5) << '\n';
2115 out << HTML::kWhite << '\t' << floor(max+.5) << '\n';
2116
2117 ofstream(fPath+"/ratescan.data") << out.str();
2118
2119 out.str("");
2120 out << d.GetJavaDate() << '\n';
2121 out << HTML::kWhite << '\t' << int(fRateScanBoard) << '\n';
2122 out << HTML::kWhite << '\t' << pow(10, fRateScanDataHist[fRateScanBoard+1].back()) << '\n';
2123
2124 ofstream(fPath+"/ratescan_board.data") << out.str();
2125
2126 return GetCurrentState();
2127 }
2128
2129 int HandleRateControlThreshold(const EventImp &d)
2130 {
2131 if (!CheckDataSize(d, "RateControl:Threshold", 18))
2132 return GetCurrentState();
2133
2134 const uint16_t th = d.Get<uint16_t>();
2135
2136 fRateControlThreshold.push_back(th);
2137 if (fRateControlThreshold.size()>300)
2138 fRateControlThreshold.pop_front();
2139
2140 WriteHist(d, "hist-ratecontrol-threshold", fRateControlThreshold, 1000);
2141
2142 return GetCurrentState();
2143 }
2144
2145 int HandleChatMsg(const EventImp &d)
2146 {
2147 if (d.GetSize()==0 || d.GetQoS()!=MessageImp::kComment)
2148 return GetCurrentState();
2149
2150 if (Time()<d.GetTime()+boost::posix_time::minutes(1))
2151 SetAudio("message");
2152
2153 fChatHist.add(d.GetText(), d.GetTime());
2154
2155 ostringstream out;
2156 out << setprecision(3);
2157 out << Header(d) << '\n';
2158 out << HTML::kWhite << '\t';
2159 out << "<->" << fChatHist.rget() << "</->";
2160 out << '\n';
2161
2162 ofstream(fPath+"/chat.data") << out.str();
2163
2164 return GetCurrentState();
2165 }
2166
2167 // -------------------------------------------------------------------
2168
2169 int HandleDoTest(const EventImp &d)
2170 {
2171 ostringstream out;
2172 out << d.GetJavaDate() << '\n';
2173
2174 switch (d.GetQoS())
2175 {
2176 case -3: out << HTML::kWhite << "\tNot running\n"; break;
2177 case -2: out << HTML::kBlue << "\tLoading\n"; break;
2178 case -1: out << HTML::kBlue << "\tStarted\n"; break;
2179 default: out << HTML::kGreen << "\tRunning [" << d.GetQoS() << "]\n"; break;
2180 }
2181
2182 ofstream(fPath+"/dotest.data") << out.str();
2183
2184 return StateMachineImp::kSM_KeepState;
2185 }
2186
2187 // -------------------------------------------------------------------
2188
2189 /*
2190 bool CheckEventSize(size_t has, const char *name, size_t size)
2191 {
2192 if (has==size)
2193 return true;
2194
2195 ostringstream msg;
2196 msg << name << " - Received event has " << has << " bytes, but expected " << size << ".";
2197 Fatal(msg);
2198 return false;
2199 }*/
2200
2201 int Print() const
2202 {
2203 Out() << fDimDNS << endl;
2204 Out() << fDimMcp << endl;
2205 Out() << fDimControl << endl;
2206 Out() << fDimDataLogger << endl;
2207 Out() << fDimDriveControl << endl;
2208 Out() << fDimTimeCheck << endl;
2209 Out() << fDimFadControl << endl;
2210 Out() << fDimFtmControl << endl;
2211 Out() << fDimBiasControl << endl;
2212 Out() << fDimFeedback << endl;
2213 Out() << fDimRateControl << endl;
2214 Out() << fDimFscControl << endl;
2215 Out() << fDimAgilentControl24 << endl;
2216 Out() << fDimAgilentControl50 << endl;
2217 Out() << fDimAgilentControl80 << endl;
2218 Out() << fDimPwrControl << endl;
2219 Out() << fDimLidControl << endl;
2220 Out() << fDimMagicWeather << endl;
2221 Out() << fDimTngWeather << endl;
2222 Out() << fDimMagicLidar << endl;
2223 Out() << fDimTemperature << endl;
2224 Out() << fDimRateScan << endl;
2225 Out() << fDimChat << endl;
2226 Out() << fDimSkypeClient << endl;
2227
2228 return GetCurrentState();
2229 }
2230
2231 string GetStateHtml(const DimState &state, int green) const
2232 {
2233 if (!state.online())
2234 return HTML::kWhite+"\t&mdash;\n";
2235
2236 if (&state==&fDimControl)
2237 return HTML::kGreen +'\t'+(state.state()==0?"Idle":fDimControl.shortmsg)+'\n';
2238
2239 const State rc = state.description();
2240
2241 // Sate not found in list, server online (-3: offline; -2: not found)
2242 if (rc.index==-2)
2243 {
2244 ostringstream out;
2245 out << HTML::kWhite << '\t' << state.state() << '\n';
2246 return out.str();
2247 }
2248
2249 //ostringstream msg;
2250 //msg << HTML::kWhite << '\t' << rc.name << " [" << rc.index << "]\n";
2251 //return msg.str();
2252
2253 if (rc.index<0)
2254 return HTML::kWhite + "\t&mdash;\n";
2255
2256 string col = HTML::kGreen;
2257 if (rc.index<green)
2258 col = HTML::kYellow;
2259 if (rc.index>0xff)
2260 col = HTML::kRed;
2261
2262 return col + '\t' + rc.name + '\n';
2263 }
2264
2265 bool SetError(bool b, const string &err)
2266 {
2267 if (!b)
2268 {
2269 fErrorList.erase(err);
2270 return 0;
2271 }
2272
2273 const bool isnew = fErrorList.insert(err).second;
2274 if (isnew)
2275 fErrorHist.add(err);
2276
2277 return isnew;
2278 }
2279
2280#ifdef HAVE_NOVA
2281
2282 //vector<pair<Nova::EquPosn, double>> fMoonCoords;
2283
2284 vector<Nova::SolarObjects> fCoordinates;
2285
2286 void CalcCoordinates(double jd)
2287 {
2288 jd = floor(jd);
2289
2290 fCoordinates.clear();
2291 for (double h=0; h<1; h+=1./(24*12))
2292 fCoordinates.emplace_back(jd+h);
2293 }
2294
2295 pair<vector<float>, pair<Time, float>> GetVisibility(Nova::EquPosn *src=0)
2296 {
2297 const double sunset = fSun.fSunSet12.JD()-1;
2298 const double sunrise = fSun.fSunRise12.JD();
2299
2300 Nova::EquPosn moon;
2301 Nova::EquPosn *pos = src ? src : &moon;
2302
2303 double max = 0;
2304 double maxjd = 0;
2305
2306 int cnt = 0;
2307
2308 vector<float> alt;
2309 for (auto it=fCoordinates.begin(); it!=fCoordinates.end(); it++)
2310 {
2311 if (src==0)
2312 moon = it->fMoonEqu;
2313
2314 const Nova::HrzPosn hrz = Nova::GetHrzFromEqu(*pos, it->fJD);
2315
2316 if (it->fJD>sunset && it->fJD<sunrise)
2317 alt.push_back(hrz.alt);
2318
2319 if (hrz.alt>max)
2320 {
2321 max = hrz.alt;
2322 maxjd = it->fJD;
2323 }
2324
2325 if (it->fJD>sunset && it->fJD<sunrise && hrz.alt>15)
2326 cnt++;
2327 }
2328
2329 if (max<=15 || cnt==0)
2330 return make_pair(vector<float>(), make_pair(Time(), 0));
2331
2332 return make_pair(alt, make_pair(maxjd, maxjd>sunset&&maxjd<sunrise?max:0));
2333 }
2334
2335 pair<vector<float>, pair<Time, float>> GetLightCondition(const Nova::EquPosn &src_pos)
2336 {
2337 const double sunset = fSun.fSunSet12.JD()-1;
2338 const double sunrise = fSun.fSunRise12.JD();
2339
2340 double max = -1;
2341 double maxjd = 0;
2342
2343 int cnt = 0;
2344
2345 vector<float> vec;
2346 for (auto it=fCoordinates.begin(); it!=fCoordinates.end(); it++)
2347 {
2348 double cur = -1;
2349
2350 if (it->fJD>sunset && it->fJD<sunrise)
2351 {
2352 cur = FACT::PredictI(*it, src_pos);
2353 vec.push_back(cur);
2354 }
2355
2356 if (cur>max)
2357 {
2358 max = cur;
2359 maxjd = it->fJD;
2360 }
2361
2362 if (it->fJD>sunset && it->fJD<sunrise && cur>0)
2363 cnt++;
2364 }
2365
2366 if (max<=0 || cnt==0)
2367 return make_pair(vector<float>(), make_pair(Time(), 0));
2368
2369 return make_pair(vec, make_pair(maxjd, maxjd>sunset&&maxjd<sunrise?max:-1));
2370 }
2371#endif
2372
2373 void UpdateAstronomy()
2374 {
2375 Time now;
2376
2377 CalcCoordinates(now.JD());
2378
2379 fSun = Sun (now);
2380 fMoon = Moon(now);
2381
2382 vector<string> color(8, HTML::kWhite);
2383 color[fSun.state] = HTML::kBlue;
2384
2385 ostringstream out;
2386 out << setprecision(3);
2387 out << now.JavaDate() << '\n';
2388 out << color[4] << '\t' << fSun.fSunRise18.GetAsStr("%H:%M") << '\n';
2389 out << color[5] << '\t' << fSun.fSunRise12.GetAsStr("%H:%M") << '\n';
2390 out << color[6] << '\t' << fSun.fSunRise06.GetAsStr("%H:%M") << '\n';
2391 out << color[7] << '\t' << fSun.fSunRise00.GetAsStr("%H:%M") << '\n';
2392
2393 out << color[0] << '\t' << fSun.fSunSet00.GetAsStr("%H:%M") << '\n';
2394 out << color[1] << '\t' << fSun.fSunSet06.GetAsStr("%H:%M") << '\n';
2395 out << color[2] << '\t' << fSun.fSunSet12.GetAsStr("%H:%M") << '\n';
2396 out << color[3] << '\t' << fSun.fSunSet18.GetAsStr("%H:%M") << '\n';
2397
2398 ofstream(fPath+"/sun.data") << out.str();
2399
2400 color.assign(3, HTML::kWhite);
2401 color[fMoon.state%3] = HTML::kBlue;
2402
2403 out.str("");
2404 out << now.JavaDate() << '\n';
2405
2406 out << color[0] << '\t' << fMoon.fRise.GetAsStr("%H:%M") << '\n';
2407 out << color[1] << '\t' << fMoon.fTransit.GetAsStr("%H:%M") << '\n';
2408 out << color[2] << '\t' << fMoon.fSet.GetAsStr("%H:%M") << '\n';
2409
2410 out << (fSun.isday?HTML::kWhite:fMoon.color) << '\t' << fMoon.description << '\n';
2411
2412 if (!fMoon.visible)
2413 out << HTML::kWhite << "\t&mdash;\t\n";
2414 else
2415 {
2416 string col = HTML::kWhite;
2417 if (!fSun.isday)
2418 {
2419 col = HTML::kGreen;
2420 if (fMoon.zd>25)
2421 col = HTML::kYellow;
2422 if (fMoon.zd>45 && fMoon.zd<80)
2423 col = HTML::kRed;
2424 if (fMoon.zd>=80)
2425 col = HTML::kRed;
2426 }
2427 out << col << '\t' << fMoon.zd << '\t' << GetDir(fMoon.az) << '\n';
2428 }
2429
2430 ostringstream out2, out3, out4;
2431 out2 << setprecision(3);
2432 out2 << now.JavaDate() << '\n';
2433 out3 << now.JavaDate() << '\n';
2434 out4 << now.JavaDate() << '\n';
2435
2436 struct Entry
2437 {
2438 string name;
2439 float value;
2440 int color;
2441 Entry(const string &n, float v, int c) : name(n), value(v), color(c%8) { }
2442
2443 const string &Col() const
2444 {
2445 // If this list is updatd the number count in the constructor needs
2446 // to be updated, too
2447 static const string hcol[] = { "888", "8cf", "c8f", "bbb", "8fc", "cf8", "f8c", "fc8" };
2448 return hcol[color];
2449 }
2450
2451 vector<float> GetColor(double scale, double offset=0) const
2452 {
2453 vector<float> rc(3);
2454 rc[0] = double(Col()[0])*scale/126+offset;
2455 rc[1] = double(Col()[1])*scale/126+offset;
2456 rc[2] = double(Col()[2])*scale/126+offset;
2457 return rc;
2458 }
2459 };
2460
2461 multimap<Time, Entry> culmination;
2462 multimap<Time, Entry> lightcond;
2463 vector<vector<float>> alt;
2464 vector<vector<float>> cur;
2465
2466#ifdef HAVE_NOVA
2467 int ccol = 0;
2468 int lcol = 0;
2469
2470 /*const*/ pair<vector<float>, pair<Time, float>> vism = GetVisibility();
2471 if (!vism.first.empty())
2472 {
2473 const Entry entry("Moon", vism.second.second, ccol);
2474 culmination.insert(make_pair(vism.second.first, entry));
2475 const vector<float> col = entry.GetColor(75, 15);
2476 vism.first.insert(vism.first.begin(), col.begin(), col.end());
2477 alt.push_back(vism.first);
2478
2479 ccol++;
2480 }
2481#endif
2482
2483#ifdef HAVE_SQL
2484 try
2485 {
2486 const mysqlpp::StoreQueryResult res =
2487 Database(fDatabase).query("SELECT fSourceName, fRightAscension, fDeclination FROM Source WHERE fSourceTypeKEY=1").store();
2488
2489 out << HTML::kWhite << '\t';
2490 out2 << HTML::kWhite << '\t';
2491 out3 << HTML::kWhite << '\t';
2492 out4 << HTML::kWhite << '\t';
2493
2494 for (vector<mysqlpp::Row>::const_iterator v=res.begin(); v<res.end(); v++)
2495 {
2496 const string name = (*v)[0].c_str();
2497 const double ra = (*v)[1];
2498 const double dec = (*v)[2];
2499#ifdef HAVE_NOVA
2500 Nova::EquPosn pos;
2501 pos.ra = ra*15;
2502 pos.dec = dec;
2503
2504 const Nova::ZdAzPosn hrz = Nova::GetHrzFromEqu(pos, now.JD());
2505
2506 /*const*/ pair<vector<float>, pair<Time, float>> vis = GetVisibility(&pos);
2507 if (!vis.first.empty())
2508 {
2509 const Entry entry(name, vis.second.second, ccol);
2510 culmination.insert(make_pair(vis.second.first, entry));
2511 const vector<float> col = entry.GetColor(75, 15);
2512 vis.first.insert(vis.first.begin(), col.begin(), col.end());
2513 alt.push_back(vis.first);
2514
2515 ccol++;
2516
2517 /*const*/ pair<vector<float>, pair<Time, float>> lc = GetLightCondition(pos);
2518 if (!lc.first.empty())
2519 {
2520 const Entry entry2(name, lc.second.second, lcol);
2521 lightcond.insert(make_pair(lc.second.first, entry2));
2522 const vector<float> col2 = entry2.GetColor(100);
2523 lc.first.insert(lc.first.begin(), col2.begin(), col2.end());
2524 cur.push_back(lc.first);
2525
2526 lcol++;
2527 }
2528 }
2529
2530 string col = HTML::kWhite;
2531 if (hrz.zd<85)
2532 col = HTML::kRed;
2533 if (hrz.zd<65)
2534 col = HTML::kYellow;
2535 if (hrz.zd<30)
2536 col = HTML::kGreen;
2537
2538 out2 << "<tr bgcolor='" << col << "'>";
2539 out2 << "<td>" << name << "</td>";
2540 if (hrz.zd<85)
2541 {
2542 out2 << "<td>" << hrz.zd << "&deg;</td>";
2543 out2 << "<td>" << GetDir(hrz.az) << "</td>";
2544 }
2545 else
2546 out2 << "<td/><td/>";
2547 out2 << "</tr>";
2548#endif
2549 const int32_t angle = fMoon.Angle(ra, dec);
2550
2551 out << "<tr bgcolor='" << Moon::Color(angle) << "'>";
2552 out << "<td>" << name << "</td>";
2553 out << "<td>" << round(angle) << "&deg;</td>";
2554 out << "</tr>";
2555 }
2556
2557 for (auto it=culmination.begin(); it!=culmination.end(); it++)
2558 {
2559 const Entry &e = it->second;
2560 if (it!=culmination.begin())
2561 out3 << ", ";
2562 out3 << "<B#" << e.Col() << ">" << e.name << "</B>";
2563 if (e.value>0)
2564 out3 << " [" << nearbyint(90-e.value) << "&deg;]";
2565 }
2566
2567 out4 << setprecision(3);
2568
2569 for (auto it=lightcond.begin(); it!=lightcond.end(); it++)
2570 {
2571 const Entry &e = it->second;
2572 if (it!=lightcond.begin())
2573 out4 << ", ";
2574 out4 << "<B#" << e.Col() << ">" << e.name << "</B>";
2575 if (e.value>0)
2576 out4 << " [" << nearbyint(e.value) << "]";
2577 }
2578
2579 const Time st = fSun.fSunSet12;;
2580 const Time rs = fSun.fSunRise12;
2581
2582 ostringstream title;
2583 title << st.GetAsStr("%H:%M");
2584 title << " / ";
2585 title << ((rs>st?rs-st:st-rs)/20).minutes();
2586 title << "' / ";
2587 title << rs.GetAsStr("%H:%M");
2588
2589 out << '\n';
2590 out2 << '\n';
2591 out3 << '\n';
2592 out4 << '\n';
2593 out << HTML::kWhite << '\t' << Time()-now << '\n';
2594 out2 << HTML::kWhite << '\t' << Time()-now << '\n';
2595
2596 WriteBinaryVec(now, "hist-visibility", alt, 75, 15, "Alt "+title.str());
2597 WriteBinaryVec(now, "hist-current-prediction", cur, 100, 0, "I " +title.str());
2598 }
2599 catch (const exception &e)
2600 {
2601 out << '\n';
2602 out2 << '\n';
2603 out << HTML::kWhite << '\t' << "ERROR - "+string(e.what()) << '\n';
2604 out2 << HTML::kWhite << '\t' << "ERROR - "+string(e.what()) << '\n';
2605 out3 << HTML::kWhite << '\t' << "ERROR - "+string(e.what()) << '\n';
2606 out4 << HTML::kWhite << '\t' << "ERROR - "+string(e.what()) << '\n';
2607 }
2608#endif
2609
2610 ofstream(fPath+"/moon.data") << out.str();
2611 ofstream(fPath+"/source-list.data") << out2.str();
2612 ofstream(fPath+"/visibility.data") << out3.str();
2613 ofstream(fPath+"/current-prediction.data") << out4.str();
2614 }
2615
2616 int Execute()
2617 {
2618 Time now;
2619 if (now-fLastUpdate<boost::posix_time::seconds(1))
2620 return fDimDNS.online() ? kStateRunning : kStateDimNetworkNA;
2621 fLastUpdate=now;
2622
2623 // ==============================================================
2624
2625 bool reqscript = false;
2626
2627#ifdef HAVE_SQL
2628 try
2629 {
2630 const string query = Tools::Form("SELECT COUNT(*) FROM calendar.Data WHERE NOT u LIKE 'moon' AND y=%d AND m=%d AND d=%d",
2631 now.NightAsInt()/10000, (now.NightAsInt()/100)%100-1, now.NightAsInt()%100);
2632
2633 const mysqlpp::StoreQueryResult res = Database(fDatabase).query(query).store();
2634
2635 const uint32_t cnt = res[0][0];
2636
2637 reqscript = cnt>0 && (fSun.state==3 || fSun.state==4);
2638 }
2639 catch (const exception &e)
2640 {
2641 Out() << e.what() << endl;
2642 }
2643#endif
2644 // ==============================================================
2645
2646 struct statvfs vfs;
2647 statvfs("/daq", &vfs);
2648
2649 const uint64_t freedaq = vfs.f_bsize*vfs.f_bavail;
2650
2651 // ==============================================================
2652
2653 const bool data_taking =
2654 fDimMcp.state()==MCP::State::kTriggerOn ||
2655 fDimMcp.state()==MCP::State::kTakingData;
2656
2657 const bool data_run =
2658 fMcpConfigurationName=="data" ||
2659 fMcpConfigurationName=="data-rt";
2660
2661 const bool bias_on =
2662 fDimBiasControl.state()==BIAS::State::kRamping ||
2663 fDimBiasControl.state()==BIAS::State::kOverCurrent ||
2664 fDimBiasControl.state()==BIAS::State::kVoltageOn;
2665
2666 const bool calibrated =
2667 fDimFeedback.state()>=Feedback::State::kCalibrated;
2668
2669 const bool haderr = !fErrorList.empty();
2670
2671 bool newerr = false;
2672
2673 newerr |= SetError(!fDimDNS.online(),
2674 "<b><#darkred>DIM network not available</#></b>");
2675 newerr |= SetError(!fDimControl.online(),
2676 "<b>no dimctrl server available</b>");
2677 newerr |= SetError(fDimDataLogger.state()<20 || fDimDataLogger.state()>40,
2678 "<b>datalogger not ready</b>");
2679
2680 newerr |= SetError(fDimControl.state()!=3 && reqscript,
2681 "<b>No script running during datataking time.</b>");
2682
2683 //newerr |= SetError(fDimDriveControl.state()==Drive::State::kLocked,
2684 // "<b><#darkred>Drive in LOCKED state, drive was automatically parked</#></b>");
2685
2686 newerr |= SetError(fDimDriveControl.state()>0xff && data_taking && data_run,
2687 "Drive in ERROR state during data-run");
2688 newerr |= SetError(fDriveControlMoonDist>155,
2689 "Moon within the field-of-view of the cones");
2690 newerr |= SetError(fDriveControlMoonDist>=0 && fDriveControlMoonDist<3,
2691 "Moon within the field-of-view of the camera");
2692
2693 newerr |= SetError(fDimBiasControl.state()<BIAS::State::kRamping && data_taking && data_run,
2694 "BIAS not operating during data-run");
2695 newerr |= SetError(fDimBiasControl.state()==BIAS::State::kOverCurrent,
2696 "BIAS channels in OverCurrent");
2697 newerr |= SetError(fDimBiasControl.state()==BIAS::State::kNotReferenced,
2698 "BIAS voltage not at reference");
2699
2700 newerr |= SetError(fDimFeedback.state()==Feedback::State::kOnStandby,
2701 "Feedback in standby due to high currents");
2702
2703
2704 newerr |= SetError(bias_on && calibrated && fBiasControlCurrentMed>115,
2705 "Median current (excl. crazy) exceeds 115&micro;A/pix");
2706 newerr |= SetError(bias_on && calibrated && fBiasControlCurrentMax>160,
2707 "Maximum current (excl. crazy) exceeds 160&micro;A/pix");
2708
2709 newerr |= SetError(fFscControlHumidityAvg>60,
2710 "Average camera humidity exceed 60%");
2711
2712 newerr |= SetError(!fPfMiniHumidityHist.empty() && fPfMiniHumidityHist.back()>50,
2713 "Camera humidity inside camera exceeds 50% (PFmini)");
2714 newerr |= SetError(!fTemperatureControlHist.empty() && (fTemperatureControlHist.back()<25.5 || fTemperatureControlHist.back()>28.5),
2715 "Container temperature outside [25.5;28.5]&deg;C");
2716
2717 newerr |= SetError(!fMagicWeatherHist[kHum].empty() && fMagicWeatherHist[kHum].back()>98 && fDimLidControl.state()==Lid::State::kOpen,
2718 "Outside humidity exceeds 98% while lid is open");
2719 newerr |= SetError(!fMagicWeatherHist[kGusts].empty() && fMagicWeatherHist[kGusts].back()>50 && (fDimDriveControl.state()==Drive::State::kTracking||fDimDriveControl.state()==Drive::State::kOnTrack),
2720 "Wind gusts exceed 50km/h during tracking");
2721
2722 newerr |= SetError(fDimFscControl.state()>=FSC::State::kConnected && !fFscControlTemperatureHist.empty() && fFscControlTemperatureHist.back()>15,
2723 "Sensor temperature exceeds outside temperature by more than 15&deg;C");
2724
2725 newerr |= SetError(fFtmControlTriggerRateTooLow>0,
2726 "Trigger rate below 1Hz while trigger switched on");
2727
2728 newerr |= SetError(fFtmControlState!=FTM::kFtmConfig && (fFtmControlState&FTM::kFtmLocked)==0,
2729 "FTM - clock conditioner not locked!");
2730
2731 newerr |= SetError(fDimTimeCheck.state()==1,
2732 "Warning NTP time difference of drive PC exceeds 1s");
2733 newerr |= SetError(fDimTimeCheck.state()<1,
2734 "Warning timecheck not running");
2735
2736 newerr |= SetError(fDimBiasControl.state()==BIAS::State::kVoltageOn &&
2737 fDimFeedback.state()<Feedback::State::kCalibrating &&
2738 fBiasControlVoltageMed>3,
2739 "Bias voltage switched on, but bias crate not calibrated");
2740
2741 newerr |= SetError(fLastRunFinishedWithZeroEvents,
2742 "Last run finshed, but contained zero events.");
2743
2744 newerr |= SetError(fFreeSpace<uint64_t(50000000000),
2745 "Less than 50GB disk space left on newdaq.");
2746
2747 newerr |= SetError(freedaq<uint64_t(800000000000),
2748 "Less than 800GB disk space left on daq.");
2749
2750 newerr |= SetError(fDimPwrControl.state()==Power::State::kCoolingFailure,
2751 "Cooling unit reports failure!");
2752
2753 for (auto it=fControlAlarmHist.begin(); it!=fControlAlarmHist.end(); it++)
2754 newerr |= SetError(it->time.IsValid(), it->msg);
2755 fControlAlarmHist.clean();;
2756
2757 fLastRunFinishedWithZeroEvents = false;
2758
2759 // FTM in Connected instead of Idle --> power cyclen
2760
2761 /* // Check offline and disconnected status?
2762 Out() << fDimMcp << endl;
2763 Out() << fDimControl << endl;
2764 Out() << fDimDataLogger << endl;
2765 Out() << fDimDriveControl << endl;
2766 Out() << fDimFadControl << endl;
2767 Out() << fDimFtmControl << endl;
2768 Out() << fDimBiasControl << endl;
2769 Out() << fDimFeedback << endl;
2770 Out() << fDimRateControl << endl;
2771 Out() << fDimFscControl << endl;
2772 Out() << fDimMagicWeather << endl;
2773 Out() << fDimRateScan << endl;
2774 Out() << fDimChat << endl;
2775 */
2776
2777 // FTU in error
2778 // FAD lost
2779
2780 // --------------------------------------------------------------
2781 ostringstream out;
2782
2783 if (newerr)
2784 {
2785 SetAudio("error");
2786
2787 out << now.JavaDate() << '\n';
2788 out << HTML::kWhite << '\t';
2789 out << "<->" << fErrorHist.rget() << "<->";
2790 out << '\n';
2791
2792 ofstream(fPath+"/errorhist.data") << out.str();
2793 }
2794
2795 out.str("");
2796 out << Header(now) << '\t' << (!fErrorList.empty()) << '\t' << (fDimControl.state()>0) << '\n';
2797 out << setprecision(3);
2798 out << HTML::kWhite << '\t';
2799 for (auto it=fErrorList.begin(); it!=fErrorList.end(); it++)
2800 out << *it << "<br/>";
2801 out << '\n';
2802
2803 if (haderr || !fErrorList.empty())
2804 ofstream(fPath+"/error.data") << out.str();
2805
2806 // ==============================================================
2807
2808 out.str("");
2809 out << Header(now) << '\t' << (!fErrorList.empty()) << '\t' << (fDimControl.state()>0) << '\n';
2810 out << setprecision(3);
2811
2812 // -------------- System status --------------
2813 if (fDimDNS.online() && fDimMcp.state()>=MCP::State::kIdle) // Idle
2814 {
2815 string col = HTML::kBlue;
2816 switch (fMcpConfigurationState)
2817 {
2818 case MCP::State::kIdle:
2819 case DimState::kOffline:
2820 col = HTML::kWhite;
2821 break;
2822 case MCP::State::kConfiguring1:
2823 case MCP::State::kConfiguring2:
2824 case MCP::State::kConfiguring3:
2825 case MCP::State::kConfigured:
2826 case MCP::State::kTriggerOn:
2827 col = HTML::kBlue;
2828 break;
2829 case MCP::State::kTakingData:
2830 col = HTML::kBlue;
2831 if (fDimFadControl.state()==FAD::State::kRunInProgress)
2832 col = HTML::kGreen;
2833 break;
2834 }
2835
2836 const bool other =
2837 fDimRateControl.state()==RateControl::State::kSettingGlobalThreshold ||
2838 fDimLidControl.state()==Lid::State::kMoving ||
2839 fDimRateScan.state()==RateScan::State::kInProgress;
2840
2841 if (other)
2842 col = HTML::kBlue;
2843
2844 out << col << '\t';
2845
2846 if (!other)
2847 {
2848 const string conf = fMcpConfigurationName.length()>0?" ["+fMcpConfigurationName+"]":"";
2849 switch (fMcpConfigurationState)
2850 {
2851 case MCP::State::kIdle:
2852 out << "Idle" << conf;
2853 break;
2854 case MCP::State::kConfiguring1:
2855 case MCP::State::kConfiguring2:
2856 case MCP::State::kConfiguring3:
2857 out << "Configuring" << conf;
2858 break;
2859 case MCP::State::kConfigured:
2860 out << "Configured" << conf;
2861 break;
2862 case MCP::State::kTriggerOn:
2863 case MCP::State::kTakingData:
2864 out << fMcpConfigurationName;
2865 if (fFadControlDrsRuns[2]>0)
2866 out << "(" << fFadControlDrsRuns[2] << ")";
2867 break;
2868 }
2869 }
2870 else
2871 if (fDimRateControl.state()==RateControl::State::kSettingGlobalThreshold)
2872 out << "Calibrating threshold";
2873 else
2874 if (fDimRateScan.state()==RateScan::State::kInProgress)
2875 out << "Rate scan in progress";
2876 else
2877 if (fDimLidControl.state()==Lid::State::kMoving)
2878 out << "Lid moving";
2879
2880
2881 if (fMcpConfigurationState>MCP::State::kConfigured &&
2882 fDimRateControl.state()!=RateControl::State::kSettingGlobalThreshold)
2883 {
2884 ostringstream evt;
2885 if (fMcpConfigurationMaxEvents>0)
2886 {
2887 const int64_t de = int64_t(fMcpConfigurationMaxEvents) - int64_t(fFadControlNumEvents);
2888 if (de>=0 && fMcpConfigurationState==MCP::State::kTakingData)
2889 evt << de;
2890 else
2891 evt << fMcpConfigurationMaxEvents;
2892 }
2893 else
2894 {
2895 if (fMcpConfigurationState==MCP::State::kTakingData)
2896 {
2897 if (fFadControlNumEvents>2999)
2898 evt << floor(fFadControlNumEvents/1000) << 'k';
2899 else
2900 evt << fFadControlNumEvents;
2901 }
2902 }
2903
2904 ostringstream tim;
2905 if (fMcpConfigurationMaxTime>0)
2906 {
2907 const uint32_t dt = (Time()-fMcpConfigurationRunStart).total_seconds();
2908 if (dt<=fMcpConfigurationMaxTime && fMcpConfigurationState==MCP::State::kTakingData)
2909 tim << fMcpConfigurationMaxTime-dt << 's';
2910 else
2911 tim << fMcpConfigurationMaxTime << 's';
2912 }
2913 else
2914 {
2915 if (fMcpConfigurationState==MCP::State::kTakingData)
2916 tim << fMcpConfigurationRunStart.SecondsTo();
2917 }
2918
2919 const bool has_evt = !evt.str().empty();
2920 const bool has_tim = !tim.str().empty();
2921
2922 if (has_evt || has_tim)
2923 out << " [";
2924 out << evt.str();
2925 if (has_evt && has_tim)
2926 out << '/';
2927 out << tim.str();
2928 if (has_evt || has_tim)
2929 out << ']';
2930 }
2931 }
2932 else
2933 out << HTML::kWhite;
2934 out << '\n';
2935
2936 // ------------------ Drive -----------------
2937 if (fDimDNS.online() && fDimDriveControl.state()>=Drive::State::kInitialized) // Armed, Moving, Tracking, OnTrack, Error
2938 {
2939 const uint32_t dev = !fDriveControlTrackingDevHist.empty() ? round(fDriveControlTrackingDevHist.back()) : 0;
2940 const State rc = fDimDriveControl.description();
2941 string col = HTML::kGreen;
2942 if (fDimDriveControl.state()==Drive::State::kInitialized) // Armed
2943 col = HTML::kWhite;
2944 if (fDimDriveControl.state()>Drive::State::kInitialized && // Moving
2945 fDimDriveControl.state()<Drive::State::kTracking)
2946 col = HTML::kBlue;
2947 if (fDimDriveControl.state()==Drive::State::kTracking || // Tracking
2948 fDimDriveControl.state()==Drive::State::kOnTrack)
2949 {
2950 if (dev>60) // ~1.5mm
2951 col = HTML::kYellow;
2952 if (dev>120) // ~1/4 of a pixel ~ 2.5mm
2953 col = HTML::kRed;
2954 }
2955 if (fDimDriveControl.state()>0xff)
2956 col = HTML::kRed;
2957 out << col << '\t';
2958
2959 //out << rc.name << '\t';
2960 out << fDriveControlPointingAz << ' ';
2961 out << fDriveControlPointingZd << "&deg;";
2962 out << setprecision(2);
2963 if (fDimDriveControl.state()==Drive::State::kTracking ||
2964 fDimDriveControl.state()==Drive::State::kOnTrack) // Tracking
2965 {
2966 out << " &plusmn; " << dev << '"';
2967 if (!fDriveControlSourceName.empty())
2968 out << " [" << fDriveControlSourceName << ']';
2969 }
2970 if (fDimDriveControl.state()>Drive::State::kInitialized && // Moving
2971 fDimDriveControl.state()<Drive::State::kTracking)
2972 out << " &#10227;";
2973 out << setprecision(3);
2974 }
2975 else
2976 out << HTML::kWhite << '\t';
2977
2978 if (fSun.time.IsValid() && fMoon.time.IsValid())
2979 {
2980 if (fSun.visible)
2981 {
2982 out << " &#9788;";
2983 if (fDimDriveControl.state()<Drive::State::kInitialized)
2984 out << " [" << fSun.fSunSet12.MinutesTo() << "&darr;]";
2985 }
2986 else
2987 if (!fSun.visible && fMoon.visible)
2988 {
2989 out << " &#9790;";
2990 if (fDimDriveControl.state()<Drive::State::kInitialized)
2991 out << " [" << fMoon.disk << "%]";
2992 }
2993 }
2994 if (fDimDNS.online() && fDimDriveControl.state()>0xff)
2995 out << " <ERR>";
2996 if (fDimDNS.online() && fDimDriveControl.state()==Drive::State::kLocked)
2997 out << " &otimes;";
2998 out << '\n';
2999
3000 // ------------------- FSC ------------------
3001 if (fDimDNS.online() && fDimFscControl.state()>FSC::State::kDisconnected && !fFscControlTemperatureHist.empty())
3002 {
3003 string col = HTML::kGreen;
3004 if (fFscControlTemperatureHist.back()>9)
3005 col = HTML::kYellow;
3006 if (fFscControlTemperatureHist.back()>15)
3007 col = HTML::kRed;
3008
3009 out << col << '\t' << fFscControlTemperatureHist.back() << '\n';
3010 }
3011 else
3012 out << HTML::kWhite << '\n';
3013
3014 // --------------- MagicWeather -------------
3015 if (fDimDNS.online() && fDimMagicWeather.state()==MagicWeather::State::kReceiving && !fMagicWeatherHist[kWeatherBegin].empty())
3016 {
3017 /*
3018 const float diff = fMagicWeatherHist[kTemp].back()-fMagicWeatherHist[kDew].back();
3019 string col1 = HTML::kRed;
3020 if (diff>0.3)
3021 col1 = HTML::kYellow;
3022 if (diff>0.7)
3023 col1 = HTML::kGreen;
3024 */
3025
3026 const float wind = fMagicWeatherHist[kGusts].back();
3027 const float hum = fMagicWeatherHist[kHum].back();
3028 string col = HTML::kGreen;
3029 if (wind>35 || hum>95)
3030 col = HTML::kYellow;
3031 if (wind>45 || hum>98)
3032 col = HTML::kRed;
3033
3034 out << col << '\t';
3035 out << fMagicWeatherHist[kHum].back() << '\t';
3036 out << setprecision(2);
3037 out << fMagicWeatherHist[kGusts].back() << '\n';
3038 out << setprecision(3);
3039 }
3040 else
3041 out << HTML::kWhite << "\n";
3042
3043 // --------------- FtmControl -------------
3044 if (fDimDNS.online() && fDimFtmControl.state()==FTM::State::kTriggerOn)
3045 {
3046 string col = HTML::kGreen;
3047 if (!fFtmControlTriggerRateHist.empty())
3048 {
3049 if (fFtmControlTriggerRateHist.back()<15)
3050 col = HTML::kYellow;
3051 if (fFtmControlTriggerRateHist.back()>100)
3052 col = HTML::kRed;
3053
3054 out << col << '\t' << fFtmControlTriggerRateHist.back() << " Hz";
3055 }
3056
3057 if (bias_on)
3058 out << " (" << setprecision(4) << fFtmPatchThresholdMed << ')';
3059 out << '\n';
3060 }
3061 else
3062 out << HTML::kWhite << '\n';
3063
3064 // --------------- BiasControl -------------
3065 const bool bias_off = fDimBiasControl.state()==BIAS::State::kVoltageOff;
3066 const bool bias_oc = fDimBiasControl.state()==BIAS::State::kOverCurrent;
3067
3068 if (fDimDNS.online() && (bias_on || bias_off))
3069 {
3070
3071 string col = fBiasControlVoltageMed>3?HTML::kGreen:HTML::kWhite;
3072 if (bias_on)
3073 {
3074 if (fBiasControlCurrentMed>95 || fBiasControlCurrentMax>135)
3075 col = HTML::kYellow;
3076 if (fBiasControlCurrentMed>100 || fBiasControlCurrentMax>140)
3077 col = HTML::kRed;
3078 }
3079
3080 // Bias in overcurrent => Red
3081 if (bias_oc)
3082 col = HTML::kRed;
3083
3084 // MCP in ReadyForDatataking/Configuring/Configured/TriggerOn/TakingData
3085 // and Bias not in "data-taking state' => Red
3086 if (fMcpConfigurationState>MCP::State::kIdle && !bias_on)
3087 col = HTML::kWhite;
3088
3089 const bool cal = fDimFeedback.state()>=Feedback::State::kCalibrated;
3090
3091 // Feedback is currently calibrating => Blue
3092 if (fDimFeedback.state()==Feedback::State::kCalibrating)
3093 {
3094 out << HTML::kBlue << '\t';
3095 out << "***\t";
3096 out << "***\t";
3097 }
3098 else
3099 {
3100 out << col << '\t';
3101 out << setprecision(fBiasControlCurrentMed<100?2:3);
3102 out << (bias_off ? 0 : (fBiasControlCurrentMed<10?fBiasControlCurrentMed:floor(fBiasControlCurrentMed))) << '\t';
3103 if (bias_oc)
3104 out << "(OC) ";
3105 else
3106 {
3107 if (cal)
3108 {
3109 out << setprecision(fBiasControlCurrentMax<100?2:3);
3110 out << (bias_off ? 0 : (fBiasControlCurrentMax<10?fBiasControlCurrentMax:floor(fBiasControlCurrentMax)));
3111 }
3112 else
3113 out << "&mdash; ";
3114 }
3115 out << '\t';
3116 }
3117 if (cal && fDimFeedback.state()!=Feedback::State::kCalibrating)
3118 out << setprecision(2) << fBiasControlPowerTot << " W";
3119 else
3120 out << setprecision(3) << (bias_off ? 0 : fBiasControlVoltageMed) << " V";
3121 out << '\n';
3122 }
3123 else
3124 out << HTML::kWhite << '\n';
3125
3126 ofstream(fPath+"/fact.data") << out.str();
3127
3128 // ==============================================================
3129
3130 out.str("");
3131 out << Header(now) << '\t' << (!fErrorList.empty()) << '\t' << (fDimControl.state()>0) << '\n';
3132
3133 if (!fDimDNS.online())
3134 out << HTML::kWhite << "\tOffline\n\n\n\n\n\n\n\n\n\n\n\n\n";
3135 else
3136 {
3137 ostringstream dt;
3138 dt << (Time()-fRunTime);
3139
3140 out << HTML::kGreen << '\t' << fDimDNS.version() << '\n';
3141
3142 out << GetStateHtml(fDimControl, 0);
3143 out << GetStateHtml(fDimMcp, MCP::State::kConnected);
3144 out << GetStateHtml(fDimDataLogger, 1);
3145 out << GetStateHtml(fDimDriveControl, Drive::State::kConnected);
3146 out << GetStateHtml(fDimTimeCheck, 1);
3147 out << GetStateHtml(fDimFadControl, FAD::State::kConnected);
3148 out << GetStateHtml(fDimFtmControl, FTM::State::kConnected);
3149 out << GetStateHtml(fDimBiasControl, BIAS::State::kConnected);
3150 out << GetStateHtml(fDimFeedback, Feedback::State::kConnected);
3151 out << GetStateHtml(fDimRateControl, RateControl::State::kConnected);
3152 out << GetStateHtml(fDimFscControl, FSC::State::kConnected);
3153 out << GetStateHtml(fDimPfMiniControl, PFmini::State::kConnected);
3154 out << GetStateHtml(fDimGpsControl, GPS::State::kConnected);
3155 out << GetStateHtml(fDimSqmControl, SQM::State::kConnected);
3156 out << GetStateHtml(fDimAgilentControl24, Agilent::State::kVoltageOff);
3157 out << GetStateHtml(fDimAgilentControl50, Agilent::State::kVoltageOff);
3158 out << GetStateHtml(fDimAgilentControl80, Agilent::State::kVoltageOff);
3159 out << GetStateHtml(fDimPwrControl, Power::State::kSystemOff);
3160 out << GetStateHtml(fDimLidControl, Lid::State::kConnected);
3161 out << GetStateHtml(fDimRateScan, RateScan::State::kConnected);
3162 out << GetStateHtml(fDimMagicWeather, MagicWeather::State::kConnected);
3163 out << GetStateHtml(fDimTngWeather, TNGWeather::State::kConnected);
3164 out << GetStateHtml(fDimMagicLidar, MagicLidar::State::kConnected);
3165 out << GetStateHtml(fDimTemperature, Temperature::State::kValid);
3166 out << GetStateHtml(fDimChat, 0);
3167 out << GetStateHtml(fDimSkypeClient, 1);
3168
3169 string col = HTML::kRed;
3170 if (fFreeSpace>uint64_t(199999999999))
3171 col = HTML::kYellow;
3172 if (fFreeSpace>uint64_t(999999999999))
3173 col = HTML::kGreen;
3174 if (fFreeSpace==UINT64_MAX)
3175 col = HTML::kWhite;
3176
3177 out << col << '\t' << Tools::Scientific(fFreeSpace) << "B\n";
3178
3179 col = HTML::kRed;
3180 if (freedaq>uint64_t(999999999999))
3181 col = HTML::kYellow;
3182 if (freedaq>uint64_t(149999999999))
3183 col = HTML::kGreen;
3184 if (freedaq==UINT64_MAX)
3185 col = HTML::kWhite;
3186
3187 out << col << '\t' << Tools::Scientific(freedaq) << "B\n";
3188
3189 out << HTML::kGreen << '\t' << dt.str().substr(0, dt.str().length()-7) << '\n';
3190 }
3191
3192 ofstream(fPath+"/status.data") << out.str();
3193
3194 if (now-fLastAstroCalc>boost::posix_time::seconds(15))
3195 {
3196 UpdateAstronomy();
3197 fLastAstroCalc = now;
3198 }
3199
3200 return fDimDNS.online() ? kStateRunning : kStateDimNetworkNA;
3201 }
3202
3203
3204public:
3205 StateMachineSmartFACT(ostream &out=cout) : StateMachineDim(out, fIsServer?"SMART_FACT":""),
3206 fLastAstroCalc(boost::date_time::neg_infin),
3207 fPath("www/smartfact/data"),
3208 fControlScriptDepth(0),
3209 fMcpConfigurationState(DimState::kOffline),
3210 fMcpConfigurationMaxTime(0),
3211 fMcpConfigurationMaxEvents(0),
3212 fLastRunFinishedWithZeroEvents(false),
3213 fTngWeatherDustTime(Time::none),
3214 fBiasControlVoltageMed(0),
3215 fBiasControlCurrentMed(0),
3216 fBiasControlCurrentMax(0),
3217 fFscControlHumidityAvg(0),
3218 fDriveControlMoonDist(-1),
3219 fFadControlNumEvents(0),
3220 fFadControlDrsRuns(3),
3221 fFtmControlState(FTM::kFtmLocked),
3222 fRateScanDataId(0),
3223 fRateScanBoard(0),
3224 fFreeSpace(UINT64_MAX),
3225 // ---
3226 fDimMcp ("MCP"),
3227 fDimDataLogger ("DATA_LOGGER"),
3228 fDimDriveControl ("DRIVE_CONTROL"),
3229 fDimTimeCheck ("TIME_CHECK"),
3230 fDimMagicWeather ("MAGIC_WEATHER"),
3231 fDimMagicLidar ("MAGIC_LIDAR"),
3232 fDimTngWeather ("TNG_WEATHER"),
3233 fDimTemperature ("TEMPERATURE"),
3234 fDimFeedback ("FEEDBACK"),
3235 fDimBiasControl ("BIAS_CONTROL"),
3236 fDimFtmControl ("FTM_CONTROL"),
3237 fDimFadControl ("FAD_CONTROL"),
3238 fDimFscControl ("FSC_CONTROL"),
3239 fDimPfMiniControl ("PFMINI_CONTROL"),
3240 fDimGpsControl ("GPS_CONTROL"),
3241 fDimSqmControl ("SQM_CONTROL"),
3242 fDimAgilentControl24("AGILENT_CONTROL_24V"),
3243 fDimAgilentControl50("AGILENT_CONTROL_50V"),
3244 fDimAgilentControl80("AGILENT_CONTROL_80V"),
3245 fDimPwrControl ("PWR_CONTROL"),
3246 fDimLidControl ("LID_CONTROL"),
3247 fDimRateControl ("RATE_CONTROL"),
3248 fDimRateScan ("RATE_SCAN"),
3249 fDimChat ("CHAT"),
3250 fDimSkypeClient ("SKYPE_CLIENT")
3251 {
3252 fDimDNS.Subscribe(*this);
3253 fDimControl.Subscribe(*this);
3254 fDimMcp.Subscribe(*this);
3255 fDimDataLogger.Subscribe(*this);
3256 fDimDriveControl.Subscribe(*this);
3257 fDimTimeCheck.Subscribe(*this);
3258 fDimMagicWeather.Subscribe(*this);
3259 fDimMagicLidar.Subscribe(*this);
3260 fDimTngWeather.Subscribe(*this);
3261 fDimTemperature.Subscribe(*this);
3262 fDimFeedback.Subscribe(*this);
3263 fDimBiasControl.Subscribe(*this);
3264 fDimFtmControl.Subscribe(*this);
3265 fDimFadControl.Subscribe(*this);
3266 fDimFscControl.Subscribe(*this);
3267 fDimPfMiniControl.Subscribe(*this);
3268 fDimGpsControl.Subscribe(*this);
3269 fDimSqmControl.Subscribe(*this);
3270 fDimAgilentControl24.Subscribe(*this);
3271 fDimAgilentControl50.Subscribe(*this);
3272 fDimAgilentControl80.Subscribe(*this);
3273 fDimPwrControl.Subscribe(*this);
3274 fDimLidControl.Subscribe(*this);
3275 fDimRateControl.Subscribe(*this);
3276 fDimRateScan.Subscribe(*this);
3277 fDimChat.Subscribe(*this);
3278 fDimSkypeClient.Subscribe(*this);
3279
3280 fDimFscControl.SetCallback(bind(&StateMachineSmartFACT::HandleFscControlStateChange, this, placeholders::_1));
3281 //fDimFtmControl.SetCallback(bind(&StateMachineSmartFACT::HandleFtmControlStateChange, this));
3282 fDimDriveControl.SetCallback(bind(&StateMachineSmartFACT::HandleDriveControlStateChange, this, placeholders::_1));
3283 fDimControl.SetCallback(bind(&StateMachineSmartFACT::HandleControlStateChange, this, placeholders::_1));
3284 fDimControl.AddCallback("dotest.dim", bind(&StateMachineSmartFACT::HandleDoTest, this, placeholders::_1));
3285
3286 Subscribe("DIM_CONTROL/MESSAGE")
3287 (bind(&StateMachineSmartFACT::HandleDimControlMessage, this, placeholders::_1));
3288
3289 Subscribe("MCP/CONFIGURATION")
3290 (bind(&StateMachineSmartFACT::HandleMcpConfiguration, this, placeholders::_1));
3291
3292 Subscribe("DRIVE_CONTROL/POINTING_POSITION")
3293 (bind(&StateMachineSmartFACT::HandleDrivePointing, this, placeholders::_1));
3294 Subscribe("DRIVE_CONTROL/TRACKING_POSITION")
3295 (bind(&StateMachineSmartFACT::HandleDriveTracking, this, placeholders::_1));
3296 Subscribe("DRIVE_CONTROL/SOURCE_POSITION")
3297 (bind(&StateMachineSmartFACT::HandleDriveSource, this, placeholders::_1));
3298
3299 Subscribe("FSC_CONTROL/TEMPERATURE")
3300 (bind(&StateMachineSmartFACT::HandleFscTemperature, this, placeholders::_1));
3301 Subscribe("FSC_CONTROL/HUMIDITY")
3302 (bind(&StateMachineSmartFACT::HandleFscHumidity, this, placeholders::_1));
3303 Subscribe("FSC_CONTROL/BIAS_TEMP")
3304 (bind(&StateMachineSmartFACT::HandleFscBiasTemp, this, placeholders::_1));
3305
3306 Subscribe("PFMINI_CONTROL/DATA")
3307 (bind(&StateMachineSmartFACT::HandlePfMiniData, this, placeholders::_1));
3308
3309 Subscribe("GPS_CONTROL/NEMA")
3310 (bind(&StateMachineSmartFACT::HandleGpsNema, this, placeholders::_1));
3311
3312 Subscribe("SQM_CONTROL/DATA")
3313 (bind(&StateMachineSmartFACT::HandleSqmData, this, placeholders::_1));
3314
3315 Subscribe("TEMPERATURE/DATA")
3316 (bind(&StateMachineSmartFACT::HandleTemperatureData, this, placeholders::_1));
3317
3318 Subscribe("AGILENT_CONTROL_24V/DATA")
3319 (bind(&StateMachineSmartFACT::HandleAgilentData, this, placeholders::_1, "24"));
3320 Subscribe("AGILENT_CONTROL_50V/DATA")
3321 (bind(&StateMachineSmartFACT::HandleAgilentData, this, placeholders::_1, "50"));
3322 Subscribe("AGILENT_CONTROL_80V/DATA")
3323 (bind(&StateMachineSmartFACT::HandleAgilentData, this, placeholders::_1, "80"));
3324
3325 Subscribe("MAGIC_WEATHER/DATA")
3326 (bind(&StateMachineSmartFACT::HandleMagicWeatherData, this, placeholders::_1));
3327 Subscribe("TNG_WEATHER/DUST")
3328 (bind(&StateMachineSmartFACT::HandleTngWeatherDust, this, placeholders::_1));
3329
3330 Subscribe("FEEDBACK/CALIBRATED_CURRENTS")
3331 (bind(&StateMachineSmartFACT::HandleFeedbackCalibratedCurrents, this, placeholders::_1));
3332
3333 Subscribe("BIAS_CONTROL/VOLTAGE")
3334 (bind(&StateMachineSmartFACT::HandleBiasVoltage, this, placeholders::_1));
3335 Subscribe("BIAS_CONTROL/CURRENT")
3336 (bind(&StateMachineSmartFACT::HandleBiasCurrent, this, placeholders::_1));
3337
3338 Subscribe("FAD_CONTROL/CONNECTIONS")
3339 (bind(&StateMachineSmartFACT::HandleFadConnections, this, placeholders::_1));
3340 Subscribe("FAD_CONTROL/EVENTS")
3341 (bind(&StateMachineSmartFACT::HandleFadEvents, this, placeholders::_1));
3342 Subscribe("FAD_CONTROL/START_RUN")
3343 (bind(&StateMachineSmartFACT::HandleFadStartRun, this, placeholders::_1));
3344 Subscribe("FAD_CONTROL/DRS_RUNS")
3345 (bind(&StateMachineSmartFACT::HandleFadDrsRuns, this, placeholders::_1));
3346 Subscribe("FAD_CONTROL/EVENT_DATA")
3347 (bind(&StateMachineSmartFACT::HandleFadEventData, this, placeholders::_1));
3348 Subscribe("FAD_CONTROL/STATS")
3349 (bind(&StateMachineSmartFACT::HandleStats, this, placeholders::_1));
3350
3351 Subscribe("DATA_LOGGER/STATS")
3352 (bind(&StateMachineSmartFACT::HandleStats, this, placeholders::_1));
3353
3354 Subscribe("FTM_CONTROL/TRIGGER_RATES")
3355 (bind(&StateMachineSmartFACT::HandleFtmTriggerRates, this, placeholders::_1));
3356 Subscribe("FTM_CONTROL/STATIC_DATA")
3357 (bind(&StateMachineSmartFACT::HandleFtmStaticData, this, placeholders::_1));
3358 Subscribe("FTM_CONTROL/FTU_LIST")
3359 (bind(&StateMachineSmartFACT::HandleFtmFtuList, this, placeholders::_1));
3360
3361 Subscribe("RATE_CONTROL/THRESHOLD")
3362 (bind(&StateMachineSmartFACT::HandleRateControlThreshold,this, placeholders::_1));
3363
3364 Subscribe("RATE_SCAN/DATA")
3365 (bind(&StateMachineSmartFACT::HandleRateScanData, this, placeholders::_1));
3366
3367 Subscribe("CHAT/MESSAGE")
3368 (bind(&StateMachineSmartFACT::HandleChatMsg, this, placeholders::_1));
3369
3370
3371 // =================================================================
3372
3373 // State names
3374 AddStateName(kStateDimNetworkNA, "DimNetworkNotAvailable",
3375 "The Dim DNS is not reachable.");
3376
3377 AddStateName(kStateRunning, "Running", "");
3378
3379 // =================================================================
3380
3381 AddEvent("PRINT")
3382 (bind(&StateMachineSmartFACT::Print, this))
3383 ("Print a list of the states of all connected servers.");
3384
3385 }
3386 int EvalOptions(Configuration &conf)
3387 {
3388 if (!fPixelMap.Read(conf.Get<string>("pixel-map-file")))
3389 {
3390 Error("Reading mapping table from "+conf.Get<string>("pixel-map-file")+" failed.");
3391 return 1;
3392 }
3393
3394 fPath = conf.Get<string>("path");
3395 fDatabase = conf.Get<string>("source-database");
3396
3397 struct stat st;
3398 if (stat(fPath.c_str(), &st))
3399 {
3400 Error(fPath+" does not exist!");
3401 return 2;
3402 }
3403
3404 if ((st.st_mode&S_IFDIR)==0)
3405 {
3406 Error(fPath+" not a directory!");
3407 return 3;
3408 }
3409
3410 if ((st.st_mode&S_IWUSR)==0)
3411 {
3412 Error(fPath+" has no write permission!");
3413 return 4;
3414 }
3415
3416 if ((st.st_mode&S_IXUSR)==0)
3417 {
3418 Error(fPath+" has no execute permission!");
3419 return 5;
3420 }
3421
3422 ostringstream out;
3423 out << Time().JavaDate() << '\n';
3424
3425 ofstream(fPath+"/error.data") << out.str();
3426
3427 return -1;
3428 }
3429};
3430
3431bool StateMachineSmartFACT::fIsServer = false;
3432
3433// ------------------------------------------------------------------------
3434
3435#include "Main.h"
3436
3437template<class T>
3438int RunShell(Configuration &conf)
3439{
3440 StateMachineSmartFACT::fIsServer = !conf.Get<bool>("client");
3441 return Main::execute<T, StateMachineSmartFACT>(conf);
3442}
3443
3444void SetupConfiguration(Configuration &conf)
3445{
3446 po::options_description control("Smart FACT");
3447 control.add_options()
3448 ("pixel-map-file", var<string>()->required(), "Pixel mapping file. Used here to get the default reference voltage")
3449 ("path", var<string>("www/smartfact/data"), "Output path for the data-files")
3450 ("source-database", var<string>(""), "Database link as in\n\tuser:password@server[:port]/database.")
3451 ("client", po_bool(false), "For a standalone client choose this option.")
3452 ;
3453
3454 conf.AddOptions(control);
3455}
3456
3457/*
3458 Extract usage clause(s) [if any] for SYNOPSIS.
3459 Translators: "Usage" and "or" here are patterns (regular expressions) which
3460 are used to match the usage synopsis in program output. An example from cp
3461 (GNU coreutils) which contains both strings:
3462 Usage: cp [OPTION]... [-T] SOURCE DEST
3463 or: cp [OPTION]... SOURCE... DIRECTORY
3464 or: cp [OPTION]... -t DIRECTORY SOURCE...
3465 */
3466void PrintUsage()
3467{
3468 cout <<
3469 "SmartFACT is a tool writing the files needed for the SmartFACT web interface.\n"
3470 "\n"
3471 "The default is that the program is started without user intercation. "
3472 "All actions are supposed to arrive as DimCommands. Using the -c "
3473 "option, a local shell can be initialized. With h or help a short "
3474 "help message about the usuage can be brought to the screen.\n"
3475 "\n"
3476 "Usage: smartfact [-c type] [OPTIONS]\n"
3477 " or: smartfact [OPTIONS]\n";
3478 cout << endl;
3479}
3480
3481void PrintHelp()
3482{
3483 Main::PrintHelp<StateMachineSmartFACT>();
3484
3485 /* Additional help text which is printed after the configuration
3486 options goes here */
3487
3488 /*
3489 cout << "bla bla bla" << endl << endl;
3490 cout << endl;
3491 cout << "Environment:" << endl;
3492 cout << "environment" << endl;
3493 cout << endl;
3494 cout << "Examples:" << endl;
3495 cout << "test exam" << endl;
3496 cout << endl;
3497 cout << "Files:" << endl;
3498 cout << "files" << endl;
3499 cout << endl;
3500 */
3501}
3502
3503int main(int argc, const char* argv[])
3504{
3505 Configuration conf(argv[0]);
3506 conf.SetPrintUsage(PrintUsage);
3507 Main::SetupConfiguration(conf);
3508 SetupConfiguration(conf);
3509
3510 if (!conf.DoParse(argc, argv, PrintHelp))
3511 return 127;
3512
3513 if (!conf.Has("console"))
3514 return RunShell<LocalStream>(conf);
3515
3516 if (conf.Get<int>("console")==0)
3517 return RunShell<LocalShell>(conf);
3518 else
3519 return RunShell<LocalConsole>(conf);
3520
3521 return 0;
3522}
Note: See TracBrowser for help on using the repository browser.