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

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