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

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