source: trunk/FACT++/src/smartfact.cc@ 18383

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