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

Last change on this file since 14177 was 14161, checked in by tbretz, 12 years ago
Added the possibility to start no dim-server; added some checks for the existance and accessibility of the given path; some small updates and improvements to the error handling; added zero-event check
File size: 89.6 KB
Line 
1#ifdef HAVE_LIBNOVA
2#include <libnova/solar.h>
3#include <libnova/lunar.h>
4#include <libnova/rise_set.h>
5#include <libnova/transform.h>
6#endif
7
8#ifdef HAVE_SQL
9#include "Database.h"
10#endif
11
12#include <sys/stat.h> //for file stats
13
14#include "Dim.h"
15#include "Event.h"
16#include "Shell.h"
17#include "StateMachineDim.h"
18#include "Connection.h"
19#include "Configuration.h"
20#include "Console.h"
21#include "Converter.h"
22#include "PixelMap.h"
23
24#include "tools.h"
25
26#include "LocalControl.h"
27
28#include "HeadersFAD.h"
29#include "HeadersBIAS.h"
30#include "HeadersFTM.h"
31#include "HeadersFSC.h"
32#include "HeadersMCP.h"
33#include "HeadersDrive.h"
34#include "HeadersFeedback.h"
35#include "HeadersRateScan.h"
36#include "HeadersRateControl.h"
37#include "HeadersMagicWeather.h"
38
39#include <boost/filesystem.hpp>
40
41using namespace std;
42
43// ------------------------------------------------------------------------
44
45#include "DimDescriptionService.h"
46#include "DimState.h"
47
48// ------------------------------------------------------------------------
49/*
50template<class T>
51 class buffer : public deque<T>
52 {
53 int32_t max_size;
54
55 public:
56 buffer(int32_t max=-1) : max_size(max) { }
57 const T &operator=(const T &t) const { push_back(t); if (max_size>0 && deque<T>::size()>max_size) deque<T>::pop_front(); }
58 operator T() const { return deque<T>::size()>0 ? deque<T>::back() : T(); }
59 bool valid() const { return deque<T>::size()>0; }
60 };
61*/
62
63// ------------------------------------------------------------------------
64
65namespace HTML
66{
67 const static string kWhite = "#ffffff";
68 const static string kYellow = "#fffff0";
69 const static string kRed = "#fff8f0";
70 const static string kGreen = "#f0fff0";
71 const static string kBlue = "#f0f0ff";
72};
73
74// ========================================================================
75// ========================================================================
76// ========================================================================
77
78class Sun
79{
80public:
81 Time time;
82
83 Time fRiseDayTime;
84 Time fRiseCivil;
85 Time fRiseAstronomical;
86 Time fRiseDarkTime;
87
88 Time fSetDayTime;
89 Time fSetCivil;
90 Time fSetAstronomical;
91 Time fSetDarkTime;
92
93 int state;
94 string description;
95 string color;
96
97 bool isday;
98 bool visible;
99
100public:
101 Sun() : time(Time::none)
102 {
103 }
104
105 // Could be done more efficient: Only recalcuate if
106 // the current time exceeds at least on of the stored times
107 Sun(double lon, double lat, const Time &t=Time()) : time(t)
108 {
109#ifdef HAVE_LIBNOVA
110 ln_lnlat_posn observer;
111 observer.lng = lon;
112 observer.lat = lat;
113
114 // get Julian day from local time
115 const double JD = time.JD();
116
117 ln_rst_time sun_day;
118 ln_rst_time sun_civil;
119 ln_rst_time sun_astronomical;
120 ln_rst_time sun_dark;
121
122 // Warning: return code of 1 means circumpolar and is not checked!
123 ln_get_solar_rst (JD-0.5, &observer, &sun_day);
124 ln_get_solar_rst_horizon(JD-0.5, &observer, - 6, &sun_civil);
125 ln_get_solar_rst_horizon(JD-0.5, &observer, -12, &sun_astronomical);
126 ln_get_solar_rst_horizon(JD-0.5, &observer, -18, &sun_dark);
127
128 fSetDayTime = Time(sun_day.set);
129 fSetCivil = Time(sun_civil.set);
130 fSetAstronomical = Time(sun_astronomical.set);
131 fSetDarkTime = Time(sun_dark.set);
132
133 fRiseDayTime = Time(sun_day.rise);
134 fRiseCivil = Time(sun_civil.rise);
135 fRiseAstronomical = Time(sun_astronomical.rise);
136 fRiseDarkTime = Time(sun_dark.rise);
137
138 const bool is_day = JD>sun_day.rise;
139 const bool is_night = JD>sun_dark.set;
140
141 ln_get_solar_rst (JD+0.5, &observer, &sun_day);
142 ln_get_solar_rst_horizon(JD+0.5, &observer, - 6, &sun_civil);
143 ln_get_solar_rst_horizon(JD+0.5, &observer, -12, &sun_astronomical);
144 ln_get_solar_rst_horizon(JD+0.5, &observer, -18, &sun_dark);
145
146 if (is_day)
147 {
148 fRiseDayTime = Time(sun_day.rise);
149 fRiseCivil = Time(sun_civil.rise);
150 fRiseAstronomical = Time(sun_astronomical.rise);
151 fRiseDarkTime = Time(sun_dark.rise);
152 }
153
154 if (is_night)
155 {
156 fSetDayTime = Time(sun_day.set);
157 fSetCivil = Time(sun_civil.set);
158 fSetAstronomical = Time(sun_astronomical.set);
159 fSetDarkTime = Time(sun_dark.set);
160 }
161
162 // case 0: midnight to sun-rise | !is_day && !is_night | rise/set
163 // case 1: sun-rise to sun-set | is_day && !is_night | set /rise
164 // case 2: sun-set to midnight | is_day && is_night | rise/set
165
166 isday = is_day^is_night;
167
168 state = isday ? 4 : 0;
169 if (time>fSetDayTime) state++;
170 if (time>fSetCivil) state++;
171 if (time>fSetAstronomical) state++;
172 if (time>fSetDarkTime) state++;
173
174 if (time>fRiseDarkTime) state++;
175 if (time>fRiseAstronomical) state++;
176 if (time>fRiseCivil) state++;
177 if (time>fRiseDayTime) state++;
178
179 string name[] =
180 {
181 "dark time",
182 "astron. twilight",
183 "civil twilight",
184 "sunrise",
185 "day time",
186 "sunset",
187 "civil twilight",
188 "astron. twilight",
189 "dark time"
190 };
191
192 description = state[name];
193
194 const string arr = isday ?
195 fSetDarkTime.MinutesTo(time)+"&darr;" :
196 fRiseDarkTime.MinutesTo(time)+"&uarr;";
197
198 description += " ["+arr+"]";
199
200 switch (state)
201 {
202 case 0: case 1: color = HTML::kGreen; break;
203 case 2: case 3: color = HTML::kYellow; break;
204 case 4: color = HTML::kRed; break;
205 case 5: case 6: color = HTML::kYellow; break;
206 case 7: case 8: color = HTML::kGreen; break;
207 }
208
209 visible = state>=3 && state<=5;
210#endif
211 }
212};
213
214class Moon
215{
216public:
217 Time time;
218
219 double ra;
220 double dec;
221
222 double zd;
223 double az;
224
225 double disk;
226
227 bool visible;
228
229 Time fRise;
230 Time fTransit;
231 Time fSet;
232
233 string description;
234 string color;
235
236 int state;
237
238 Moon() : time(Time::none)
239 {
240 }
241
242 // Could be done more efficient: Only recalcuate if
243 // the current time exceeds at least on of the stored times
244 Moon(double lon, double lat, const Time &t=Time()) : time(t)
245 {
246#ifdef HAVE_LIBNOVA
247 const double JD = time.JD();
248
249 ln_lnlat_posn observer;
250 observer.lng = lon;
251 observer.lat = lat;
252
253 //observer.lng.degrees = -5;
254 //observer.lng.minutes = 36;
255 //observer.lng.seconds = 30;
256 //observer.lat.degrees = 42;
257 //observer.lat.minutes = 35;
258 //observer.lat.seconds = 40;
259
260 ln_rst_time moon;
261 ln_get_lunar_rst(JD-0.5, &observer, &moon);
262
263 fRise = Time(moon.rise);
264 fTransit = Time(moon.transit);
265 fSet = Time(moon.set);
266
267 //visible =
268 // ((JD>moon.rise && JD<moon.set ) && moon.rise<moon.set) ||
269 // ((JD<moon.set || JD>moon.rise) && moon.rise>moon.set);
270
271 const bool is_up = JD>moon.rise;
272 const bool is_sinking = JD>moon.transit;
273 const bool is_dn = JD>moon.set;
274
275 ln_get_lunar_rst(JD+0.5, &observer, &moon);
276 if (is_up)
277 fRise = Time(moon.rise);
278 if (is_sinking)
279 fTransit = Time(moon.transit);
280 if (is_dn)
281 fSet = Time(moon.set);
282
283 ln_equ_posn pos;
284 ln_get_lunar_equ_coords(JD, &pos);
285
286 ln_hrz_posn hrz;
287 ln_get_hrz_from_equ (&pos, &observer, JD, &hrz);
288 az = hrz.az;
289 zd = 90-hrz.alt;
290
291 ra = pos.ra/15;
292 dec = pos.dec;
293
294 disk = ln_get_lunar_disk(JD)*100;
295 state = 0;
296 if (fRise <fTransit && fRise <fSet) state = 0; // not visible
297 if (fTransit<fSet && fTransit<fRise) state = 1; // before culm
298 if (fSet <fRise && fSet <fTransit) state = 2; // after culm
299
300 visible = state!=0;
301
302 // 0: not visible
303 // 1: visible before cul
304 // 2: visible after cul
305
306 if (!visible || disk<25)
307 color = HTML::kGreen;
308 else
309 color = disk>75 ? HTML::kRed : HTML::kYellow;
310
311 const string arr = fSet<fRise ?
312 fSet.MinutesTo(time) +"&darr;" :
313 fRise.MinutesTo(time)+"&uarr;";
314
315 ostringstream out;
316 out << setprecision(2);
317 out << (visible?"visible ":"") << (disk<0.1?0:disk) << "% [" << arr << "]";
318
319 description = out.str();
320#endif
321 }
322
323 double Angle(double r, double d) const
324 {
325 const double theta0 = M_PI/2-d*M_PI/180;
326 const double phi0 = r*M_PI/12;
327
328 const double theta1 = M_PI/2-dec*M_PI/180;
329 const double phi1 = ra*M_PI/12;
330
331 const double x0 = sin(theta0) * cos(phi0);
332 const double y0 = sin(theta0) * sin(phi0);
333 const double z0 = cos(theta0);
334
335 const double x1 = sin(theta1) * cos(phi1);
336 const double y1 = sin(theta1) * sin(phi1);
337 const double z1 = cos(theta1);
338
339 double arg = x0*x1 + y0*y1 + z0*z1;
340 if(arg > 1.0) arg = 1.0;
341 if(arg < -1.0) arg = -1.0;
342
343 return acos(arg) * 180/M_PI;
344 }
345
346 static string Color(double angle)
347 {
348 if (angle<10 || angle>150)
349 return HTML::kRed;
350 if (angle<20 || angle>140)
351 return HTML::kYellow;
352 return HTML::kGreen;
353 }
354};
355
356// ========================================================================
357// ========================================================================
358// ========================================================================
359
360class StateMachineSmartFACT : public StateMachineDim
361{
362public:
363 static bool fIsServer;
364
365private:
366 enum states_t
367 {
368 kStateDimNetworkNA = 1,
369 kStateRunning,
370 };
371
372 // ------------------------- Internal variables -----------------------
373
374 const Time fRunTime;
375
376 PixelMap fPixelMap;
377
378 string fDatabase;
379
380 Time fLastUpdate;
381 Time fLastAstroCalc;
382
383 string fPath;
384
385 // ----------------------------- Data storage -------------------------
386
387 deque<string> fControlMessageHist;
388 int32_t fControlScriptDepth;
389
390 uint32_t fMcpConfigurationState; // For consistency
391 int64_t fMcpConfigurationMaxTime;
392 int64_t fMcpConfigurationMaxEvents;
393 string fMcpConfigurationName;
394 Time fMcpConfigurationRunStart;
395 Time fMcpConfigurationLastTime;
396 deque<string> fMcpConfigurationHist;
397
398 bool fLastRunFinishedWithZeroEvents;
399
400 enum weather_t { kWeatherBegin=0, kTemp = kWeatherBegin, kDew, kHum, kPress, kWind, kGusts, kDir, kWeatherEnd = kDir+1 };
401 deque<float> fMagicWeatherHist[kWeatherEnd];
402
403 deque<float> fTngWeatherDustHist;
404 Time fTngWeatherDustTime;
405
406 vector<float> fFeedbackCalibration;
407
408 float fFeedbackTempOffset;
409 float fFeedbackUserOffset;
410
411 vector<float> fBiasControlVoltageVec;
412
413 float fBiasControlPowerTot;
414 float fBiasControlVoltageMed;
415 float fBiasControlCurrentMed;
416 float fBiasControlCurrentMax;
417
418 deque<float> fBiasControlCurrentHist;
419 deque<float> fFscControlTemperatureHist;
420
421 float fFscControlHumidityAvg;
422
423 float fDriveControlPointingZd;
424 string fDriveControlPointingAz;
425 string fDriveControlSourceName;
426 float fDriveControlMoonDist;
427
428 deque<float> fDriveControlTrackingDevHist;
429
430 int64_t fFadControlNumEvents;
431 int64_t fFadControlStartRun;
432 int32_t fFadControlDrsStep;
433 vector<uint32_t> fFadControlDrsRuns;
434
435 deque<float> fFtmControlTriggerRateHist;
436 int32_t fFtmControlTriggerRateTooLow;
437
438 float fFtmPatchThresholdMed;
439 float fFtmBoardThresholdMed;
440
441 bool fFtmControlFtuOk;
442
443 deque<float> fRateControlThreshold;
444
445 uint64_t fRateScanDataId;
446 uint8_t fRateScanBoard;
447 deque<float> fRateScanDataHist[41];
448
449 set<string> fErrorList;
450 deque<string> fErrorHist;
451
452 Sun fSun;
453 Moon fMoon;
454
455 // --------------------------- File header ----------------------------
456
457 Time fAudioTime;
458 string fAudioName;
459
460 string Header(const Time &d)
461 {
462 ostringstream msg;
463 msg << d.JavaDate() << '\t' << fAudioTime.JavaDate() << '\t' << fAudioName;
464 return msg.str();
465 }
466
467 string Header(const EventImp &d)
468 {
469 return Header(d.GetTime());
470 }
471
472 void SetAudio(const string &name)
473 {
474 fAudioName = name;
475 fAudioTime = Time();
476 }
477
478 // ------------- Initialize variables before the Dim stuff ------------
479
480 DimVersion fDimDNS;
481 DimControl fDimControl;
482 DimDescribedState fDimMcp;
483 DimDescribedState fDimDataLogger;
484 DimDescribedState fDimDriveControl;
485 DimDescribedState fDimTimeCheck;
486 DimDescribedState fDimMagicWeather;
487 DimDescribedState fDimTngWeather;
488 DimDescribedState fDimFeedback;
489 DimDescribedState fDimBiasControl;
490 DimDescribedState fDimFtmControl;
491 DimDescribedState fDimFadControl;
492 DimDescribedState fDimFscControl;
493 DimDescribedState fDimRateControl;
494 DimDescribedState fDimRateScan;
495 DimDescribedState fDimChat;
496 DimDescribedState fDimSkypeClient;
497
498 // -------------------------------------------------------------------
499
500 string GetDir(const double angle)
501 {
502 static const char *dir[] =
503 {
504 "N", "NNE", "NE", "ENE",
505 "E", "ESE", "SE", "SSE",
506 "S", "SSW", "SW", "WSW",
507 "W", "WNW", "NW", "NNW"
508 };
509
510 const uint16_t idx = uint16_t(floor(angle/22.5+16.5))%16;
511 return dir[idx];
512 }
513
514 // -------------------------------------------------------------------
515
516 bool CheckDataSize(const EventImp &d, const char *name, size_t size, bool min=false)
517 {
518 if (d.GetSize()==0)
519 return false;
520
521 if ((!min && d.GetSize()==size) || (min && d.GetSize()>size))
522 return true;
523
524 ostringstream msg;
525 msg << name << " - Received service has " << d.GetSize() << " bytes, but expected ";
526 if (min)
527 msg << "more than ";
528 msg << size << ".";
529 Warn(msg);
530 return false;
531 }
532
533 // -------------------------------------------------------------------
534
535 template<class T>
536 void WriteBinaryVec(const Time &tm, const string &fname, const vector<T> &vec, double scale, double offset=0, const string &title="")
537 {
538 if (vec.size()==0)
539 return;
540
541 ostringstream out;
542 out << tm.JavaDate() << '\n';
543 out << offset << '\n';
544 out << offset+scale << '\n';
545 out << setprecision(3);
546 if (!title.empty())
547 out << title << '\x7f';
548 else
549 {
550 const Statistics stat(vec[0]);
551 out << stat.min << '\n';
552 out << stat.med << '\n';
553 out << stat.max << '\x7f';
554 }
555 for (auto it=vec.begin(); it!=vec.end(); it++)
556 {
557 // The valid range is from 1 to 127
558 // \0 is used to seperate different curves
559 vector<uint8_t> val(it->size());
560 for (uint64_t i=0; i<it->size(); i++)
561 {
562 float range = nearbyint(126*(double(it->at(i))-offset)/scale); // [-2V; 2V]
563 if (range>126)
564 range=126;
565 if (range<0)
566 range=0;
567 val[i] = (uint8_t)range;
568 }
569
570 const char *ptr = reinterpret_cast<char*>(val.data());
571 out.write(ptr, val.size()*sizeof(uint8_t));
572 out << '\x7f';
573 }
574
575 ofstream(fPath+"/"+fname+".bin") << out.str();
576 }
577
578 template<class T>
579 void WriteBinaryVec(const EventImp &d, const string &fname, const vector<T> &vec, double scale, double offset=0, const string &title="")
580 {
581 WriteBinaryVec(d.GetTime(), fname, vec, scale, offset, title);
582 }
583
584 template<class T>
585 void WriteBinary(const Time &tm, const string &fname, const T &t, double scale, double offset=0)
586 {
587 WriteBinaryVec(tm, fname, vector<T>(&t, &t+1), scale, offset);
588 }
589
590 template<class T>
591 void WriteBinary(const EventImp &d, const string &fname, const T &t, double scale, double offset=0)
592 {
593 WriteBinaryVec(d.GetTime(), fname, vector<T>(&t, &t+1), scale, offset);
594 }
595
596 // -------------------------------------------------------------------
597
598 struct Statistics
599 {
600 float min;
601 float max;
602 float med;
603 float avg;
604 //float rms;
605
606 template<class T>
607 Statistics(const T &t, size_t offset_min=0, size_t offset_max=0)
608 : min(0), max(0), med(0), avg(0)
609 {
610 if (t.size()==0)
611 return;
612
613 T copy(t);
614 sort(copy.begin(), copy.end());
615
616 if (offset_min>t.size())
617 offset_min = 0;
618 if (offset_max>t.size())
619 offset_max = 0;
620
621 min = copy[offset_min];
622 max = copy[copy.size()-1-offset_max];
623 avg = accumulate (t.begin(), t.end(), 0.)/t.size();
624
625 const size_t p = t.size()/2;
626
627 med = copy[p];
628 }
629 };
630
631 void HandleControlMessageImp(const EventImp &d)
632 {
633 if (d.GetSize()==0)
634 return;
635
636 const string time = d.GetTimeAsStr("%H:%M:%S ");
637
638 string str = " ";
639 for (auto it=fControlMessageHist.rbegin(); it!=fControlMessageHist.rend(); it++)
640 {
641 str = it->substr(0, time.length());
642 if (str!="--:--:-- ")
643 break;
644 }
645
646 ostringstream tst;
647 tst << d.GetQoS();
648
649 string msg;
650 msg += str==time ? "--:--:-- " : time;
651 msg += d.Ptr<char>();
652
653 fControlMessageHist.push_back(msg);
654
655 ostringstream out;
656 out << setprecision(3);
657 out << Header(d) << '\n';
658 out << HTML::kWhite << '\t';
659
660 out << "<->";
661 for (auto it=fControlMessageHist.begin(); it!=fControlMessageHist.end(); it++)
662 out << *it << "<br/>";
663 out << "</->";
664
665 out << '\n';
666
667 ofstream(fPath+"/scriptlog.data") << out.str();
668 }
669
670 int HandleDimControlMessage(const EventImp &d)
671 {
672 if (d.GetSize()==0)
673 return GetCurrentState();
674
675 if (d.GetQoS()==90)
676 HandleControlMessageImp(d);
677
678 return GetCurrentState();
679 }
680
681 void HandleControlStateChange(const EventImp &d)
682 {
683 if (d.GetSize()==0)
684 return;
685
686 if (d.GetQoS()==-2 && fDimControl.scriptdepth==0)
687 fControlMessageHist.clear();
688
689 // Not that this will also "ding" just after program startup
690 // if the dimctrl is still in state -3
691 if (fDimControl.last.second!=DimState::kOffline &&
692 d.GetQoS()==-3 && fDimControl.scriptdepth==0)
693 SetAudio("ding");
694
695 if (d.GetQoS()>=0)
696 return;
697
698#if BOOST_VERSION < 104600
699 const string file = boost::filesystem::path(fDimControl.file).filename();
700#else
701 const string file = boost::filesystem::path(fDimControl.file).filename().string();
702#endif
703
704 HandleControlMessageImp(Event(d, fDimControl.shortmsg.data(), fDimControl.shortmsg.length()+1));
705 if (!file.empty())
706 HandleControlMessageImp(Event(d, file.data(), file.length()+1));
707 }
708
709 void HandleFscControlStateChange()
710 {
711 const int32_t &last = fDimFscControl.last.second;
712 const int32_t &state = fDimFscControl.state();
713
714 if (last==DimState::kOffline || state==DimState::kOffline)
715 return;
716
717 if (last<FSC::State::kConnected && state==FSC::State::kConnected)
718 SetAudio("startup");
719
720 if (last==FSC::State::kConnected && state<FSC::State::kConnected)
721 SetAudio("shutdown");
722 }
723
724 int HandleMcpConfiguration(const EventImp &d)
725 {
726 if (!CheckDataSize(d, "Mcp:Configuration", 16, true))
727 {
728 fMcpConfigurationState = DimState::kOffline;
729 fMcpConfigurationMaxTime = 0;
730 fMcpConfigurationMaxEvents = 0;
731 fMcpConfigurationName = "";
732 fMcpConfigurationRunStart = Time(Time::none);
733 return GetCurrentState();
734 }
735
736 if (d.GetTime()>fMcpConfigurationLastTime+boost::posix_time::hours(12))
737 fMcpConfigurationHist.clear();
738
739 // If a run ends...
740 if (fMcpConfigurationState==MCP::State::kTakingData && d.GetQoS()==MCP::State::kIdle)
741 {
742 // ...and no script is running just play a simple 'tick'
743 // ...and a script is running just play a simple 'tick'
744 if (/*fDimControl.state()<-2 &&*/ fDimControl.scriptdepth==0)
745 SetAudio("dong");
746 else
747 SetAudio("losticks");
748
749 ostringstream out;
750 out << d.GetTimeAsStr("%H:%M:%S") << " <#darkred>" << d.Ptr<char>(16);
751 if (!fDriveControlSourceName.empty())
752 out << " [" << fDriveControlSourceName << ']';
753 out << " (N=" << fFadControlNumEvents << ')';
754 out << "</#><br/>";
755 fMcpConfigurationHist.push_back(out.str());
756
757 fLastRunFinishedWithZeroEvents = fFadControlNumEvents==0;
758 }
759
760 if (d.GetQoS()==MCP::State::kTakingData)
761 {
762 fMcpConfigurationRunStart = Time();
763 SetAudio("losticks");
764
765 ostringstream out;
766 out << d.GetTimeAsStr("%H:%M:%S") << " <#darkgreen>" << fMcpConfigurationName;
767 if (!fDriveControlSourceName.empty())
768 out << " [" << fDriveControlSourceName << ']';
769 if (fFadControlStartRun>0)
770 out << " (Run " << fFadControlStartRun << ')';
771 out << "</#><br/>";
772 fMcpConfigurationHist.push_back(out.str());
773 }
774
775 fMcpConfigurationState = d.GetQoS();
776 fMcpConfigurationMaxTime = d.Get<uint64_t>();
777 fMcpConfigurationMaxEvents = d.Get<uint64_t>(8);
778 fMcpConfigurationName = d.Ptr<char>(16);
779 fMcpConfigurationLastTime = d.GetTime();
780
781 ostringstream out;
782 out << d.GetJavaDate() << '\n';
783 out << HTML::kWhite << '\t';
784 for (auto it=fMcpConfigurationHist.rbegin(); it!=fMcpConfigurationHist.rend(); it++)
785 out << *it;
786 out << '\n';
787
788 ofstream(fPath+"/observations.data") << out.str();
789
790 return GetCurrentState();
791 }
792
793 void WriteWeather(const EventImp &d, const string &name, int i, float min, float max)
794 {
795 const Statistics stat(fMagicWeatherHist[i]);
796
797 ostringstream out;
798 out << setprecision(3);
799 out << d.GetJavaDate() << '\n';
800
801 out << HTML::kWhite << '\t' << fMagicWeatherHist[i].back() << '\n';
802 out << HTML::kWhite << '\t' << stat.min << '\n';
803 out << HTML::kWhite << '\t' << stat.avg << '\n';
804 out << HTML::kWhite << '\t' << stat.max << '\n';
805
806 ofstream(fPath+"/"+name+".data") << out.str();
807
808 WriteBinary(d, "hist-magicweather-"+name, fMagicWeatherHist[i], max-min, min);
809 }
810
811 int HandleMagicWeatherData(const EventImp &d)
812 {
813 if (!CheckDataSize(d, "MagicWeather:Data", 7*4+2))
814 return GetCurrentState();
815
816 // Store a history of the last 300 entries
817 for (int i=kWeatherBegin; i<kWeatherEnd; i++)
818 {
819 fMagicWeatherHist[i].push_back(d.Ptr<float>(2)[i]);
820 if (fMagicWeatherHist[i].size()>300)
821 fMagicWeatherHist[i].pop_front();
822 }
823
824 ostringstream out;
825 out << d.GetJavaDate() << '\n';
826 if (fSun.time.IsValid() && fMoon.time.IsValid())
827 {
828 out << fSun.color << '\t' << fSun.description << '\n';
829 out << setprecision(2);
830 out << (fSun.isday?HTML::kWhite:fMoon.color) << '\t' << fMoon.description << '\n';
831 }
832 else
833 out << "\n\n";
834 out << setprecision(3);
835 for (int i=0; i<6; i++)
836 out << HTML::kWhite << '\t' << fMagicWeatherHist[i].back() << '\n';
837 out << HTML::kWhite << '\t' << GetDir(fMagicWeatherHist[kDir].back()) << '\n';
838 out << HTML::kWhite << '\t';
839 if (fTngWeatherDustHist.size()>0)
840 out << fTngWeatherDustHist.back() << '\t' << fTngWeatherDustTime.GetAsStr("%H:%M") << '\n';
841 else
842 out << "\t\n";
843
844 ofstream(fPath+"/weather.data") << out.str();
845
846 WriteWeather(d, "temp", kTemp, -5, 35);
847 WriteWeather(d, "dew", kDew, -5, 35);
848 WriteWeather(d, "hum", kHum, 0, 100);
849 WriteWeather(d, "wind", kWind, 0, 100);
850 WriteWeather(d, "gusts", kGusts, 0, 100);
851 WriteWeather(d, "press", kPress, 700, 1000);
852
853 return GetCurrentState();
854 }
855
856 int HandleTngWeatherDust(const EventImp &d)
857 {
858 if (!CheckDataSize(d, "TngWeather:Dust", 4))
859 return GetCurrentState();
860
861 fTngWeatherDustTime = d.GetTime();
862
863 fTngWeatherDustHist.push_back(d.GetFloat());
864 if (fTngWeatherDustHist.size()>300)
865 fTngWeatherDustHist.pop_front();
866
867 const Statistics stat(fTngWeatherDustHist);
868
869 const double scale = stat.max>0 ? pow(10, ceil(log10(stat.max))) : 0;
870
871 WriteBinary(d, "hist-tng-dust", fTngWeatherDustHist, scale);
872
873 ostringstream out;
874 out << d.GetJavaDate() << '\n';
875
876 ofstream(fPath+"/tngdust.data") << out.str();
877
878 return GetCurrentState();
879 }
880
881 int HandleDrivePointing(const EventImp &d)
882 {
883 if (!CheckDataSize(d, "DriveControl:Pointing", 16))
884 return GetCurrentState();
885
886 fDriveControlPointingZd = d.Get<double>();
887
888 const double az = d.Get<double>(8);
889
890 fDriveControlPointingAz = GetDir(az);
891
892 ostringstream out;
893 out << d.GetJavaDate() << '\n';
894
895 out << setprecision(0) << fixed;
896 out << HTML::kWhite << '\t' << az << '\t' << fDriveControlPointingAz << '\n';
897 out << HTML::kWhite << '\t' << fDriveControlPointingZd << '\n';
898
899 ofstream(fPath+"/pointing.data") << out.str();
900
901 return GetCurrentState();
902 }
903
904 int HandleDriveTracking(const EventImp &d)
905 {
906 if (!CheckDataSize(d, "DriveControl:Tracking", 56))
907 return GetCurrentState();
908
909 const double Ra = d.Get<double>(0*8);
910 const double Dec = d.Get<double>(1*8);
911 const double Zd = d.Get<double>(3*8);
912 const double Az = d.Get<double>(4*8);
913
914 const double zd = Zd * M_PI / 180;
915 const double dzd = d.Get<double>(5*8) * M_PI / 180;
916 const double daz = d.Get<double>(6*8) * M_PI / 180;
917
918 // Correct:
919 // const double d = cos(del) - sin(zd+dzd)*sin(zd)*(1.-cos(daz));
920
921 // Simplified:
922 double dev = cos(dzd) - sin(zd+dzd)*sin(zd)*(1.-cos(daz));
923 dev = acos(dev) * 180 / M_PI * 3600;
924
925 fDriveControlTrackingDevHist.push_back(dev);
926 if (fDriveControlTrackingDevHist.size()>300)
927 fDriveControlTrackingDevHist.pop_front();
928
929 WriteBinary(d, "hist-control-deviation", fDriveControlTrackingDevHist, 120);
930
931 ostringstream out;
932 out << d.GetJavaDate() << '\n';
933
934 out << HTML::kWhite << '\t' << fDriveControlSourceName << '\n';
935 out << setprecision(5);
936 out << HTML::kWhite << '\t' << Ra << '\n';
937 out << HTML::kWhite << '\t' << Dec << '\n';
938 out << setprecision(3);
939 out << HTML::kWhite << '\t' << Zd << '\n';
940 out << HTML::kWhite << '\t' << Az << '\n';
941 out << HTML::kWhite << '\t' << dev << '\n';
942
943 fDriveControlMoonDist = -1;
944
945 if (fMoon.visible)
946 {
947 const double angle = fMoon.Angle(Ra, Dec);
948 out << Moon::Color(angle) << '\t' << setprecision(3) << angle << '\n';
949
950 fDriveControlMoonDist = angle;
951 }
952 else
953 out << HTML::kWhite << "\t&mdash; \n";
954
955 ofstream(fPath+"/tracking.data") << out.str();
956
957 return GetCurrentState();
958 }
959
960 int HandleDriveSource(const EventImp &d)
961 {
962 if (!CheckDataSize(d, "DriveControl:Source", 7*4+2, true))
963 return GetCurrentState();
964
965 const double *ptr = d.Ptr<double>();
966
967 const double ra = ptr[0]; // Ra[h]
968 const double dec = ptr[1]; // Dec[deg]
969 const double woff = ptr[4]; // Wobble offset [deg]
970 const double wang = ptr[5]; // Wobble angle [deg]
971
972 fDriveControlSourceName = d.Ptr<char>(6*8);
973
974 ostringstream out;
975 out << d.GetJavaDate() << '\n';
976
977 out << HTML::kWhite << '\t' << fDriveControlSourceName << '\n';
978 out << setprecision(5);
979 out << HTML::kWhite << '\t' << ra << '\n';
980 out << HTML::kWhite << '\t' << dec << '\n';
981 out << setprecision(3);
982 out << HTML::kWhite << '\t' << woff << '\n';
983 out << HTML::kWhite << '\t' << wang << '\n';
984
985 ofstream(fPath+"/source.data") << out.str();
986
987 return GetCurrentState();
988 }
989
990 int HandleFeedbackCalibration(const EventImp &d)
991 {
992 if (!CheckDataSize(d, "Feedback:Calibration", 3*4*416))
993 {
994 fFeedbackCalibration.clear();
995 return GetCurrentState();
996 }
997
998 const float *ptr = d.Ptr<float>();
999 fFeedbackCalibration.assign(ptr+2*416, ptr+3*416);
1000
1001 return GetCurrentState();
1002 }
1003
1004 int HandleFeedbackDeviation(const EventImp &d)
1005 {
1006 if (!CheckDataSize(d, "Feedback:Deviation", (2*416+2)*4))
1007 return GetCurrentState();
1008
1009 const float *ptr = d.Ptr<float>();
1010 vector<float> dev(ptr+416, ptr+416+320);
1011
1012 fFeedbackTempOffset = ptr[2*416];
1013 fFeedbackUserOffset = ptr[2*416+1];
1014
1015 for (int i=0; i<320; i++)
1016 dev[i] -= fFeedbackTempOffset+fFeedbackUserOffset;
1017
1018 // Write the 160 patch values to a file
1019 WriteBinary(d, "cam-feedback-deviation", dev, 1);
1020
1021 const Statistics stat(dev, 3);
1022
1023 ostringstream out;
1024 out << d.GetJavaDate() << '\n';
1025 out << HTML::kWhite << '\t' << fFeedbackUserOffset << '\n';
1026 out << setprecision(3);
1027 out << HTML::kWhite << '\t' << fFeedbackTempOffset << '\n';
1028 out << HTML::kWhite << '\t' << stat.min << '\n';
1029 out << HTML::kWhite << '\t' << stat.med << '\n';
1030 out << HTML::kWhite << '\t' << stat.avg << '\n';
1031 out << HTML::kWhite << '\t' << stat.max << '\n';
1032 ofstream(fPath+"/feedback.data") << out.str();
1033
1034 return GetCurrentState();
1035 }
1036
1037 int HandleBiasVoltage(const EventImp &d)
1038 {
1039 if (!CheckDataSize(d, "BiasControl:Voltage", 1664))
1040 {
1041 fBiasControlVoltageVec.clear();
1042 return GetCurrentState();
1043 }
1044
1045 fBiasControlVoltageVec.assign(d.Ptr<float>(), d.Ptr<float>()+320);
1046
1047 const Statistics stat(fBiasControlVoltageVec);
1048
1049 fBiasControlVoltageMed = stat.med;
1050
1051 vector<float> val(320, 0);
1052 for (int i=0; i<320; i++)
1053 {
1054 const int idx = (fPixelMap.hv(i).hw()/9)*2+fPixelMap.hv(i).group();
1055 val[idx] = fBiasControlVoltageVec[i];
1056 }
1057
1058 if (fDimBiasControl.state()==BIAS::State::kVoltageOn)
1059 WriteBinary(d, "cam-biascontrol-voltage", val, 10, 65);
1060 else
1061 WriteBinary(d, "cam-biascontrol-voltage", val, 75);
1062
1063 ostringstream out;
1064 out << setprecision(3);
1065 out << d.GetJavaDate() << '\n';
1066 out << HTML::kWhite << '\t' << stat.min << '\n';
1067 out << HTML::kWhite << '\t' << stat.med << '\n';
1068 out << HTML::kWhite << '\t' << stat.avg << '\n';
1069 out << HTML::kWhite << '\t' << stat.max << '\n';
1070 ofstream(fPath+"/voltage.data") << out.str();
1071
1072 return GetCurrentState();
1073 }
1074
1075 int HandleBiasCurrent(const EventImp &d)
1076 {
1077 if (!CheckDataSize(d, "BiasControl:Current", 832))
1078 return GetCurrentState();
1079
1080 // Convert dac counts to uA
1081 vector<float> v(320);
1082 for (int i=0; i<320; i++)
1083 v[i] = d.Ptr<uint16_t>()[i] * 5000./4096;
1084
1085 const bool cal = fFeedbackCalibration.size()>0 && fBiasControlVoltageVec.size()>0;
1086
1087 double power_tot = 0;
1088 double power_apd = 0;
1089
1090 // 3900 Ohm/n + 1000 Ohm + 1100 Ohm (with n=4 or n=5)
1091 const double R[2] = { 3075, 2870 };
1092
1093 // Calibrate the data (subtract offset)
1094 if (cal)
1095 for (int i=0; i<320; i++)
1096 {
1097 // Measued current minus leakage current (bias crate calibration)
1098 v[i] -= fBiasControlVoltageVec[i]/fFeedbackCalibration[i]*1e6;
1099
1100 // Total power participated in the camera at the G-APD
1101 // and the serial resistors (total voltage minus voltage
1102 // drop at resistors in bias crate)
1103 power_tot += v[i]*(fBiasControlVoltageVec[i] - 1100e-6*v[i])*1e-6;
1104
1105 // Group index (0 or 1) of the of the pixel (4 or 5 pixel patch)
1106 const int g = fPixelMap.hv(i).group();
1107
1108 // Current per G-APD
1109 v[i] /= g ? 5 : 4;
1110
1111 // Power consumption per G-APD
1112 if (i!=66 && i!=191 && i!=193)
1113 power_apd += v[i]*(fBiasControlVoltageVec[i]-R[g]*v[i]*1e-6)*1e-6;
1114 }
1115
1116 // Divide by number of summed channels, convert to mW
1117 power_apd /= 317e-3; // [mW]
1118
1119 if (power_tot<1e-3)
1120 power_tot = 0;
1121 if (power_apd<1e-3)
1122 power_apd = 0;
1123
1124 fBiasControlPowerTot = power_tot;
1125
1126 // Get the maximum of each patch
1127 vector<float> val(320, 0);
1128 for (int i=0; i<320; i++)
1129 {
1130 const int idx = (fPixelMap.hv(i).hw()/9)*2+fPixelMap.hv(i).group();
1131 val[idx] = v[i];
1132 }
1133
1134 // Write the 160 patch values to a file
1135 WriteBinary(d, "cam-biascontrol-current", val, 100);
1136
1137 const Statistics stat(v, 0, 3);
1138
1139 // Exclude the three crazy channels
1140 fBiasControlCurrentMed = stat.med;
1141 fBiasControlCurrentMax = stat.max;
1142
1143 // Store a history of the last 60 entries
1144 fBiasControlCurrentHist.push_back(fBiasControlCurrentMed);
1145 if (fBiasControlCurrentHist.size()>360)
1146 fBiasControlCurrentHist.pop_front();
1147
1148 // write the history to a file
1149 WriteBinary(d, "hist-biascontrol-current", fBiasControlCurrentHist, 100);
1150
1151 const string col0 = cal ? HTML::kGreen : HTML::kWhite;
1152
1153 string col1 = col0;
1154 string col2 = col0;
1155 string col3 = col0;
1156 string col4 = col0;
1157
1158 if (cal && stat.min>65)
1159 col1 = kYellow;
1160 if (cal && stat.min>80)
1161 col1 = kRed;
1162
1163 if (cal && stat.med>65)
1164 col2 = kYellow;
1165 if (cal && stat.med>80)
1166 col2 = kRed;
1167
1168 if (cal && stat.avg>65)
1169 col3 = kYellow;
1170 if (cal && stat.avg>80)
1171 col3 = kRed;
1172
1173 if (cal && stat.max>65)
1174 col4 = kYellow;
1175 if (cal && stat.max>80)
1176 col4 = kRed;
1177
1178 ostringstream out;
1179 out << setprecision(2);
1180 out << d.GetJavaDate() << '\n';
1181 out << col0 << '\t' << (cal?"yes":"no") << '\n';
1182 out << col1 << '\t' << stat.min << '\n';
1183 out << col2 << '\t' << stat.med << '\n';
1184 out << col3 << '\t' << stat.avg << '\n';
1185 out << col4 << '\t' << stat.max << '\n';
1186 out << HTML::kWhite << '\t' << power_tot << "W [" << power_apd << "mW]\n";
1187 ofstream(fPath+"/current.data") << out.str();
1188
1189 return GetCurrentState();
1190 }
1191
1192 int HandleFadEvents(const EventImp &d)
1193 {
1194 if (!CheckDataSize(d, "FadControl:Events", 4*4))
1195 {
1196 fFadControlNumEvents = -1;
1197 return GetCurrentState();
1198 }
1199
1200 fFadControlNumEvents = d.Get<uint32_t>();
1201
1202 return GetCurrentState();
1203 }
1204
1205 int HandleFadStartRun(const EventImp &d)
1206 {
1207 if (!CheckDataSize(d, "FadControl:StartRun", 16))
1208 {
1209 fFadControlStartRun = -1;
1210 return GetCurrentState();
1211 }
1212
1213 fFadControlStartRun = d.Get<int64_t>();
1214
1215 return GetCurrentState();
1216 }
1217
1218 int HandleFadDrsRuns(const EventImp &d)
1219 {
1220 if (!CheckDataSize(d, "FadControl:DrsRuns", 4*4))
1221 {
1222 fFadControlDrsStep = -1;
1223 return GetCurrentState();
1224 }
1225
1226 const uint32_t *ptr = d.Ptr<uint32_t>();
1227 fFadControlDrsStep = ptr[0];
1228 fFadControlDrsRuns[0] = ptr[1];
1229 fFadControlDrsRuns[1] = ptr[2];
1230 fFadControlDrsRuns[2] = ptr[3];
1231
1232 return GetCurrentState();
1233 }
1234
1235 int HandleFadConnections(const EventImp &d)
1236 {
1237 if (!CheckDataSize(d, "FadControl:Connections", 41))
1238 {
1239 //fStatusEventBuilderLabel->setText("Offline");
1240 return GetCurrentState();
1241 }
1242
1243 string rc(40, '-'); // orange/red [45]
1244
1245 const uint8_t *ptr = d.Ptr<uint8_t>();
1246
1247 int c[4] = { '.', '.', '.', '.' };
1248
1249 for (int i=0; i<40; i++)
1250 {
1251 const uint8_t stat1 = ptr[i]&3;
1252 const uint8_t stat2 = ptr[i]>>3;
1253
1254 if (stat1==0 && stat2==0)
1255 rc[i] = '.'; // gray [46]
1256 else
1257 if (stat1>=2 && stat2==8)
1258 rc[i] = stat1==2?'+':'*'; // green [43] : check [42]
1259
1260 if (rc[i]<c[i/10])
1261 c[i/10] = rc[i];
1262 }
1263
1264 string col[4];
1265 for (int i=0; i<4; i++)
1266 switch (c[i])
1267 {
1268 case '.': col[i]=HTML::kWhite; break;
1269 case '-': col[i]=HTML::kRed; break;
1270 case '+': col[i]=HTML::kYellow; break;
1271 case '*': col[i]=HTML::kGreen; break;
1272 }
1273
1274 ostringstream out;
1275 out << setprecision(3);
1276 out << d.GetJavaDate() << '\n';
1277 out << col[0] << '\t' << rc.substr( 0, 10) << '\n';
1278 out << col[1] << '\t' << rc.substr(10, 10) << '\n';
1279 out << col[2] << '\t' << rc.substr(20, 10) << '\n';
1280 out << col[3] << '\t' << rc.substr(30, 10) << '\n';
1281 ofstream(fPath+"/fad.data") << out.str();
1282
1283 return GetCurrentState();
1284 }
1285
1286 int HandleFtmTriggerRates(const EventImp &d)
1287 {
1288 if (!CheckDataSize(d, "FtmControl:TriggerRates", 24+160+640+8))
1289 {
1290 fFtmControlTriggerRateTooLow = 0;
1291 return GetCurrentState();
1292 }
1293
1294 const float *crate = d.Ptr<float>(20); // Camera rate
1295
1296 // New run started
1297 if (*crate<0)
1298 {
1299 fFtmControlTriggerRateTooLow = -1;
1300 return GetCurrentState();
1301 }
1302
1303 // At the end of a run sometimes the trigger rate drops (the
1304 // service is trasmitted) before the run is 'officially' finished
1305 // by the MCP. Hence, we get a warning. So we have to require
1306 // two consecutive low rates.
1307 if (*crate<0.1)
1308 fFtmControlTriggerRateTooLow++;
1309 else
1310 fFtmControlTriggerRateTooLow=0;
1311
1312 const float *brates = crate + 1; // Board rate
1313 const float *prates = brates+40; // Patch rate
1314
1315 // Store a history of the last 60 entries
1316 fFtmControlTriggerRateHist.push_back(*crate);
1317 if (fFtmControlTriggerRateHist.size()>300)
1318 fFtmControlTriggerRateHist.pop_front();
1319
1320 // FIXME: Add statistics for all kind of rates
1321
1322 WriteBinary(d, "hist-ftmcontrol-triggerrate",
1323 fFtmControlTriggerRateHist, 100);
1324 WriteBinary(d, "cam-ftmcontrol-boardrates",
1325 vector<float>(brates, brates+40), 10);
1326 WriteBinary(d, "cam-ftmcontrol-patchrates",
1327 vector<float>(prates, prates+160), 10);
1328
1329 ostringstream out;
1330 out << setprecision(3);
1331 out << d.GetJavaDate() << '\n';
1332 out << HTML::kWhite << '\t' << *crate << '\n';
1333
1334 ofstream(fPath+"/trigger.data") << out.str();
1335
1336 const Statistics bstat(vector<float>(brates, brates+ 40));
1337 const Statistics pstat(vector<float>(prates, prates+160));
1338
1339 out.str("");
1340 out << d.GetJavaDate() << '\n';
1341 out << HTML::kWhite << '\t' << bstat.min << '\n';
1342 out << HTML::kWhite << '\t' << bstat.med << '\n';
1343 out << HTML::kWhite << '\t' << bstat.avg << '\n';
1344 out << HTML::kWhite << '\t' << bstat.max << '\n';
1345 ofstream(fPath+"/boardrates.data") << out.str();
1346
1347 out.str("");
1348 out << d.GetJavaDate() << '\n';
1349 out << HTML::kWhite << '\t' << pstat.min << '\n';
1350 out << HTML::kWhite << '\t' << pstat.med << '\n';
1351 out << HTML::kWhite << '\t' << pstat.avg << '\n';
1352 out << HTML::kWhite << '\t' << pstat.max << '\n';
1353 ofstream(fPath+"/patchrates.data") << out.str();
1354
1355 return GetCurrentState();
1356 }
1357
1358 int HandleFtmStaticData(const EventImp &d)
1359 {
1360 if (!CheckDataSize(d, "FtmControl:StaticData", sizeof(FTM::DimStaticData)))
1361 return GetCurrentState();
1362
1363 const FTM::DimStaticData &dat = d.Ref<FTM::DimStaticData>();
1364
1365 vector<uint16_t> vecp(dat.fThreshold, dat.fThreshold+160);
1366 vector<uint16_t> vecb(dat.fMultiplicity, dat.fMultiplicity+40);
1367
1368 WriteBinary(d, "cam-ftmcontrol-thresholds-patch", vecp, 1000);
1369 WriteBinary(d, "cam-ftmcontrol-thresholds-board", vecb, 100);
1370
1371 const Statistics statp(vecp);
1372 const Statistics statb(vecb);
1373
1374 fFtmPatchThresholdMed = statp.med;
1375 fFtmBoardThresholdMed = statb.med;
1376
1377 ostringstream out;
1378 out << d.GetJavaDate() << '\n';
1379 out << HTML::kWhite << '\t' << statb.min << '\n';
1380 out << HTML::kWhite << '\t' << statb.med << '\n';
1381 out << HTML::kWhite << '\t' << statb.max << '\n';
1382 ofstream(fPath+"/thresholds-board.data") << out.str();
1383
1384 out.str("");
1385 out << d.GetJavaDate() << '\n';
1386 out << HTML::kWhite << '\t' << statp.min << '\n';
1387 out << HTML::kWhite << '\t' << statp.med << '\n';
1388 out << HTML::kWhite << '\t' << statp.max << '\n';
1389 ofstream(fPath+"/thresholds-patch.data") << out.str();
1390
1391 out.str("");
1392 out << d.GetJavaDate() << '\n';
1393 out << HTML::kWhite << '\t' << statb.med << '\n';
1394 out << HTML::kWhite << '\t' << statp.med << '\n';
1395 ofstream(fPath+"/thresholds.data") << out.str();
1396
1397 out.str("");
1398 out << d.GetJavaDate() << '\n';
1399 out << HTML::kWhite << '\t' << dat.fTriggerInterval << '\n';
1400 out << HTML::kWhite << '\t';
1401 if (dat.HasPedestal())
1402 out << dat.fTriggerSeqPed;
1403 else
1404 out << "&ndash;";
1405 out << ':';
1406 if (dat.HasLPext())
1407 out << dat.fTriggerSeqLPext;
1408 else
1409 out << "&ndash;";
1410 out << ':';
1411 if (dat.HasLPint())
1412 out << dat.fTriggerSeqLPint;
1413 else
1414 out << "&ndash;";
1415 out << '\n';
1416
1417 out << HTML::kWhite << '\t' << (dat.HasTrigger()?"on":"off") << " / " << (dat.HasExt1()?"on":"off") << " / " << (dat.HasExt2()?"on":"off") << '\n';
1418 out << HTML::kWhite << '\t' << (dat.HasVeto()?"on":"off") << " / " << (dat.HasClockConditioner()?"time cal":"marker") << '\n';
1419 out << HTML::kWhite << '\t' << dat.fMultiplicityPhysics << " / " << dat.fMultiplicityCalib << '\n';
1420 out << HTML::kWhite << '\t' << dat.fWindowPhysics << '\t' << dat.fWindowCalib << '\n';
1421 out << HTML::kWhite << '\t' << dat.fDelayTrigger << '\t' << dat.fDelayTimeMarker << '\n';
1422 out << HTML::kWhite << '\t' << dat.fDeadTime << '\n';
1423
1424 int64_t vp = dat.fPrescaling[0];
1425 for (int i=1; i<40; i++)
1426 if (vp!=dat.fPrescaling[i])
1427 vp = -1;
1428
1429 if (vp<0)
1430 out << HTML::kYellow << "\tdifferent\n";
1431 else
1432 out << HTML::kWhite << '\t' << 0.5*vp << "\n";
1433
1434 ofstream(fPath+"/ftm.data") << out.str();
1435
1436 // Active FTUs: IsActive(i)
1437 // Enabled Pix: IsEnabled(i)
1438
1439 return GetCurrentState();
1440 }
1441
1442 int HandleFtmFtuList(const EventImp &d)
1443 {
1444 if (!CheckDataSize(d, "FtmControl:FtuList", sizeof(FTM::DimFtuList)))
1445 return GetCurrentState();
1446
1447 const FTM::DimFtuList &sdata = d.Ref<FTM::DimFtuList>();
1448
1449 ostringstream out;
1450 out << d.GetJavaDate() << '\n';
1451
1452 int cnt = 0;
1453 for (int i=0; i<4; i++)
1454 {
1455 out << HTML::kWhite << '\t';
1456 for (int j=0; j<10; j++)
1457 if (sdata.IsActive(i*10+j))
1458 {
1459 if (sdata.fPing[i*10+j]==1)
1460 {
1461 out << '*';
1462 cnt++;
1463 }
1464 else
1465 out << sdata.fPing[i*10+j];
1466 }
1467 else
1468 out << '-';
1469 out << '\n';
1470 }
1471
1472 fFtmControlFtuOk = cnt==40;
1473
1474 ofstream(fPath+"/ftu.data") << out.str();
1475
1476 return GetCurrentState();
1477 }
1478
1479 int HandleFadEventData(const EventImp &d)
1480 {
1481 if (!CheckDataSize(d, "FadControl:EventData", 23040))
1482 return GetCurrentState();
1483
1484 //const float *avg = d.Ptr<float>();
1485 //const float *rms = d.Ptr<float>(1440*sizeof(float));
1486 const float *dat = d.Ptr<float>(1440*sizeof(float)*2);
1487 //const float *pos = d.Ptr<float>(1440*sizeof(float)*3);
1488
1489 vector<float> max(320, -2);
1490 for (int i=0; i<1440; i++)
1491 {
1492 if (i%9==8)
1493 continue;
1494
1495 const int idx = (fPixelMap.hw(i).hw()/9)*2+fPixelMap.hw(i).group();
1496 const double v = dat[i]/1000;
1497 if (v>max[idx])
1498 max[idx]=v;
1499 }
1500
1501 switch (fFadControlDrsStep)
1502 {
1503 case 0: WriteBinary(d, "cam-fadcontrol-eventdata", max, 2, -1); break;
1504 case 1: WriteBinary(d, "cam-fadcontrol-eventdata", max, 2, 0); break;
1505 default: WriteBinary(d, "cam-fadcontrol-eventdata", max, 0.25, 0); break;
1506 }
1507
1508 return GetCurrentState();
1509 }
1510
1511 int HandleFscTemperature(const EventImp &d)
1512 {
1513 if (!CheckDataSize(d, "FscControl:Temperature", 240))
1514 return GetCurrentState();
1515
1516 const float *ptr = d.Ptr<float>(4);
1517
1518 double avg = 0;
1519 double rms = 0;
1520 double min = 99;
1521 double max = -99;
1522
1523 int num = 0;
1524 for (const float *t=ptr; t<ptr+31; t++)
1525 {
1526 if (*t==0)
1527 continue;
1528
1529 if (*t>max)
1530 max = *t;
1531
1532 if (*t<min)
1533 min = *t;
1534
1535 avg += *t;
1536 rms += *t * *t;
1537
1538 num++;
1539 }
1540
1541 avg /= num;
1542 rms = sqrt(rms/num-avg*avg);
1543
1544 if (fMagicWeatherHist[kTemp].size()>0)
1545 {
1546 fFscControlTemperatureHist.push_back(avg-fMagicWeatherHist[kTemp].back());
1547 if (fFscControlTemperatureHist.size()>300)
1548 fFscControlTemperatureHist.pop_front();
1549 }
1550
1551 const Statistics stat(fFscControlTemperatureHist);
1552
1553 ostringstream out;
1554 out << setprecision(3);
1555 out << d.GetJavaDate() << '\n';
1556 out << HTML::kWhite << '\t' << fFscControlHumidityAvg << '\n';
1557 out << HTML::kWhite << '\t' << min << '\n';
1558 out << HTML::kWhite << '\t' << avg << '\n';
1559 out << HTML::kWhite << '\t' << max << '\n';
1560 out << HTML::kWhite << '\t' << stat.min << '\n';
1561 out << HTML::kWhite << '\t' << stat.avg << '\n';
1562 out << HTML::kWhite << '\t' << stat.max << '\n';
1563
1564 ofstream(fPath+"/fsc.data") << out.str();
1565
1566 WriteBinary(d, "hist-fsccontrol-temperature",
1567 fFscControlTemperatureHist, 10);
1568
1569 return GetCurrentState();
1570 }
1571
1572 int HandleFscHumidity(const EventImp &d)
1573 {
1574 if (!CheckDataSize(d, "FscControl:Humidity", 5*4))
1575 return GetCurrentState();
1576
1577 const float *ptr = d.Ptr<float>(4);
1578
1579 double avg =0;
1580 int num = 0;
1581
1582 for (const float *t=ptr; t<ptr+4; t++)
1583 if (*t>0 && *t<=100)
1584 {
1585 avg += *t;
1586 num++;
1587 }
1588
1589 fFscControlHumidityAvg = num>0 ? avg/num : 0;
1590
1591 return GetCurrentState();
1592 }
1593
1594 int HandleRateScanData(const EventImp &d)
1595 {
1596 if (!CheckDataSize(d, "RateScan:Data", 824))
1597 return GetCurrentState();
1598
1599 const uint64_t id = d.Get<uint64_t>();
1600 const float *rate = d.Ptr<float>(20);
1601
1602 if (fRateScanDataId!=id)
1603 {
1604 for (int i=0; i<41; i++)
1605 fRateScanDataHist[i].clear();
1606 fRateScanDataId = id;
1607 }
1608 fRateScanDataHist[0].push_back(log10(rate[0]));
1609
1610 double max = 0;
1611 for (int i=1; i<41; i++)
1612 {
1613 fRateScanDataHist[i].push_back(log10(rate[i]));
1614 if (rate[i]>max)
1615 max = rate[i];
1616 }
1617
1618 // Cycle by time!
1619 fRateScanBoard ++;
1620 fRateScanBoard %= 40;
1621
1622 WriteBinary(d, "hist-ratescan", fRateScanDataHist[0], 10, -2);
1623 WriteBinary(d, "cam-ratescan-board", fRateScanDataHist[fRateScanBoard+1], 10, -4);
1624
1625 ostringstream out;
1626 out << setprecision(3);
1627 out << d.GetJavaDate() << '\n';
1628 out << HTML::kWhite << '\t' << fFtmBoardThresholdMed << '\n';
1629 out << HTML::kWhite << '\t' << fFtmPatchThresholdMed << '\n';
1630 out << HTML::kWhite << '\t' << floor(pow(10, fRateScanDataHist[0].back())+.5) << '\n';
1631 out << HTML::kWhite << '\t' << floor(max+.5) << '\n';
1632
1633 ofstream(fPath+"/ratescan.data") << out.str();
1634
1635 out.str("");
1636 out << d.GetJavaDate() << '\n';
1637 out << HTML::kWhite << '\t' << int(fRateScanBoard) << '\n';
1638 out << HTML::kWhite << '\t' << pow(10, fRateScanDataHist[fRateScanBoard+1].back()) << '\n';
1639
1640 ofstream(fPath+"/ratescan_board.data") << out.str();
1641
1642 return GetCurrentState();
1643 }
1644
1645 int HandleRateControlThreshold(const EventImp &d)
1646 {
1647 if (!CheckDataSize(d, "RateControl:Threshold", 2))
1648 return GetCurrentState();
1649
1650 const uint16_t th = d.Get<uint16_t>();
1651
1652 fRateControlThreshold.push_back(th);
1653 if (fRateControlThreshold.size()>300)
1654 fRateControlThreshold.pop_front();
1655
1656 WriteBinary(d, "hist-ratecontrol-threshold", fRateControlThreshold, 1000);
1657
1658 return GetCurrentState();
1659 }
1660
1661 // -------------------------------------------------------------------
1662
1663 void HandleDoTest(const EventImp &d)
1664 {
1665 ostringstream out;
1666 out << d.GetJavaDate() << '\n';
1667
1668 switch (d.GetQoS())
1669 {
1670 case -3: out << HTML::kWhite << "\tNot running\n"; break;
1671 case -2: out << HTML::kBlue << "\tLoading\n"; break;
1672 case -1: out << HTML::kBlue << "\tStarted\n"; break;
1673 default: out << HTML::kGreen << "\tRunning [" << d.GetQoS() << "]\n"; break;
1674 }
1675
1676 ofstream(fPath+"/dotest.data") << out.str();
1677 }
1678
1679 // -------------------------------------------------------------------
1680
1681 /*
1682 bool CheckEventSize(size_t has, const char *name, size_t size)
1683 {
1684 if (has==size)
1685 return true;
1686
1687 ostringstream msg;
1688 msg << name << " - Received event has " << has << " bytes, but expected " << size << ".";
1689 Fatal(msg);
1690 return false;
1691 }*/
1692
1693 int Print() const
1694 {
1695 Out() << fDimDNS << endl;
1696 Out() << fDimMcp << endl;
1697 Out() << fDimControl << endl;
1698 Out() << fDimDataLogger << endl;
1699 Out() << fDimDriveControl << endl;
1700 Out() << fDimTimeCheck << endl;
1701 Out() << fDimFadControl << endl;
1702 Out() << fDimFtmControl << endl;
1703 Out() << fDimBiasControl << endl;
1704 Out() << fDimFeedback << endl;
1705 Out() << fDimRateControl << endl;
1706 Out() << fDimFscControl << endl;
1707 Out() << fDimMagicWeather << endl;
1708 Out() << fDimTngWeather << endl;
1709 Out() << fDimRateScan << endl;
1710 Out() << fDimChat << endl;
1711 Out() << fDimSkypeClient << endl;
1712
1713 return GetCurrentState();
1714 }
1715
1716 string GetStateHtml(const DimState &state, int green) const
1717 {
1718 if (!state.online())
1719 return HTML::kWhite+"\t&mdash;\n";
1720
1721 if (&state==&fDimControl)
1722 return HTML::kGreen +'\t'+(state.state()<-2?"Idle":fDimControl.shortmsg)+'\n';
1723
1724 const State rc = state.description();
1725
1726 // Sate not found in list, server online (-3: offline; -2: not found)
1727 if (rc.index==-2)
1728 {
1729 ostringstream out;
1730 out << HTML::kWhite << '\t' << state.state() << '\n';
1731 return out.str();
1732 }
1733
1734 //ostringstream msg;
1735 //msg << HTML::kWhite << '\t' << rc.name << " [" << rc.index << "]\n";
1736 //return msg.str();
1737
1738 if (rc.index<0)
1739 return HTML::kWhite + "\t&mdash;\n";
1740
1741 string col = HTML::kGreen;
1742 if (rc.index<green)
1743 col = HTML::kYellow;
1744 if (rc.index>0xff)
1745 col = HTML::kRed;
1746
1747 return col + '\t' + rc.name + '\n';
1748 }
1749
1750 bool SetError(bool b, const string &err)
1751 {
1752 if (!b)
1753 {
1754 fErrorList.erase(err);
1755 return 0;
1756 }
1757
1758 const bool isnew = fErrorList.insert(err).second;
1759
1760 if (isnew)
1761 {
1762 ostringstream msg;
1763 msg << "<pre>" << Time().GetAsStr("%m-%d %H:%M") << "</pre> <->" << err << "</->";
1764 if (find(fErrorHist.begin(), fErrorHist.end(), msg.str())==fErrorHist.end())
1765 {
1766 fErrorHist.push_front(msg.str());
1767 if (fErrorHist.size()>80)
1768 fErrorHist.pop_back();
1769 }
1770 }
1771
1772 return isnew;
1773 }
1774
1775#ifdef HAVE_NOVA
1776 pair<vector<float>, pair<Time, float>> GetVisibility(ln_equ_posn *src, ln_lnlat_posn *observer, double jd)
1777 {
1778 jd = floor(jd);
1779
1780 const double jd0 = fmod(fSun.fSetAstronomical.JD(), 1);
1781 const double jd1 = fmod(fSun.fRiseAstronomical.JD(), 1);
1782
1783 ln_equ_posn moon;
1784 ln_equ_posn *pos = src ? src : &moon;
1785
1786 double max = 0;
1787 double maxjd = jd0;
1788
1789
1790 vector<float> alt;
1791 for (double h=0; h<1; h+=1./(24*12))
1792 {
1793 if (src==0)
1794 ln_get_lunar_equ_coords(jd+h, &moon);
1795
1796 ln_hrz_posn hrz;
1797 ln_get_hrz_from_equ(pos, observer, jd+h, &hrz);
1798
1799 if (h>jd0 && h<jd1 && hrz.alt>15)
1800 alt.push_back(hrz.alt);
1801
1802 if (hrz.alt>max)
1803 {
1804 max = hrz.alt;
1805 maxjd = jd+h;
1806 }
1807 }
1808
1809 if (max<15)
1810 return make_pair(vector<float>(), make_pair(Time(), 0));
1811
1812 return make_pair(alt, make_pair(maxjd, maxjd>jd0+jd&&maxjd<jd1+jd?max:0));
1813 }
1814#endif
1815
1816 void UpdateAstronomy()
1817 {
1818 const double lon = -(17.+53./60+26.525/3600);
1819 const double lat = 28.+45./60+42.462/3600;
1820
1821 Time now;
1822
1823 fSun = Sun (lon, lat, now);
1824 fMoon = Moon(lon, lat, now);
1825
1826 vector<string> color(8, HTML::kWhite);
1827 color[fSun.state%8] = HTML::kBlue;
1828
1829 ostringstream out;
1830 out << setprecision(3);
1831 out << now.JavaDate() << '\n';
1832 out << color[0] << '\t' << fSun.fRiseDarkTime.GetAsStr("%H:%M") << '\n';
1833 out << color[1] << '\t' << fSun.fRiseAstronomical.GetAsStr("%H:%M") << '\n';
1834 out << color[2] << '\t' << fSun.fRiseCivil.GetAsStr("%H:%M") << '\n';
1835 out << color[3] << '\t' << fSun.fRiseDayTime.GetAsStr("%H:%M") << '\n';
1836
1837 out << color[4] << '\t' << fSun.fSetDayTime.GetAsStr("%H:%M") << '\n';
1838 out << color[5] << '\t' << fSun.fSetCivil.GetAsStr("%H:%M") << '\n';
1839 out << color[6] << '\t' << fSun.fSetAstronomical.GetAsStr("%H:%M") << '\n';
1840 out << color[7] << '\t' << fSun.fSetDarkTime.GetAsStr("%H:%M") << '\n';
1841
1842 ofstream(fPath+"/sun.data") << out.str();
1843
1844 color.assign(3, HTML::kWhite);
1845 color[fMoon.state%3] = HTML::kBlue;
1846
1847 out.str("");
1848 out << now.JavaDate() << '\n';
1849
1850 out << color[0] << '\t' << fMoon.fRise.GetAsStr("%H:%M") << '\n';
1851 out << color[1] << '\t' << fMoon.fTransit.GetAsStr("%H:%M") << '\n';
1852 out << color[2] << '\t' << fMoon.fSet.GetAsStr("%H:%M") << '\n';
1853
1854 out << (fSun.isday?HTML::kWhite:fMoon.color) << '\t' << fMoon.description << '\n';
1855
1856 if (!fMoon.visible)
1857 out << HTML::kWhite << "\t&mdash;\t\n";
1858 else
1859 {
1860 string col = HTML::kWhite;
1861 if (!fSun.isday)
1862 {
1863 col = HTML::kGreen;
1864 if (fMoon.zd>25)
1865 col = HTML::kYellow;
1866 if (fMoon.zd>45 && fMoon.zd<80)
1867 col = HTML::kRed;
1868 if (fMoon.zd>=80)
1869 col = HTML::kRed;
1870 }
1871 out << col << '\t' << fMoon.zd << '\t' << GetDir(fMoon.az) << '\n';
1872 }
1873
1874 ostringstream out2, out3;
1875 out2 << setprecision(3);
1876 out2 << now.JavaDate() << '\n';
1877 out3 << now.JavaDate() << '\n';
1878
1879 map<Time, pair<string, float>> culmination;
1880 vector<vector<float>> alt;
1881
1882#ifdef HAVE_NOVA
1883 ln_lnlat_posn observer;
1884 observer.lng = lon;
1885 observer.lat = lat;
1886
1887 const pair<vector<float>, pair<Time, float>> vism = GetVisibility(0, &observer, now.JD());
1888 if (vism.first.size()>0)
1889 {
1890 alt.push_back(vism.first);
1891 culmination[vism.second.first] = make_pair("Moon", vism.second.second);
1892 }
1893#endif
1894
1895#ifdef HAVE_SQL
1896 try
1897 {
1898 const mysqlpp::StoreQueryResult res =
1899 Database(fDatabase).query("SELECT fSourceName, fRightAscension, fDeclination FROM source").store();
1900
1901 out << HTML::kWhite << '\t';
1902 out2 << HTML::kWhite << '\t';
1903 out3 << HTML::kWhite << '\t';
1904
1905 for (vector<mysqlpp::Row>::const_iterator v=res.begin(); v<res.end(); v++)
1906 {
1907 const string name = (*v)[0].c_str();
1908 const double ra = (*v)[1];
1909 const double dec = (*v)[2];
1910#ifdef HAVE_NOVA
1911 ln_equ_posn pos;
1912 pos.ra = ra*15;
1913 pos.dec = dec;
1914
1915 ln_hrz_posn hrz;
1916 ln_get_hrz_from_equ(&pos, &observer, now.JD(), &hrz);
1917
1918 const pair<vector<float>, pair<Time, float>> vis = GetVisibility(&pos, &observer, now.JD());
1919 if (vis.first.size()>0)
1920 {
1921 alt.push_back(vis.first);
1922 culmination[vis.second.first] = make_pair(name, vis.second.second);
1923 }
1924
1925 //out3 << vis.second.first << "/" << vis.second.second << " ";
1926
1927 string col = HTML::kWhite;
1928 if (hrz.alt>5)
1929 col = HTML::kRed;
1930 if (hrz.alt>25)
1931 col = HTML::kYellow;
1932 if (hrz.alt>60)
1933 col = HTML::kGreen;
1934
1935 out2 << "<tr bgcolor='" << col << "'>";
1936 out2 << "<td>" << name << "</td>";
1937 if (hrz.alt>5)
1938 {
1939 out2 << "<td>" << 90-hrz.alt << "&deg;</td>";
1940 out2 << "<td>" << GetDir(hrz.az) << "</td>";
1941 }
1942 else
1943 out2 << "<td/><td/>";
1944 out2 << "</tr>";
1945#endif
1946 const int32_t angle = fMoon.Angle(ra, dec);
1947
1948 out << "<tr bgcolor='" << Moon::Color(angle) << "'>";
1949 out << "<td>" << name << "</td>";
1950 out << "<td>" << round(angle) << "&deg;</td>";
1951 out << "</tr>";
1952 }
1953
1954 for (auto it=culmination.begin(); it!=culmination.end(); it++)
1955 {
1956 if (it!=culmination.begin())
1957 out3 << ", ";
1958 out3 << "<B>" << it->second.first << "</B>";
1959 if (it->second.second>0)
1960 out3 << " [" << nearbyint(90-it->second.second) << "&deg;]";
1961 }
1962
1963 ostringstream title;
1964 title << "Alt ";
1965 title << fSun.fSetAstronomical.GetAsStr("%H:%M");
1966 title << " / ";
1967 title << ((fSun.fRiseAstronomical-fSun.fSetAstronomical)/20).minutes();
1968 title << "' / ";
1969 title << fSun.fRiseAstronomical.GetAsStr("%H:%M");
1970
1971 out << '\n';
1972 out2 << '\n';
1973 out3 << '\n';
1974 out << HTML::kWhite << '\t' << Time()-now << '\n';
1975 out2 << HTML::kWhite << '\t' << Time()-now << '\n';
1976
1977 WriteBinaryVec(now, "hist-visibility", alt, 75, 15, title.str());
1978 }
1979 catch (const exception &e)
1980 {
1981 out << '\n';
1982 out2 << '\n';
1983 out << HTML::kWhite << '\t' << "ERROR - "+string(e.what()) << '\n';
1984 out2 << HTML::kWhite << '\t' << "ERROR - "+string(e.what()) << '\n';
1985 out3 << HTML::kWhite << '\t' << "ERROR - "+string(e.what()) << '\n';
1986 }
1987#endif
1988
1989 ofstream(fPath+"/moon.data") << out.str();
1990 ofstream(fPath+"/source-list.data") << out2.str();
1991 ofstream(fPath+"/visibility.data") << out3.str();
1992 }
1993
1994 int Execute()
1995 {
1996 // Dispatch (execute) at most one handler from the queue. In contrary
1997 // to run_one(), it doesn't wait until a handler is available
1998 // which can be dispatched, so poll_one() might return with 0
1999 // handlers dispatched. The handlers are always dispatched/executed
2000 // synchronously, i.e. within the call to poll_one()
2001 //poll_one();
2002
2003 Time now;
2004 if (now-fLastUpdate<boost::posix_time::seconds(1))
2005 return fDimDNS.online() ? kStateRunning : kStateDimNetworkNA;
2006 fLastUpdate=now;
2007
2008 // ==============================================================
2009
2010 const bool data_taking =
2011 fDimMcp.state()==MCP::State::kTriggerOn ||
2012 fDimMcp.state()==MCP::State::kTakingData;
2013
2014 const bool data_run =
2015 fMcpConfigurationName=="data" ||
2016 fMcpConfigurationName=="data-rt";
2017
2018 const bool bias_on =
2019 fDimBiasControl.state()==BIAS::State::kRamping ||
2020 fDimBiasControl.state()==BIAS::State::kOverCurrent ||
2021 fDimBiasControl.state()==BIAS::State::kVoltageOn;
2022
2023 const bool haderr = fErrorList.size()>0;
2024
2025 bool newerr = false;
2026
2027 newerr |= SetError(!fDimDNS.online(),
2028 "<b><#darkred>DIM network not available</#></b>");
2029 newerr |= SetError(!fDimControl.online(),
2030 "<b>dimctrl offline</b>");
2031
2032 //newerr |= SetError(fDimDriveControl.state()==Drive::State::kLocked,
2033 // "<b><#darkred>Drive in LOCKED state, drive was automatically parked</#></b>");
2034
2035 newerr |= SetError(fDimDriveControl.state()>0xff && data_taking && data_run,
2036 "Drive in ERROR state during data-taking");
2037 newerr |= SetError(fDriveControlMoonDist>155,
2038 "Moon within the field-of-view of the cones");
2039 newerr |= SetError(fDriveControlMoonDist>=0 && fDriveControlMoonDist<3,
2040 "Moon within the field-of-view of the camera");
2041
2042 newerr |= SetError(fDimBiasControl.state()<BIAS::State::kRamping && data_taking,
2043 "BIAS not operating during data-taking");
2044 newerr |= SetError(fDimBiasControl.state()==BIAS::State::kOverCurrent,
2045 "BIAS channels in OverCurrent");
2046 newerr |= SetError(fDimBiasControl.state()==BIAS::State::kNotReferenced,
2047 "BIAS voltage not at reference");
2048
2049
2050 newerr |= SetError(bias_on && fFeedbackCalibration.size()>0 && fBiasControlCurrentMed>80,
2051 "Median current exceeds 80&micro;A/pix exceeds 80&micro;A/pix");
2052 newerr |= SetError(bias_on && fFeedbackCalibration.size()>0 && fBiasControlCurrentMax>100,
2053 "Maximum current exceeds 100&micro;A/pix");
2054
2055 newerr |= SetError(fFscControlHumidityAvg>60,
2056 "Average camera humidity exceed 60%");
2057
2058 newerr |= SetError(fMagicWeatherHist[kHum].size()>0 && fMagicWeatherHist[kHum].back()>98 && data_taking,
2059 "Outside humidity exceeds 98% during data-taking");
2060 newerr |= SetError(fMagicWeatherHist[kGusts].size()>0 && fMagicWeatherHist[kGusts].back()>98 && fDimDriveControl.state()==Drive::State::kTracking,
2061 "Wind gusts exceed 50km/h during tracking");
2062
2063 newerr |= SetError(fFscControlTemperatureHist.size()>0 && fFscControlTemperatureHist.back()>8,
2064 "Sensor temperature exceeds outside temperature by more than 8&deg;C");
2065
2066 newerr |= SetError(fFtmControlTriggerRateTooLow>2 && fDimMcp.state()==MCP::State::kTakingData,
2067 "Trigger rate below 100mHz during data taking");
2068
2069 newerr |= SetError(fDimTimeCheck.state()==1,
2070 "Warning NTP time difference of drive PC exceeds 1s");
2071 newerr |= SetError(fDimTimeCheck.state()<1,
2072 "Warning timecheck not running");
2073
2074 newerr |= SetError(fDimFeedback.state()!=Feedback::State::kCalibrating &&
2075 fDimBiasControl.state()==BIAS::State::kVoltageOn &&
2076 fBiasControlVoltageMed>3 &&
2077 fFeedbackCalibration.size()==0,
2078 "Bias voltage switched on, but bias crate not calibrated");
2079
2080 newerr |= SetError(fLastRunFinishedWithZeroEvents,
2081 "Last run finshed, but contained zero events.");
2082
2083 fLastRunFinishedWithZeroEvents = false;
2084
2085 // FTM in Connected instead of Idle --> power cyclen
2086
2087 /* // Check offline and disconnected status?
2088 Out() << fDimMcp << endl;
2089 Out() << fDimControl << endl;
2090 Out() << fDimDataLogger << endl;
2091 Out() << fDimDriveControl << endl;
2092 Out() << fDimFadControl << endl;
2093 Out() << fDimFtmControl << endl;
2094 Out() << fDimBiasControl << endl;
2095 Out() << fDimFeedback << endl;
2096 Out() << fDimRateControl << endl;
2097 Out() << fDimFscControl << endl;
2098 Out() << fDimMagicWeather << endl;
2099 Out() << fDimRateScan << endl;
2100 Out() << fDimChat << endl;
2101 */
2102
2103 // FTU in error
2104 // FAD lost
2105
2106 // --------------------------------------------------------------
2107 ostringstream out;
2108
2109 if (newerr)
2110 {
2111 SetAudio("error");
2112
2113 out << now.JavaDate() << '\n';
2114 out << HTML::kWhite << '\t';
2115 for (auto it=fErrorHist.begin(); it!=fErrorHist.end(); it++)
2116 out << *it << "<br/>";
2117 out << '\n';
2118
2119 ofstream(fPath+"/errorhist.data") << out.str();
2120 }
2121
2122 out.str("");
2123 out << Header(now) << '\t' << (fErrorList.size()>0) << '\t' << (fDimControl.state()>-3) << '\n';
2124 out << setprecision(3);
2125 out << HTML::kWhite << '\t';
2126 for (auto it=fErrorList.begin(); it!=fErrorList.end(); it++)
2127 out << *it << "<br/>";
2128 out << '\n';
2129
2130 if (haderr || fErrorList.size()>0)
2131 ofstream(fPath+"/error.data") << out.str();
2132
2133 // ==============================================================
2134
2135 out.str("");
2136 out << Header(now) << '\t' << (fErrorList.size()>0) << '\t' << (fDimControl.state()>-3) << '\n';
2137 out << setprecision(3);
2138
2139 // -------------- System status --------------
2140 if (fDimDNS.online() && fDimMcp.state()>=MCP::State::kIdle) // Idle
2141 {
2142 string col = HTML::kBlue;
2143 switch (fMcpConfigurationState)
2144 {
2145 case MCP::State::kIdle:
2146 col = HTML::kWhite;
2147 break;
2148 case MCP::State::kConfiguring1:
2149 case MCP::State::kConfiguring2:
2150 case MCP::State::kConfiguring3:
2151 case MCP::State::kConfigured:
2152 case MCP::State::kTriggerOn:
2153 col = HTML::kBlue;
2154 break;
2155 case MCP::State::kTakingData:
2156 col = HTML::kBlue;
2157 if (fDimFadControl.state()==FAD::State::kWritingData)
2158 col = HTML::kGreen;
2159 break;
2160 }
2161
2162 const bool other =
2163 fDimRateControl.state()==RateControl::State::kSettingGlobalThreshold ||
2164 fDimRateScan.state()==RateScan::State::kInProgress;
2165
2166 if (other)
2167 col = HTML::kBlue;
2168
2169 out << col << '\t';
2170
2171 if (!other)
2172 {
2173 switch (fMcpConfigurationState)
2174 {
2175 case MCP::State::kIdle:
2176 out << "Idle [" << fMcpConfigurationName << "]";
2177 break;
2178 case MCP::State::kConfiguring1:
2179 case MCP::State::kConfiguring2:
2180 case MCP::State::kConfiguring3:
2181 out << "Configuring [" << fMcpConfigurationName << "]";
2182 break;
2183 case MCP::State::kConfigured:
2184 out << "Configured [" << fMcpConfigurationName << "]";
2185 break;
2186 case MCP::State::kTriggerOn:
2187 case MCP::State::kTakingData:
2188 out << fMcpConfigurationName;
2189 if (fFadControlDrsRuns[2]>0)
2190 out << "(" << fFadControlDrsRuns[2] << ")";
2191 break;
2192 }
2193 }
2194 else
2195 if (fDimRateControl.state()==RateControl::State::kSettingGlobalThreshold)
2196 out << "Calibrating threshold";
2197 else
2198 if (fDimRateScan.state()==RateScan::State::kInProgress)
2199 out << "Rate scan in progress";
2200
2201 if (fMcpConfigurationState>MCP::State::kConfigured &&
2202 fDimRateControl.state()!=RateControl::State::kSettingGlobalThreshold)
2203 {
2204 ostringstream evt;
2205 if (fMcpConfigurationMaxEvents>0)
2206 {
2207 const int64_t de = int64_t(fMcpConfigurationMaxEvents) - int64_t(fFadControlNumEvents);
2208 if (de>=0 && fMcpConfigurationState==MCP::State::kTakingData)
2209 evt << de;
2210 else
2211 evt << fMcpConfigurationMaxEvents;
2212 }
2213 else
2214 {
2215 if (fMcpConfigurationState==MCP::State::kTakingData)
2216 {
2217 if (fFadControlNumEvents>2999)
2218 evt << floor(fFadControlNumEvents/1000) << 'k';
2219 else
2220 evt << fFadControlNumEvents;
2221 }
2222 }
2223
2224 ostringstream tim;
2225 if (fMcpConfigurationMaxTime>0)
2226 {
2227 const uint32_t dt = (Time()-fMcpConfigurationRunStart).total_seconds();
2228 if (dt<=fMcpConfigurationMaxTime && fMcpConfigurationState==MCP::State::kTakingData)
2229 tim << fMcpConfigurationMaxTime-dt << 's';
2230 else
2231 tim << fMcpConfigurationMaxTime << 's';
2232 }
2233 else
2234 {
2235 if (fMcpConfigurationState==MCP::State::kTakingData)
2236 tim << fMcpConfigurationRunStart.SecondsTo();
2237 }
2238
2239 const bool has_evt = !evt.str().empty();
2240 const bool has_tim = !tim.str().empty();
2241
2242 if (has_evt || has_tim)
2243 out << " [";
2244 out << evt.str();
2245 if (has_evt && has_tim)
2246 out << '/';
2247 out << tim.str();
2248 if (has_evt || has_tim)
2249 out << ']';
2250 }
2251 }
2252 else
2253 out << HTML::kWhite;
2254 out << '\n';
2255
2256 // ------------------ Drive -----------------
2257 if (fDimDNS.online() && fDimDriveControl.state()>=Drive::State::kArmed) // Armed, Moving, Tracking
2258 {
2259 const uint32_t dev = fDriveControlTrackingDevHist.size()>0 ? round(fDriveControlTrackingDevHist.back()) : 0;
2260 const State rc = fDimDriveControl.description();
2261 string col = HTML::kGreen;
2262 if (fDimDriveControl.state()==Drive::State::kMoving) // Moving
2263 col = HTML::kBlue;
2264 if (fDimDriveControl.state()==Drive::State::kArmed) // Armed
2265 col = HTML::kWhite;
2266 if (fDimDriveControl.state()==Drive::State::kTracking) // Tracking
2267 {
2268 if (dev>60) // ~1.5mm
2269 col = HTML::kYellow;
2270 if (dev>100) // ~1/4 of a pixel ~ 2.5mm
2271 col = HTML::kRed;
2272 }
2273 if (fDimDriveControl.state()==0x100)
2274 col = HTML::kRed;
2275 out << col << '\t';
2276
2277 //out << rc.name << '\t';
2278 out << fDriveControlPointingAz << ' ';
2279 out << fDriveControlPointingZd << "&deg;";
2280 out << setprecision(2);
2281 if (fDimDriveControl.state()==Drive::State::kTracking)
2282 {
2283 out << " &plusmn; " << dev << '"';
2284 if (!fDriveControlSourceName.empty())
2285 out << " [" << fDriveControlSourceName << ']';
2286 }
2287 if (fDimDriveControl.state()==Drive::State::kMoving)
2288 out << " &#10227;";
2289 out << setprecision(3);
2290 }
2291 else
2292 out << HTML::kWhite << '\t';
2293
2294 if (fSun.time.IsValid() && fMoon.time.IsValid())
2295 {
2296 if (fSun.visible)
2297 {
2298 out << " &#9788;";
2299 if (fDimDriveControl.state()<Drive::State::kArmed)
2300 out << " [" << fSun.fSetCivil.MinutesTo() << "&darr;]";
2301 }
2302 else
2303 if (!fSun.visible && fMoon.visible)
2304 {
2305 out << " &#9790;";
2306 if (fDimDriveControl.state()<Drive::State::kArmed)
2307 out << " [" << fMoon.disk << "%]";
2308 }
2309 }
2310 if (fDimDNS.online() && fDimDriveControl.state()==0x100) // Armed, Moving, Tracking
2311 out << " [ERR]";
2312 out << '\n';
2313
2314 // ------------------- FSC ------------------
2315 if (fDimDNS.online() && fDimFscControl.state()>FSC::State::kDisconnected && fFscControlTemperatureHist.size()>0)
2316 {
2317 out << HTML::kGreen << '\t' << fFscControlTemperatureHist.back() << '\n';
2318 }
2319 else
2320 out << HTML::kWhite << '\n';
2321
2322 // --------------- MagicWeather -------------
2323 if (fDimDNS.online() && fDimMagicWeather.state()==MagicWeather::State::kReceiving && fMagicWeatherHist[kWeatherBegin].size()>0)
2324 {
2325 /*
2326 const float diff = fMagicWeatherHist[kTemp].back()-fMagicWeatherHist[kDew].back();
2327 string col1 = HTML::kRed;
2328 if (diff>0.3)
2329 col1 = HTML::kYellow;
2330 if (diff>0.7)
2331 col1 = HTML::kGreen;
2332 */
2333
2334 const float wind = fMagicWeatherHist[kGusts].back();
2335 const float hum = fMagicWeatherHist[kHum].back();
2336 string col = HTML::kGreen;
2337 if (wind>35 || hum>95)
2338 col = HTML::kYellow;
2339 if (wind>45 || hum>98)
2340 col = HTML::kRed;
2341
2342 out << col << '\t';
2343 out << fMagicWeatherHist[kHum].back() << '\t';
2344 out << setprecision(2);
2345 out << fMagicWeatherHist[kGusts].back() << '\n';
2346 out << setprecision(3);
2347 }
2348 else
2349 out << HTML::kWhite << "\n";
2350
2351 // --------------- FtmControl -------------
2352 if (fDimDNS.online() && fDimFtmControl.state()==FTM::State::kTriggerOn)
2353 {
2354 string col = HTML::kGreen;
2355 if (fFtmControlTriggerRateHist.size()>0)
2356 {
2357 if (fFtmControlTriggerRateHist.back()<15)
2358 col = HTML::kYellow;
2359 if (fFtmControlTriggerRateHist.back()>100)
2360 col = HTML::kRed;
2361
2362 out << col << '\t' << fFtmControlTriggerRateHist.back() << " Hz";
2363 }
2364
2365 if (fDimBiasControl.state()==BIAS::State::kVoltageOn)
2366 out << " (" << fFtmPatchThresholdMed << ')';
2367 out << '\n';
2368 }
2369 else
2370 out << HTML::kWhite << '\n';
2371
2372 // --------------- BiasControl -------------
2373 if (fDimDNS.online() &&
2374 (fDimBiasControl.state()==BIAS::State::kRamping ||
2375 fDimBiasControl.state()==BIAS::State::kOverCurrent ||
2376 fDimBiasControl.state()==BIAS::State::kVoltageOn ||
2377 fDimBiasControl.state()==BIAS::State::kVoltageOff))
2378 {
2379 const bool off = fDimBiasControl.state()==BIAS::State::kVoltageOff;
2380 const bool oc = fDimBiasControl.state()==BIAS::State::kOverCurrent;
2381
2382 string col = fBiasControlVoltageMed>3?HTML::kGreen:HTML::kWhite;
2383 if (fDimBiasControl.state()!=BIAS::State::kVoltageOff)
2384 {
2385 if (fBiasControlCurrentMed>60 || fBiasControlCurrentMax>80)
2386 col = HTML::kYellow;
2387 if (fBiasControlCurrentMed>70 || fBiasControlCurrentMax>90)
2388 col = HTML::kRed;
2389 }
2390
2391 // Bias in overcurrent => Red
2392 if (fDimBiasControl.state()==BIAS::State::kOverCurrent)
2393 col = HTML::kRed;
2394
2395 // MCP in ReadyForDatataking/Configuring/Configured/TriggerOn/TakingData
2396 // and Bias not in "data-taking state' => Red
2397 if (fMcpConfigurationState>MCP::State::kIdle &&
2398 fDimBiasControl.state()!=BIAS::State::kVoltageOn &&
2399 fDimBiasControl.state()!=BIAS::State::kVoltageOff)
2400 col = HTML::kRed;
2401
2402 const bool cal = fFeedbackCalibration.size();
2403
2404 // Feedback is currently calibrating => Blue
2405 if (fDimFeedback.state()==Feedback::State::kCalibrating)
2406 {
2407 out << HTML::kBlue << '\t';
2408 out << "***\t";
2409 out << "***\t";
2410 }
2411 else
2412 {
2413 out << setprecision(2);
2414 out << col << '\t';
2415 out << (off ? 0 : fBiasControlCurrentMed) << '\t';
2416 if (oc)
2417 out << "(OC) ";
2418 else
2419 {
2420 if (cal)
2421 out << (off ? 0 : fBiasControlCurrentMax);
2422 else
2423 out << "&mdash; ";
2424 }
2425 out << '\t';
2426 out << setprecision(3);
2427 }
2428 if (cal && fDimFeedback.state()!=Feedback::State::kCalibrating)
2429 out << setprecision(2) << fBiasControlPowerTot << " W" << setprecision(3);
2430 else
2431 out << (off ? 0 : fBiasControlVoltageMed) << " V";
2432 out << '\n';
2433 }
2434 else
2435 out << HTML::kWhite << '\n';
2436
2437 ofstream(fPath+"/fact.data") << out.str();
2438
2439 // ==============================================================
2440
2441 out.str("");
2442 out << Header(now) << '\t' << (fErrorList.size()>0) << '\t' << (fDimControl.state()>-3) << '\n';
2443
2444 if (!fDimDNS.online())
2445 out << HTML::kWhite << "\tOffline\n\n\n\n\n\n\n\n\n\n\n\n\n";
2446 else
2447 {
2448 ostringstream dt;
2449 dt << (Time()-fRunTime);
2450
2451 out << HTML::kGreen << '\t' << fDimDNS.version() << '\n';
2452
2453 out << GetStateHtml(fDimControl, 0);
2454 out << GetStateHtml(fDimMcp, 4);
2455 out << GetStateHtml(fDimDataLogger, 1);
2456 out << GetStateHtml(fDimDriveControl, 2);
2457 out << GetStateHtml(fDimTimeCheck, 1);
2458 out << GetStateHtml(fDimFadControl, FAD::State::kConnected);
2459 out << GetStateHtml(fDimFtmControl, FTM::State::kConnected);
2460 out << GetStateHtml(fDimBiasControl, BIAS::State::kConnected);
2461 out << GetStateHtml(fDimFeedback, 4);
2462 out << GetStateHtml(fDimRateControl, 4);
2463 out << GetStateHtml(fDimFscControl, 2);
2464 out << GetStateHtml(fDimMagicWeather, 2);
2465 out << GetStateHtml(fDimTngWeather, 2);
2466 out << GetStateHtml(fDimRateScan, 4);
2467 out << GetStateHtml(fDimChat, 0);
2468 out << GetStateHtml(fDimSkypeClient, 1);
2469
2470 out << HTML::kGreen << '\t' << dt.str().substr(0, dt.str().length()-7) << '\n';
2471 }
2472
2473 ofstream(fPath+"/status.data") << out.str();
2474
2475 if (now-fLastAstroCalc>boost::posix_time::seconds(15))
2476 {
2477 UpdateAstronomy();
2478 fLastAstroCalc = now;
2479 }
2480
2481 return fDimDNS.online() ? kStateRunning : kStateDimNetworkNA;
2482 }
2483
2484
2485public:
2486 StateMachineSmartFACT(ostream &out=cout) : StateMachineDim(out, fIsServer?"SMART_FACT":""),
2487 fLastAstroCalc(boost::date_time::neg_infin),
2488 fPath("www/smartfact/data"),
2489 fControlScriptDepth(0),
2490 fMcpConfigurationState(DimState::kOffline),
2491 fMcpConfigurationMaxTime(0),
2492 fMcpConfigurationMaxEvents(0),
2493 fLastRunFinishedWithZeroEvents(false),
2494 fTngWeatherDustTime(Time::none),
2495 fBiasControlVoltageMed(0),
2496 fBiasControlCurrentMed(0),
2497 fBiasControlCurrentMax(0),
2498 fFscControlHumidityAvg(0),
2499 fDriveControlMoonDist(-1),
2500 fFadControlNumEvents(0),
2501 fFadControlDrsRuns(3),
2502 fRateScanDataId(0),
2503 fRateScanBoard(0),
2504 // ---
2505 fDimMcp ("MCP"),
2506 fDimDataLogger ("DATA_LOGGER"),
2507 fDimDriveControl("DRIVE_CONTROL"),
2508 fDimTimeCheck ("TIME_CHECK"),
2509 fDimMagicWeather("MAGIC_WEATHER"),
2510 fDimTngWeather ("TNG_WEATHER"),
2511 fDimFeedback ("FEEDBACK"),
2512 fDimBiasControl ("BIAS_CONTROL"),
2513 fDimFtmControl ("FTM_CONTROL"),
2514 fDimFadControl ("FAD_CONTROL"),
2515 fDimFscControl ("FSC_CONTROL"),
2516 fDimRateControl ("RATE_CONTROL"),
2517 fDimRateScan ("RATE_SCAN"),
2518 fDimChat ("CHAT"),
2519 fDimSkypeClient ("SKYPE_CLIENT")
2520 {
2521 fDimDNS.Subscribe(*this);
2522 fDimControl.Subscribe(*this);
2523 fDimMcp.Subscribe(*this);
2524 fDimDataLogger.Subscribe(*this);
2525 fDimDriveControl.Subscribe(*this);
2526 fDimTimeCheck.Subscribe(*this);
2527 fDimMagicWeather.Subscribe(*this);
2528 fDimTngWeather.Subscribe(*this);
2529 fDimFeedback.Subscribe(*this);
2530 fDimBiasControl.Subscribe(*this);
2531 fDimFtmControl.Subscribe(*this);
2532 fDimFadControl.Subscribe(*this);
2533 fDimFscControl.Subscribe(*this);
2534 fDimRateControl.Subscribe(*this);
2535 fDimRateScan.Subscribe(*this);
2536 fDimChat.Subscribe(*this);
2537 fDimSkypeClient.Subscribe(*this);
2538
2539 fDimFscControl.SetCallback(bind(&StateMachineSmartFACT::HandleFscControlStateChange, this));
2540 fDimControl.SetCallback(bind(&StateMachineSmartFACT::HandleControlStateChange, this, placeholders::_1));
2541 fDimControl.AddCallback("dotest.dim", bind(&StateMachineSmartFACT::HandleDoTest, this, placeholders::_1));
2542
2543 Subscribe("DIM_CONTROL/MESSAGE")
2544 (bind(&StateMachineSmartFACT::HandleDimControlMessage, this, placeholders::_1));
2545
2546 Subscribe("MCP/CONFIGURATION")
2547 (bind(&StateMachineSmartFACT::HandleMcpConfiguration, this, placeholders::_1));
2548
2549 Subscribe("DRIVE_CONTROL/POINTING_POSITION")
2550 (bind(&StateMachineSmartFACT::HandleDrivePointing, this, placeholders::_1));
2551 Subscribe("DRIVE_CONTROL/TRACKING_POSITION")
2552 (bind(&StateMachineSmartFACT::HandleDriveTracking, this, placeholders::_1));
2553 Subscribe("DRIVE_CONTROL/SOURCE_POSITION")
2554 (bind(&StateMachineSmartFACT::HandleDriveSource, this, placeholders::_1));
2555
2556 Subscribe("FSC_CONTROL/TEMPERATURE")
2557 (bind(&StateMachineSmartFACT::HandleFscTemperature, this, placeholders::_1));
2558 Subscribe("FSC_CONTROL/HUMIDITY")
2559 (bind(&StateMachineSmartFACT::HandleFscHumidity, this, placeholders::_1));
2560
2561 Subscribe("MAGIC_WEATHER/DATA")
2562 (bind(&StateMachineSmartFACT::HandleMagicWeatherData, this, placeholders::_1));
2563 Subscribe("TNG_WEATHER/DUST")
2564 (bind(&StateMachineSmartFACT::HandleTngWeatherDust, this, placeholders::_1));
2565
2566 Subscribe("FEEDBACK/DEVIATION")
2567 (bind(&StateMachineSmartFACT::HandleFeedbackDeviation, this, placeholders::_1));
2568 Subscribe("FEEDBACK/CALIBRATION")
2569 (bind(&StateMachineSmartFACT::HandleFeedbackCalibration, this, placeholders::_1));
2570
2571 Subscribe("BIAS_CONTROL/VOLTAGE")
2572 (bind(&StateMachineSmartFACT::HandleBiasVoltage, this, placeholders::_1));
2573 Subscribe("BIAS_CONTROL/CURRENT")
2574 (bind(&StateMachineSmartFACT::HandleBiasCurrent, this, placeholders::_1));
2575
2576 Subscribe("FAD_CONTROL/CONNECTIONS")
2577 (bind(&StateMachineSmartFACT::HandleFadConnections, this, placeholders::_1));
2578 Subscribe("FAD_CONTROL/EVENTS")
2579 (bind(&StateMachineSmartFACT::HandleFadEvents, this, placeholders::_1));
2580 Subscribe("FAD_CONTROL/START_RUN")
2581 (bind(&StateMachineSmartFACT::HandleFadStartRun, this, placeholders::_1));
2582 Subscribe("FAD_CONTROL/DRS_RUNS")
2583 (bind(&StateMachineSmartFACT::HandleFadDrsRuns, this, placeholders::_1));
2584
2585 Subscribe("FTM_CONTROL/TRIGGER_RATES")
2586 (bind(&StateMachineSmartFACT::HandleFtmTriggerRates, this, placeholders::_1));
2587 Subscribe("FTM_CONTROL/STATIC_DATA")
2588 (bind(&StateMachineSmartFACT::HandleFtmStaticData, this, placeholders::_1));
2589 Subscribe("FTM_CONTROL/FTU_LIST")
2590 (bind(&StateMachineSmartFACT::HandleFtmFtuList, this, placeholders::_1));
2591
2592 Subscribe("RATE_CONTROL/THRESHOLD")
2593 (bind(&StateMachineSmartFACT::HandleRateControlThreshold,this, placeholders::_1));
2594
2595 Subscribe("RATE_SCAN/DATA")
2596 (bind(&StateMachineSmartFACT::HandleRateScanData, this, placeholders::_1));
2597
2598 Subscribe("FAD_CONTROL/EVENT_DATA")
2599 (bind(&StateMachineSmartFACT::HandleFadEventData, this, placeholders::_1));
2600
2601 // =================================================================
2602
2603 // State names
2604 AddStateName(kStateDimNetworkNA, "DimNetworkNotAvailable",
2605 "The Dim DNS is not reachable.");
2606
2607 AddStateName(kStateRunning, "Running", "");
2608
2609 // =================================================================
2610
2611 AddEvent("PRINT")
2612 (bind(&StateMachineSmartFACT::Print, this))
2613 ("Print a list of the states of all connected servers.");
2614
2615 }
2616 int EvalOptions(Configuration &conf)
2617 {
2618 if (!fPixelMap.Read(conf.Get<string>("pixel-map-file")))
2619 {
2620 Error("Reading mapping table from "+conf.Get<string>("pixel-map-file")+" failed.");
2621 return 1;
2622 }
2623
2624 fPath = conf.Get<string>("path");
2625 fDatabase = conf.Get<string>("source-database");
2626
2627 struct stat st;
2628 if (stat(fPath.c_str(), &st))
2629 {
2630 Error(fPath+" does not exist!");
2631 return 2;
2632 }
2633
2634 if ((st.st_mode&S_IFDIR)==0)
2635 {
2636 Error(fPath+" not a directory!");
2637 return 3;
2638 }
2639
2640 if ((st.st_mode&S_IWUSR)==0)
2641 {
2642 Error(fPath+" has no write permission!");
2643 return 4;
2644 }
2645
2646 if ((st.st_mode&S_IXUSR)==0)
2647 {
2648 Error(fPath+" has no execute permission!");
2649 return 5;
2650 }
2651
2652 ostringstream out;
2653 out << Time().JavaDate() << '\n';
2654
2655 ofstream(fPath+"/errorhist.data") << out.str();
2656 ofstream(fPath+"/error.data") << out.str();
2657
2658 return -1;
2659 }
2660};
2661
2662bool StateMachineSmartFACT::fIsServer = false;
2663
2664// ------------------------------------------------------------------------
2665
2666#include "Main.h"
2667
2668template<class T>
2669int RunShell(Configuration &conf)
2670{
2671 StateMachineSmartFACT::fIsServer = !conf.Get<bool>("client");
2672 return Main::execute<T, StateMachineSmartFACT>(conf);
2673}
2674
2675void SetupConfiguration(Configuration &conf)
2676{
2677 po::options_description control("Smart FACT");
2678 control.add_options()
2679 ("pixel-map-file", var<string>("FACTmapV5a.txt"), "Pixel mapping file. Used here to get the default reference voltage")
2680 ("path", var<string>("www/smartfact/data"), "Output path for the data-files")
2681 ("source-database", var<string>(), "Database link as in\n\tuser:password@server[:port]/database.")
2682 ("client", po_bool(false), "For a standalone client choose this option.")
2683 ;
2684
2685 conf.AddOptions(control);
2686}
2687
2688/*
2689 Extract usage clause(s) [if any] for SYNOPSIS.
2690 Translators: "Usage" and "or" here are patterns (regular expressions) which
2691 are used to match the usage synopsis in program output. An example from cp
2692 (GNU coreutils) which contains both strings:
2693 Usage: cp [OPTION]... [-T] SOURCE DEST
2694 or: cp [OPTION]... SOURCE... DIRECTORY
2695 or: cp [OPTION]... -t DIRECTORY SOURCE...
2696 */
2697void PrintUsage()
2698{
2699 cout <<
2700 "SmartFACT is a tool writing the files needed for the SmartFACT web interface.\n"
2701 "\n"
2702 "The default is that the program is started without user intercation. "
2703 "All actions are supposed to arrive as DimCommands. Using the -c "
2704 "option, a local shell can be initialized. With h or help a short "
2705 "help message about the usuage can be brought to the screen.\n"
2706 "\n"
2707 "Usage: smartfact [-c type] [OPTIONS]\n"
2708 " or: smartfact [OPTIONS]\n";
2709 cout << endl;
2710}
2711
2712void PrintHelp()
2713{
2714 Main::PrintHelp<StateMachineSmartFACT>();
2715
2716 /* Additional help text which is printed after the configuration
2717 options goes here */
2718
2719 /*
2720 cout << "bla bla bla" << endl << endl;
2721 cout << endl;
2722 cout << "Environment:" << endl;
2723 cout << "environment" << endl;
2724 cout << endl;
2725 cout << "Examples:" << endl;
2726 cout << "test exam" << endl;
2727 cout << endl;
2728 cout << "Files:" << endl;
2729 cout << "files" << endl;
2730 cout << endl;
2731 */
2732}
2733
2734int main(int argc, const char* argv[])
2735{
2736 Configuration conf(argv[0]);
2737 conf.SetPrintUsage(PrintUsage);
2738 Main::SetupConfiguration(conf);
2739 SetupConfiguration(conf);
2740
2741 if (!conf.DoParse(argc, argv, PrintHelp))
2742 return 127;
2743
2744 if (!conf.Has("console"))
2745 return RunShell<LocalStream>(conf);
2746
2747 if (conf.Get<int>("console")==0)
2748 return RunShell<LocalShell>(conf);
2749 else
2750 return RunShell<LocalConsole>(conf);
2751
2752 return 0;
2753}
Note: See TracBrowser for help on using the repository browser.