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

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