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

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